当前位置:文档之家› (完整word版)计算机图形学实验报告

(完整word版)计算机图形学实验报告

一、实验目的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 hereCRect 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)*Tvx0 = 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 hereAfxGetMainWnd()->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 hereAfxGetMainWnd()->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 hereAfxGetMainWnd()->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 hereAfxGetMainWnd()->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、迭代剖分法生成球面。

相关主题