《计算机图形学实验报告》
一、实验目的
1、掌握中点Bresenham直线扫描转换算法的思想。
2掌握边标志算法或有效边表算法进行多边形填充的基本设计思想。
3掌握透视投影变换的数学原理和三维坐标系中几何图形到二维图形的观察流程。
4掌握三维形体在计算机中的构造及表示方法
二、实验环境
Windows系统, VC6.0。
三、实验步骤
1、给定两个点的坐标P0(x0,y0),P1(x1,y1),使用中点Bresenham直线扫描转换算法画出连接两点的直线。
实验基本步骤
首先、使用MFC AppWizard(exe)向导生成一个单文档视图程序框架。
其次、使用中点Bresenham直线扫描转换算法实现自己的画线函数,函数原型可表示如下:
void DrawLine(CDC *pDC, int p0x, int p0y, int p1x, int p1y);
在函数中,可通过调用CDC成员函数SetPixel来画出扫描转换过程中的每个点。
COLORREF SetPixel(int x, int y, COLORREF crColor );
再次、找到文档视图程序框架视图类的OnDraw成员函数,调用DrawLine 函数画出不同斜率情况的直线,如下图:
最后、调试程序直至正确画出直线。
2、给定多边形的顶点的坐标P0(x0,y0),P1(x1,y1),P2(x2,y2),P3(x3,y3),P4(x4,y4)…使用边标志算法或有效边表算法进行多边形填充。
实验基本步骤
首先、使用MFC AppWizard(exe)向导生成一个单文档视图程序框架。
其次、实现边标志算法或有效边表算法函数,如下:
void FillPolygon(CDC *pDC, int px[], int py[], int ptnumb);
px:该数组用来表示每个顶点的x坐标
py :该数组用来表示每个顶点的y坐标
ptnumb:表示顶点个数
注意实现函数FillPolygon可以直接通过窗口的DC(设备描述符)来进行多边形填充,不需要使用帧缓冲存储。(边标志算法)首先用画线函数勾画出多边形,再针对每条扫描线,从左至右依次判断当前像素的颜色是否勾画的边界色,是就开始填充后面的像素直至再碰到边界像素。注意对顶点要做特殊处理。
通过调用GDI画点函数SetPixel来画出填充过程中的每个点。需要画线可以使用CDC的画线函数MoveTo和LineTo进行绘制,也可以使用实验一实现的画直线函数。
CPoint MoveTo(int x, int y );
BOOL LineTo(int x, int y );
实现边标志算法算法需要获取某个点的当前颜色值,可以使用CDC的成员函数
COLORREF GetPixel(int x, int y );
再次、找到文档视图程序框架视图类的OnDraw成员函数,调用FillPolygon 函数画出填充的多边形,如下:
void CTestView::OnDraw(CDC* pDC)
{
CTestcoodtransDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here
//绘制之前先把整个窗口涂上背景色(白色)以便于下面的填充
RECT Rt;
GetClientRect(&Rt);
pDC->FillSolidRect(&Rt, RGB(255,255,255));
int ptx[] = {10, 100, 200, 150, 80};
int pty[] = {10, 50, 80, 120, 70};
FillPolygon(pDC, ptx, pty, 5);
}
截图如下
3.在世界坐标系中定义一个立方体(由6个面组成),并给定观察点在世界坐标系中的位置(a,b,c)以及观察坐标系的方位角θ,俯仰角φ和姿态角α,另外再给定投影面离观察点的距离D,在屏幕上画出立方体的透视投影图形。
实验基本步骤
首先、使用MFC AppWizard(exe)向导生成一个单文档视图程序框架。
其次、由给定观察点在世界坐标系中的位置(a,b,c)以及观察坐标系的方位角θ,俯仰角φ和姿态角α求出观察变换矩阵Tv.
再次、将立方体的每一个面的顶点坐标与变换矩阵Tv相乘得到观察坐标系中的坐标,再由式(1)求得二维投影坐标。并用直线连接这些二维投影坐标点形成每一个面在投影面的图形,依次将立方体的6个面画出即可。
核心代码如下:
void CTestView::OnDraw(CDC* pDC)
{
CTestDoc* pDoc = GetDocument();
ASSERT_V ALID(pDoc);
// TODO: add draw code for native data here
CRect Rect;
GetClientRect(&Rect);
int MaxX=Rect.right;
int MaxY=Rect.bottom;
pDC->SetMapMode(MM_ANISOTROPIC);
pDC->SetWindowExt(1, 1);
pDC->SetViewportExt(1, -1);
pDC->SetViewportOrg(MaxX/2, MaxY/2);//设置视点原点在屏幕中心DrawObject(pDC);
}
void CTestView::ReadPoint()//读入8个顶点坐标
{
//每一行代表正方体每个顶点的x,y,z坐标
int a=200;//正方体边长
P[1][1]=-a/2;P[1][2]=-a/2;P[1][3]=-a/2;
P[2][1]=-a/2;P[2][2]=a/2;P[2][3]=-a/2;
P[3][1]=-a/2;P[3][2]=a/2;P[3][3]=a/2;
P[4][1]=-a/2;P[4][2]=-a/2;P[4][3]=a/2;
P[5][1]=a/2;P[5][2]=-a/2;P[5][3]=-a/2;
P[6][1]=a/2;P[6][2]=a/2;P[6][3]=-a/2;
P[7][1]=a/2;P[7][2]=a/2;P[7][3]=a/2;
P[8][1]=a/2;P[8][2]=-a/2;P[8][3]=a/2;
}
void CTestView::ReadFace()//读入6个面坐标
{
//第一列为每个面的边数;其余列为面的顶点编号
F[1][0]=4;F[1][1]=1;F[1][2]=2;F[1][3]=3;F[1][4]=4;
F[2][0]=4;F[2][1]=1;F[2][2]=4;F[2][3]=8;F[2][4]=5;
F[3][0]=4;F[3][1]=5;F[3][2]=6;F[3][3]=7;F[3][4]=8;
F[4][0]=4;F[4][1]=6;F[4][2]=2;F[4][3]=3;F[4][4]=7;
F[5][0]=4;F[5][1]=8;F[5][2]=7;F[5][3]=3;F[5][4]=4;
F[6][0]=4;F[6][1]=5;F[6][2]=6;F[6][3]=2;F[6][4]=1; }
void CTestView::DrawObject(CDC *pDC)//绘制立方体{
int TotalEdge,PointNumber;
int xt,yt,zt,x,y,z;//边的点坐标
CPen MyPen,* OldPen;
double x2d,y2d;//屏幕坐标系的二维坐标点
MyPen.CreatePen(PS_SOLID,3,RGB(0,0,0));
OldPen=pDC->SelectObject(&MyPen);
for(face=1;face<=6;face++)
{
TotalEdge=F[face][0];//面的总边数
for(int edge=1;edge<=TotalEdge;edge++)//边循环
{
PointNumber=F[face][edge];//面的顶点号
x=P[PointNumber][1];//每个顶点的x,y,z坐标
y=P[PointNumber][2];
z=P[PointNumber][3];
Project(x2d, y2d, x,y,z);
if(edge==1)//保存起点用于闭合
{
pDC->MoveTo(ROUND(x2d),ROUND(y2d));
xt=x;yt=y;zt=z;
}
else
{
pDC->LineTo(ROUND(x2d),ROUND(y2d));
}
}
Project(x2d, y2d, xt,yt,zt);
pDC->LineTo(ROUND(x2d),ROUND(y2d));//封闭边
}
pDC->SelectObject(OldPen);
MyPen.DeleteObject();
}
void CTestView::Project(double &x2d, double &y2d, int x,int y,int z)//透视变换{
double x0,y0,z0;
//用户坐标变换为观察坐标系三维坐标,即用户坐标系坐标乘观察坐标变换矩阵(x,y,z,1)*Tv
x0 = x*Proj[0][0]+y*Proj[1][0]+z*Proj[2][0]+Proj[3][0];
y0 = x*Proj[0][1]+y*Proj[1][1]+z*Proj[2][1]+Proj[3][1];
z0 = x*Proj[0][2]+y*Proj[1][2]+z*Proj[2][2]+Proj[3][2];
//观察坐标系三维坐标透视变换为屏幕坐标系二维坐标,即(xv,yv,zv,1)*Ts,再转化为非其次坐标
x2d=D*x0/z0;
y2d=D*y0/z0;
}
void CTestView::InitParameter()//初始化观察坐标变换矩阵
{
double cosTheta = cos(PI*Theta/180);
double sinTheta = sin(PI*Theta/180);
double cosPhi = cos(PI*Phi/180);
double sinPhi = sin(PI*Phi/180);
double cosAlpha = cos(PI*Alpha/180);
double sinAlpha = sin(PI*Alpha/180);
Proj[0][0] = cosTheta*cosAlpha+sinTheta*cosPhi*sinAlpha;
Proj[0][1] = cosTheta*sinAlpha - cosPhi*sinTheta*cosAlpha;
Proj[0][2] = -sinPhi*sinTheta;
Proj[0][3] = 0;
Proj[1][0] = -sinPhi*sinAlpha;
Proj[1][1] = sinPhi*cosAlpha;
Proj[1][2] = -cosPhi;
Proj[1][3] = 0;
Proj[2][0] = -sinTheta*cosAlpha+cosTheta*cosPhi*sinAlpha;
Proj[2][1] = -sinTheta*sinAlpha-cosPhi*cosTheta*cosAlpha;
Proj[2][2] = -sinPhi*cosTheta;
Proj[2][3] = 0;
Proj[3][0] =
-(a*cosTheta-c*sinTheta)*cosAlpha-(-b*sinPhi+(a*sinTheta+c*cosTheta)*cosPhi)*si nAlpha;
Proj[3][1] = -(a*cosTheta-c*sinTheta)*sinAlpha+(-b*sinPhi+(a*sinTheta+c*cosTheta)*cosPhi)*c osAlpha;
Proj[3][2] = b*cosPhi+(a*sinTheta+c*cosTheta)*sinPhi;
Proj[3][3] = 1;
}
void CTestView::OnCustom()
{
// TODO: Add your command handler code here
AfxGetMainWnd()->SetWindowText("透视变换-任意观察坐标系透视");
//任意设定观察点
a = 200;
b = 0;
c = 500;
//观察角度
Theta=20;
Phi=90;
Alpha = 10;
//视距
D = 800;
InitParameter();
ReadPoint();
ReadFace();
RedrawWindow();
}
void CTestView::OnMENUOne() //一点透视
{
// TODO: Add your command handler code here
AfxGetMainWnd()->SetWindowText("透视变换-一点透视");
Theta=0;
Phi=90;
Alpha = 0;
//采用球面坐标设定观察点
double R= 700.0;
a = R*sin(PI*Phi/180)*sin(PI*Theta/180);
b = R*cos(PI*Phi/180);
c = R*sin(PI*Phi/180)*cos(PI*Theta/180);
D = 1000;//视距
InitParameter();
ReadPoint();
ReadFace();
RedrawWindow();
}
void CTestView::OnMENUTwo()//二点透视
{
// TODO: Add your command handler code here
AfxGetMainWnd()->SetWindowText("透视变换-二点透视");
Theta=30;
Phi=90;
Alpha =0;
//采用球面坐标设定观察点
double R= 700.0;
a = R*sin(PI*Phi/180)*sin(PI*Theta/180);
b = R*cos(PI*Phi/180);
c = R*sin(PI*Phi/180)*cos(PI*Theta/180);
D = 1000;//视距
InitParameter();
ReadPoint();
ReadFace();
RedrawWindow();
}
void CTestView::OnMENUThree() //三点透视
{
// TODO: Add your command handler code here
AfxGetMainWnd()->SetWindowText("透视变换-三点透视");
Theta=45;
Phi=45;
Alpha=0;
//采用球面坐标设定观察点
double R= 700.0;
a = R*sin(PI*Phi/180)*sin(PI*Theta/180);
b = R*cos(PI*Phi/180);
c = R*sin(PI*Phi/180)*cos(PI*Theta/180);
D = 1000;//视距
InitParameter();
ReadPoint();
ReadFace();
RedrawWindow();
}
实验截图
4、迭代剖分法生成球面。
首先、使用MFC AppWizard(exe)向导生成一个单文档视图程序框架。
其次、初始化生成正八面体的顶点表,和面表。
再次、对面表里的每一个三角形进行剖分,一个三角形变成四个三角形。将产生的新的顶点加入到顶点表,同时将产生的新三角形加入到面表里,并从面表里删除原来的三角形。迭代多次后即得一个逼近于球面的多面体。
最后、对面表里的每一个三角形进行透视投影,在屏幕上画出透视投影图,调试程序直至正确。
实验核心代码如下:
void CTestView::GenerateSphereFace()//生成球面表
{
//首先生成一个正八面体
int a=200;
P[0][0]=0; P[0][1]=a; P[0][2]=0;
P[1][0]=0; P[1][1]=-a; P[1][2]=0;
P[2][0]=a; P[2][1]=0; P[2][2]=0;
P[3][0]=0; P[3][1]=0; P[3][2]=-a;
P[4][0]=-a; P[4][1]=0; P[4][2]=0;
P[5][0]=0; P[5][1]=0; P[5][2]=a;
int ptNum = 6;
faceNum = 8;
F[0][0]=3;F[0][1]=0;F[0][2]=4;F[0][3]=5;
F[1][0]=3;F[1][1]=0;F[1][2]=5;F[1][3]=2;
F[2][0]=3;F[2][1]=0;F[2][2]=2;F[2][3]=3;
F[3][0]=3;F[3][1]=0;F[3][2]=3;F[3][3]=4;
F[4][0]=3;F[4][1]=1;F[4][2]=5;F[4][3]=4;
F[5][0]=3;F[5][1]=1;F[5][2]=2;F[5][3]=5;
F[6][0]=3;F[6][1]=1;F[6][2]=3;F[6][3]=2;
F[7][0]=3;F[7][1]=1;F[7][2]=4;F[7][3]=3;
//分割迭代
for(int times = 0; times < 3; times++)
{
int i, iNum = faceNum;
for(i = 0; i < iNum; i++)
{//一个三角形分割为四个三角形
// * *
// => * *
// * * * * *
//先求中点坐标,并添加到点表
int pt1 = F[i][1];
int pt2 = F[i][2];
int pt3 = F[i][3];
int mid12 = ptNum++;
double mx = (P[pt1][0] + P[pt2][0])/2;
double my = (P[pt1][1] + P[pt2][1])/2;
double mz = (P[pt1][2] + P[pt2][2])/2;
P[mid12][0] = a/sqrt(mx*mx+my*my+mz*mz)*mx;//坐标规范化
P[mid12][1] = a/sqrt(mx*mx+my*my+mz*mz)*my;
P[mid12][2] = a/sqrt(mx*mx+my*my+mz*mz)*mz;
int mid23 = ptNum++;
mx = (P[pt3][0] + P[pt2][0])/2;
my = (P[pt3][1] + P[pt2][1])/2;
mz = (P[pt3][2] + P[pt2][2])/2;
P[mid23][0] = a/sqrt(mx*mx+my*my+mz*mz)*mx;
P[mid23][1] = a/sqrt(mx*mx+my*my+mz*mz)*my;
P[mid23][2] = a/sqrt(mx*mx+my*my+mz*mz)*mz;
int mid13 = ptNum++;
mx = (P[pt1][0] + P[pt3][0])/2;
my = (P[pt1][1] + P[pt3][1])/2;
mz = (P[pt1][2] + P[pt3][2])/2;
P[mid13][0] = a/sqrt(mx*mx+my*my+mz*mz)*mx;
P[mid13][1] = a/sqrt(mx*mx+my*my+mz*mz)*my;
P[mid13][2] = a/sqrt(mx*mx+my*my+mz*mz)*mz;
//被分割的三角形改为其中一个小的三角形,新建另外三个小的三角形
F[i][2] = mid12;
F[i][3] = mid13;
F[faceNum][0] = 3;
F[faceNum][1] = mid12;
F[faceNum][2] = pt2;
F[faceNum][3] = mid23;
faceNum++;
F[faceNum][0] = 3;
F[faceNum][1] = mid13;
F[faceNum][2] = mid23;
F[faceNum][3] = pt3;
faceNum++;
F[faceNum][0] = 3;
F[faceNum][1] = mid12;
F[faceNum][2] = mid23;
F[faceNum][3] = mid13;
faceNum++;
}
}
}
void CTestView::GenerateEllipsoidFace()//生成椭球面表
{
int a = 200, b = 100, c = 100;
P[0][0]=0; P[0][1]=b; P[0][2]=0;
P[1][0]=0; P[1][1]=-b; P[1][2]=0;
P[2][0]=a; P[2][1]=0; P[2][2]=0;
P[3][0]=0; P[3][1]=0; P[3][2]=-c;
P[4][0]=-a; P[4][1]=0; P[4][2]=0;
P[5][0]=0; P[5][1]=0; P[5][2]=c;
int ptNum = 6;
faceNum = 8;
F[0][0]=3;F[0][1]=0;F[0][2]=4;F[0][3]=5;
F[1][0]=3;F[1][1]=0;F[1][2]=5;F[1][3]=2;
F[2][0]=3;F[2][1]=0;F[2][2]=2;F[2][3]=3;
F[3][0]=3;F[3][1]=0;F[3][2]=3;F[3][3]=4;
F[4][0]=3;F[4][1]=1;F[4][2]=5;F[4][3]=4;
F[5][0]=3;F[5][1]=1;F[5][2]=2;F[5][3]=5;
F[6][0]=3;F[6][1]=1;F[6][2]=3;F[6][3]=2;
F[7][0]=3;F[7][1]=1;F[7][2]=4;F[7][3]=3;
//分割迭代
for(int times = 0; times < 3; times++)
{
int i, iNum = faceNum;
for(i = 0; i < iNum; i++)
{//一个三角形分割为四个三角形
// * *
// => * *
// * * * * *
//先求中点坐标,并添加到点表
int pt1 = F[i][1];
int pt2 = F[i][2];
int pt3 = F[i][3];
int mid12 = ptNum++;
double mx = (P[pt1][0] + P[pt2][0])/2;
double my = (P[pt1][1] + P[pt2][1])/2;
double mz = (P[pt1][2] + P[pt2][2])/2;
double scale = 1.0/sqrt(mx*mx/(a*a)+my*my/(b*b)+mz*mz/(c*c));
P[mid12][0] = scale*mx;//坐标规范化
P[mid12][1] = scale*my;
P[mid12][2] = scale*mz;
int mid23 = ptNum++;
mx = (P[pt3][0] + P[pt2][0])/2;
my = (P[pt3][1] + P[pt2][1])/2;
mz = (P[pt3][2] + P[pt2][2])/2;
scale = 1.0/sqrt(mx*mx/(a*a)+my*my/(b*b)+mz*mz/(c*c));
P[mid23][0] = scale*mx;
P[mid23][1] = scale*my;
P[mid23][2] = scale*mz;
int mid13 = ptNum++;
mx = (P[pt1][0] + P[pt3][0])/2;
my = (P[pt1][1] + P[pt3][1])/2;
mz = (P[pt1][2] + P[pt3][2])/2;
scale = 1.0/sqrt(mx*mx/(a*a)+my*my/(b*b)+mz*mz/(c*c));
P[mid13][0] = scale*mx;
P[mid13][1] = scale*my;
P[mid13][2] = scale*mz;
//被分割的三角形改为其中一个小的三角形,新建另外三个小的三角形
F[i][2] = mid12;
F[i][3] = mid13;
F[faceNum][0] = 3;
F[faceNum][1] = mid12;
F[faceNum][2] = pt2;
F[faceNum][3] = mid23;
faceNum++;
F[faceNum][0] = 3;
F[faceNum][1] = mid13;
F[faceNum][2] = mid23;
F[faceNum][3] = pt3;
faceNum++;
F[faceNum][0] = 3;
F[faceNum][1] = mid12;
F[faceNum][2] = mid23;
F[faceNum][3] = mid13;
faceNum++;
}
}
}
void CTestView::DrawObject(CDC *pDC)//绘制
{
int TotalEdge,pt;
int xt,yt,zt,x,y,z;//边的点坐标
double x2d,y2d;//屏幕坐标系的二维坐标点
for(int face=0;face { TotalEdge=F[face][0];//面的总边数 if(!IsFaceVisible(F[face]))//判定从视线方向看过去,该面是否可见 continue; for(int edge=1;edge<=TotalEdge;edge++)//边循环 { pt=F[face][edge];//面的顶点号 x=P[pt][0];//每个顶点的x,y,z坐标 y=P[pt][1]; z=P[pt][2]; Project(x2d, y2d, x,y,z); if(edge==1)//保存起点用于闭合 { pDC->MoveTo(ROUND(x2d),ROUND(y2d)); xt=x;yt=y;zt=z; } else { pDC->LineTo(ROUND(x2d),ROUND(y2d)); } } Project(x2d, y2d, xt,yt,zt); pDC->LineTo(ROUND(x2d),ROUND(y2d));//封闭边 } } void CTestView::Project(double &x2d, double &y2d, int x,int y,int z)//透视变换{ double x0,y0,z0; //用户坐标变换为观察坐标系三维坐标,即用户坐标系坐标乘观察坐标变换矩阵(x,y,z,1)*Tv x0 = x*Proj[0][0]+y*Proj[1][0]+z*Proj[2][0]+Proj[3][0]; y0 = x*Proj[0][1]+y*Proj[1][1]+z*Proj[2][1]+Proj[3][1]; z0 = x*Proj[0][2]+y*Proj[1][2]+z*Proj[2][2]+Proj[3][2]; //观察坐标系三维坐标透视变换为屏幕坐标系二维坐标,即(xv,yv,zv,1)*Ts,再转化为非其次坐标 x2d=D*x0/z0; y2d=D*y0/z0; } void CTestView::InitParameter()//初始化观察坐标变换矩阵 { double cosTheta = cos(PI*Theta/180); double sinTheta = sin(PI*Theta/180); double cosPhi = cos(PI*Phi/180); double sinPhi = sin(PI*Phi/180); double cosAlpha = cos(PI*Alpha/180); double sinAlpha = sin(PI*Alpha/180); Proj[0][0] = cosTheta*cosAlpha+sinTheta*cosPhi*sinAlpha; Proj[0][1] = cosTheta*sinAlpha - cosPhi*sinTheta*cosAlpha; Proj[0][2] = -sinPhi*sinTheta; Proj[0][3] = 0; Proj[1][0] = -sinPhi*sinAlpha; Proj[1][1] = sinPhi*cosAlpha; Proj[1][2] = -cosPhi; Proj[1][3] = 0; Proj[2][0] = -sinTheta*cosAlpha+cosTheta*cosPhi*sinAlpha; Proj[2][1] = -sinTheta*sinAlpha-cosPhi*cosTheta*cosAlpha; Proj[2][2] = -sinPhi*cosTheta; Proj[2][3] = 0; Proj[3][0] = -(a*cosTheta-c*sinTheta)*cosAlpha-(-b*sinPhi+(a*sinTheta+c*cosTheta)*cosPhi)*si nAlpha; Proj[3][1] = -(a*cosTheta-c*sinTheta)*sinAlpha+(-b*sinPhi+(a*sinTheta+c*cosTheta)*cosPhi)*c osAlpha; Proj[3][2] = b*cosPhi+(a*sinTheta+c*cosTheta)*sinPhi; Proj[3][3] = 1; } BOOL CTestView::IsFaceVisible(int Face[5]) { //求视矢量 int pt0 = Face[1]; int pt1 = Face[2]; int pt2 = Face[3]; //视点坐标减面的某个顶点的坐标(这里取第一个顶点),即得视矢量int Vx=a-P[pt0][0]; int Vy=b-P[pt0][1]; int Vz=c-P[pt0][2]; //求法矢量 //先求第一条边的分量 int Fx1=P[pt1][0]-P[pt0][0]; int Fy1=P[pt1][1]-P[pt0][1]; int Fz1=P[pt1][2]-P[pt0][2]; //先求第二条边的分量 int Fx2=P[pt2][0]-P[pt0][0]; int Fy2=P[pt2][1]-P[pt0][1]; int Fz2=P[pt2][2]-P[pt0][2]; //法矢量为第一和第二个矢量的叉积 int Nx=Fy1*Fz2-Fy2*Fz1; int Ny=Fz1*Fx2-Fz2*Fx1; int Nz=Fx1*Fy2-Fx2*Fy1; //法矢量与视矢量点积>0表示夹角小于90 return Vx*Nx+Vy*Ny+Vz*Nz > 0; } void CTestView::OnCustom() { // TODO: Add your command handler code here AfxGetMainWnd()->SetWindowText("球"); Theta=45; Phi=90; Alpha = 0; //采用球面坐标设定观察点 double R= 700.0; a = R*sin(PI*Phi/180)*sin(PI*Theta/180); b = R*cos(PI*Phi/180); c = R*sin(PI*Phi/180)*cos(PI*Theta/180); D = 800;//视距 InitParameter(); GenerateSphereFace(); RedrawWindow(); } void CTestView::OnMENUOne() { // TODO: Add your command handler code here AfxGetMainWnd()->SetWindowText("椭球"); Theta=0; Phi=90; Alpha = 0; //采用球面坐标设定观察点 double R= 700.0; a = R*sin(PI*Phi/180)*sin(PI*Theta/180); b = R*cos(PI*Phi/180); c = R*sin(PI*Phi/180)*cos(PI*Theta/180); D = 800;//视距 InitParameter(); GenerateEllipsoidFace(); RedrawWindow(); } 实验截图 实验总结: 这次试验在指导书的引导下,将每个环节逐步完成,最终顺利完成实验。通过该实验,总的来说,还有不少收获,比如进一步熟悉了Bresenham直线扫描转换算法的思想,同时,在实验中也培养了自己的耐心,总归,有不少收获。