计算机图形实验报告.docx
- 文档编号:6107522
- 上传时间:2023-01-03
- 格式:DOCX
- 页数:21
- 大小:102.08KB
计算机图形实验报告.docx
《计算机图形实验报告.docx》由会员分享,可在线阅读,更多相关《计算机图形实验报告.docx(21页珍藏版)》请在冰豆网上搜索。
计算机图形实验报告
一、实验目的
1、掌握中点Bresenham直线扫描转换算法的思想。
2掌握边标志算法或有效边表算法进行多边形填充的基本设计思想。
3掌握透视投影变换的数学原理和三维坐标系中几何图形到二维图形的观察流程。
4掌握三维形体在计算机中的构造及表示方法
二、实验环境
Windows系统,VC6.0。
3、实验步骤
1、给定两个点的坐标P0(x0,y0),P1(x1,y1),使用中点Bresenham直线扫描转换算法画出连接两点的直线。
实验基本步骤
首先、使用MFCAppWizard(exe)向导生成一个单文档视图程序框架。
其次、使用中点Bresenham直线扫描转换算法实现自己的画线函数,函数原型可表示如下:
voidDrawLine(CDC*pDC,intp0x,intp0y,intp1x,intp1y);
在函数中,可通过调用CDC成员函数SetPixel来画出扫描转换过程中的每个点。
COLORREFSetPixel(intx,inty,COLORREFcrColor);
再次、找到文档视图程序框架视图类的OnDraw成员函数,调用DrawLine函数画出不同斜率情况的直线,如下图:
最后、调试程序直至正确画出直线。
2、给定多边形的顶点的坐标P0(x0,y0),P1(x1,y1),P2(x2,y2),P3(x3,y3),P4(x4,y4)…使用边标志算法或有效边表算法进行多边形填充。
实验基本步骤
首先、使用MFCAppWizard(exe)向导生成一个单文档视图程序框架。
其次、实现边标志算法或有效边表算法函数,如下:
voidFillPolygon(CDC*pDC,intpx[],intpy[],intptnumb);
px:
该数组用来表示每个顶点的x坐标
py:
该数组用来表示每个顶点的y坐标
ptnumb:
表示顶点个数
注意实现函数FillPolygon可以直接通过窗口的DC(设备描述符)来进行多边形填充,不需要使用帧缓冲存储。
(边标志算法)首先用画线函数勾画出多边形,再针对每条扫描线,从左至右依次判断当前像素的颜色是否勾画的边界色,是就开始填充后面的像素直至再碰到边界像素。
注意对顶点要做特殊处理。
通过调用GDI画点函数SetPixel来画出填充过程中的每个点。
需要画线可以使用CDC的画线函数MoveTo和LineTo进行绘制,也可以使用实验一实现的画直线函数。
CPointMoveTo(intx,inty);
BOOLLineTo(intx,inty);
实现边标志算法算法需要获取某个点的当前颜色值,可以使用CDC的成员函数
COLORREFGetPixel(intx,inty);
再次、找到文档视图程序框架视图类的OnDraw成员函数,调用FillPolygon函数画出填充的多边形,如下:
voidCTestView:
:
OnDraw(CDC*pDC)
{
CTestcoodtransDoc*pDoc=GetDocument();
ASSERT_VALID(pDoc);
//TODO:
adddrawcodefornativedatahere
//绘制之前先把整个窗口涂上背景色(白色)以便于下面的填充
RECTRt;
GetClientRect(&Rt);
pDC->FillSolidRect(&Rt,RGB(255,255,255));
intptx[]={10,100,200,150,80};
intpty[]={10,50,80,120,70};
FillPolygon(pDC,ptx,pty,5);
}
截图如下
3.在世界坐标系中定义一个立方体(由6个面组成),并给定观察点在世界坐标系中的位置(a,b,c)以及观察坐标系的方位角θ,俯仰角φ和姿态角α,另外再给定投影面离观察点的距离D,在屏幕上画出立方体的透视投影图形。
实验基本步骤
首先、使用MFCAppWizard(exe)向导生成一个单文档视图程序框架。
其次、由给定观察点在世界坐标系中的位置(a,b,c)以及观察坐标系的方位角θ,俯仰角φ和姿态角α求出观察变换矩阵Tv.
再次、将立方体的每一个面的顶点坐标与变换矩阵Tv相乘得到观察坐标系中的坐标,再由式
(1)求得二维投影坐标。
并用直线连接这些二维投影坐标点形成每一个面在投影面的图形,依次将立方体的6个面画出即可。
核心代码如下:
voidCTestView:
:
OnDraw(CDC*pDC)
{
CTestDoc*pDoc=GetDocument();
ASSERT_VALID(pDoc);
//TODO:
adddrawcodefornativedatahere
CRectRect;
GetClientRect(&Rect);
intMaxX=Rect.right;
intMaxY=Rect.bottom;
pDC->SetMapMode(MM_ANISOTROPIC);
pDC->SetWindowExt(1,1);
pDC->SetViewportExt(1,-1);
pDC->SetViewportOrg(MaxX/2,MaxY/2);//设置视点原点在屏幕中心
DrawObject(pDC);
}
voidCTestView:
:
ReadPoint()//读入8个顶点坐标
{
//每一行代表正方体每个顶点的x,y,z坐标
inta=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;
}
voidCTestView:
:
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;
}
voidCTestView:
:
DrawObject(CDC*pDC)//绘制立方体
{
intTotalEdge,PointNumber;
intxt,yt,zt,x,y,z;//边的点坐标
CPenMyPen,*OldPen;
doublex2d,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(intedge=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();
}
voidCTestView:
:
Project(double&x2d,double&y2d,intx,inty,intz)//透视变换
{
doublex0,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;
}
voidCTestView:
:
InitParameter()//初始化观察坐标变换矩阵
{
doublecosTheta=cos(PI*Theta/180);
doublesinTheta=sin(PI*Theta/180);
doublecosPhi=cos(PI*Phi/180);
doublesinPhi=sin(PI*Phi/180);
doublecosAlpha=cos(PI*Alpha/180);
doublesinAlpha=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)*sinAlpha;
Proj[3][1]=-(a*cosTheta-c*sinTheta)*sinAlpha+(-b*sinPhi+(a*sinTheta+c*cosTheta)*cosPhi)*cosAlpha;
Proj[3][2]=b*cosPhi+(a*sinTheta+c*cosTheta)*sinPhi;
Proj[3][3]=1;
}
voidCTestView:
:
OnCustom()
{
//TODO:
Addyourcommandhandlercodehere
AfxGetMainWnd()->SetWindowText("透视变换-任意观察坐标系透视");
//任意设定观察点
a=200;
b=0;
c=500;
//观察角度
Theta=20;
Phi=90;
Alpha=10;
//视距
D=800;
InitParameter();
ReadPoint();
ReadFace();
RedrawWindow();
}
voidCTestView:
:
OnMENUOne()//一点透视
{
//TODO:
Addyourcommandhandlercodehere
AfxGetMainWnd()->SetWindowText("透视变换-一点透视");
Theta=0;
Phi=90;
Alpha=0;
//采用球面坐标设定观察点
doubleR=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();
}
voidCTestView:
:
OnMENUTwo()//二点透视
{
//TODO:
Addyourcommandhandlercodehere
AfxGetMainWnd()->SetWindowText("透视变换-二点透视");
Theta=30;
Phi=90;
Alpha=0;
//采用球面坐标设定观察点
doubleR=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();
}
voidCTestView:
:
OnMENUThree()//三点透视
{
//TODO:
Addyourcommandhandlercodehere
AfxGetMainWnd()->SetWindowText("透视变换-三点透视");
Theta=45;
Phi=45;
Alpha=0;
//采用球面坐标设定观察点
doubleR=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、迭代剖分法生成球面。
首先、使用MFCAppWizard(exe)向导生成一个单文档视图程序框架。
其次、初始化生成正八面体的顶点表,和面表。
再次、对面表里的每一个三角形进行剖分,一个三角形变成四个三角形。
将产生的新的顶点加入到顶点表,同时将产生的新三角形加入到面表里,并从面表里删除原来的三角形。
迭代多次后即得一个逼近于球面的多面体。
最后、对面表里的每一个三角形进行透视投影,在屏幕上画出透视投影图,调试程序直至正确。
实验核心代码如下:
voidCTestView:
:
GenerateSphereFace()//生成球面表
{
//首先生成一个正八面体
inta=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;
intptNum=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(inttimes=0;times<3;times++)
{
inti,iNum=faceNum;
for(i=0;i {//一个三角形分割为四个三角形 //** //=>** //***** //先求中点坐标,并添加到点表 intpt1=F[i][1]; intpt2=F[i][2]; intpt3=F[i][3]; intmid12=ptNum++; doublemx=(P[pt1][0]+P[pt2][0])/2; doublemy=(P[pt1][1]+P[pt2][1])/2; doublemz=(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; intmid23=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; intmid13=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++; } } } voidCTestView: : GenerateEllipsoidFace()//生成椭球面表 { inta=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; intptNum=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; //分割迭代
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 计算机 图形 实验 报告
![提示](https://static.bdocx.com/images/bang_tan.gif)