第一篇:计算机图形学课程设计 图形绘制变换分解
计算机图形学 实验报告
课程名称 : 计算机图形学 实验名称 : 图形绘制与变换 学 院 : 电子信息工程学院 专 业 : 计算机科学与技术 班 级 : 11计科本 01班 学 号 : 111102020103 姓 名 : 张慧 指导教师 : 王征风
二零一四年
目录
一、引言----------------3
二、设计需求---------3
2.1 设计目标--3 2.2 设计环境--3
2.2.1 VC++6.0------------------------3 2.2.2 MFC------------------------------4 2.3 设计题目及要求----------------------4 2.4 总体流程图----------------------------4
三、课程设计原理---5
3.1 实现的算法------------------------------5
3.1.2 Bresenham算法画直线------5 3.1.3 中心点算法画圆和椭圆------5 3.2 图形变换的基本原理------------------7
3.2.1平移变换------------------------7 3.2.2 旋转变换----------------------8 3.2.3 比例变换----------------------8
四、总体设计与功能实现-------------------------8
4.1 主要界面设计---------------------------8 4.2 设置颜色界面---------------------------8
4.2.1 界面设置代码------------------8 4.2.2 运行结果------------------------9 4.3 二维线画图元实现---------------------9 4.4 画多边形功能的实现--------------13 4.5 画Bezier曲线功能的实现-------14 4.6 二维图形变换的实现--------------16 4.7 三维图形的变换--------------------17
五、实验心得体会
一、引言
计算机图形学(Computer Graphics,简称CG)是一种使用数学算法将二维或三维图形转化为计算机显示器的栅格形式的科学。简单地说,计算机图形学的主要研究内容就是研究如何在计算机中表示图形、以及利用计算机进行图形的计算、处理和显示的相关原理与算法。是计算机科学的一个分支领域,主要关注数字合成与操作视觉的图形内容。计算机图形学研究的是应用计算机产生图像的所有工作,不管图像是静态的还是动态的,可交互的还是固定的,等等。图形API是允许程序员开发包含交互式计算机图形操作的应用而不需要关注图形操作细节或任务系统细节的工具集。计算机图形学有着广泛的应用领域,包括物理、航天、电影、电视、游戏、艺术、广告、通信、天气预报等几乎所有领域都用到了计算机图形学的知识,这些领域通过计算机图形学将几何模型生成图像,将问题可视化从而为各领域更好的服务。
计算机图形学利用计算机产生让人赏心悦目的视觉效果,必须建立描述图形的几何模型还有光照模型,再加上视角、颜色、纹理等属性,再经过模型变换、视图变换、投影操作等,这些步骤从而实现一个完整的OpenGL程序效果。OpenGL是一个开放的三维图形软件包,它独立于窗口系统和操作系统,以它为基础开发的应用程序可以十分方便地在各种平台间移植。计算机图形学通过应用OpenGL的功能,使得生成的图形效果具有高度真实感。学习计算机图形学的重点是掌握OpenGL在图形学程序中的使用方法。事实上,图形学也把可以表示几何场景的曲线曲面造型技术和实体造型技术作为其主要的研究内容。同时,真实感图形计算的结果是以数字图像的方式提供的,计算机图形学也就和图像处理有着密切的关系。
通过21世纪是信息的时代,在日新月异的科技更新中相信计算机会发挥越来越重要的作用,计算机图形学也会在更多的领域所应用,虽然我国在这方面还比较薄弱,但相信会有越来越好的时候的。
二、设计需求
2.1 设计目标
以图形学算法为目标,深入研究。继而策划、设计并实现一个能够表现计算机图形学算法原理的或完整过程的演示系统,并能从某些方面作出评价和改进意见。通过完成一个完整程序,经历策划、设计、开发、测试、总结和验收各阶段,达到:巩固和实践计算机图形学课程中的理论和算法;学习表现计算机图形学算法的技巧;培养认真学习、积极探索的精神。
2.2 设计环境
2.2.1 VC++6.0 VC++6.0是 Microsoft 公司推出的一个基于 Windows 系统平台、可视化的 集成开发环境,它的源程序按 C++语言的要求编写,并加入了微软提供的功能 强大的 MFC(Microsoft Foundation Class)类库。MFC 中封装了大部分 Windows API 函数和 Windows 控件,它包含的功能涉及到整个 Windows 操作系统。MFC 不仅给用户提供了 Windows 图形环境下应用程序的框架,而且还提供了创建应 用程序的组件,这样,开发人员不必从头设计创建和管理一个标准 Windows 应 用程序所需的程序,而是从一个比较高的起点编程,故节省了大量的时间。另 外,它提供了大量的代码,指导用户编程时实现某些技术和功能。因此,使用VC++提供的 高度可视化的应用程序开发工具和 MFC 类库,可使应用程序开发变 得简单。2.2.2 MFC MFC(Microsoft Foundation Classes),是 一 个 微 软 公 司 提 供 的 类 库(class libraries)以 C++类的形式封装了 Windows 的 API,它包含了窗口等许多类的定义。各种类的集合构成了一个应运程序的框架结构,以减少应用程序开发人员的工作 量。其中包含的类包含大量 Windows 句柄封装类和很多 Windows 的内建控件和组 件的封装类。MFC 6.0 版本封装了大约 200 个类,其中的一些可以被用户直接使用。例如CWnd 类封装了窗口的功能,包括打印文本、绘制图形及跟踪鼠标指针的移动等;CsplitterWnd 类是从 CWnd 类派生出来的,继承了基类或称父类 CWnd 类的所 有特 性,但增加了自己的功能,实现拆分窗口,使窗口至少可被拆分成两个窗口,用户 可以移动两个窗口之间的边框来改变窗口的大小;CtoolBar 类可以定义工具栏等。MFC 命名的惯例是类的名字通常是由“C”打头;成员变量使用前缀“m_”,接着使用一个字母来指明数据类型,然后是变量的名称;所有的单词用大写字母开头。
2.3 设计题目及要求
(1)题目:实现多边形和曲线的绘制和变换
(2)要求:学会使用VC++编写实现图形的绘制变换,需包括直线、曲线、多边形的绘制和变换,及三维立体图形的相应变换.2.4 总体流程图
三、课程设计原理
3.1 实现的算法
3.1.1 DDA算法画直线
DDA是数字微分分析式(Digital Differential Analyzer)的缩写。
已知直线两端点(x1,y1)、(x2,y2)则斜率m为:m =(y2-y1)/(x2-x1)= Dx/Dy;直线中的每一点坐标都可以由前一点坐标变化一个增量(Dx, Dy)而得到,即表示为递归式: xi+1=xi+Dx yi+1=yi+Dy。
递归式的初值为直线的起点(x1, y1),这样,就可以用加法来生成一条直线。具体算法是: 该算法适合所有象限,其中用了用了两个函数如:Integer(-8.5)=-9;Integer(8.5)=8;Sign(i),根据i的正负,分别得到-1,0,+1; 相应代码:
//DDA DrawLine
{if(abs(x2-x1)> abs(y2-y1))
length = abs(x2-x1);
else
length = abs(y2-y1);
Dx =(x2-x1)/length;
Dy =(y2-y1)/length;
x = x1+0.5*Sign(Dx);
y = x2 + 0.5*Sign(Dy);
i = 1;
while(i <= lenght)
{ setpixel(Integer(x),Integer(y),color);
x= x + Dx;
y= y + Dy;
i+=1;} } 3.1.2 Bresenham算法画直线
思路如下: // 假设该线段位于第一象限内且斜率大于0小于1,设起点为(x1,y1),终点为(x2,y2).// 根据对称性,可推导至全象限内的线段.1.画起点(x1,y1).2.准备画下个点。x坐标增1,判断如果达到终点,则完成。否则,由图中可知,下个要画的点要么为当前点的右邻接点,要么是当前点的右上邻接点.如果线段ax+by+c=0与x=x1+1的交点的y坐标大于M点的y坐标的话,下个点为U(x1+1,y1+1),否则,下个点为B(x1+1,y1),3.画点(U或者B).4.跳回第2步.5.结束.3.1.3中心点算法画圆和椭圆
(1)中心点算法画圆
在一个方向上取单位间隔,在另一个方向的取值由两种可能取值的中点离圆的远近而定。实际处理中,用决策变量的符号来确定象素点的选择,因此算法效率较高。生成圆弧的中点算 法和上面讲到的生成直线段的中点算法类似。
考虑第一象限内x[0,R/2]的八分之一圆弧段。经过计算,得出判别式的递推公式为:
di1di2xi3di2(xiyi)5d0d0
(xi, M SE yi,r)E 这两个递推公式的初值条件为:
(x0,y0,r)(0,R)d05/4R
编写成员函数如下:
void CMy2_9View::MidPointEllipse(CDC *pDC, double a, double b, int color){ double x,y,d,xP,yP,squarea,squareb;
squarea=a*a;
squareb=b*b;
xP=(int)(0.5+(double)squarea/sqrt((double)(squarea+squareb)));
yP=(int)(0.5+(double)squareb/sqrt((double)(squarea+squareb)));
x=0;
y=b;
d=4*(squareb-squarea*b)+squarea;
pDC->SetPixel(x,y,color);
while(x<=xP)
{if(d<=0)d+=4*squareb*(2*x+3);
else
{d+=4*squareb*(2*x+3)-8*squarea*(y-1);
y--;}
x++;
pDC->SetPixel(x,y,color);}
x=a;
y=0;
d=4*(squarea-a*squareb)+squareb;
pDC->SetPixel(x,y,color);
while(y { if(d<=0)d+=4*squarea*(2*y+3); else {d+=4*squarea*(2*y+3)-8*squareb*(x-1); x--;} y++; pDC->SetPixel(x,y,color);}} 编写OnDraw函数如下: void CMy2_9View::OnDraw(CDC* pDC){CMy2_9Doc* pDoc = GetDocument();ASSERT_VALID(pDoc);MidPointEllipse(pDC,500,300,RGB(0,0,0));}(2)中心点算法画椭圆 我们先考虑圆心在原点的椭圆的生成,对于中心不是原点的椭圆,可以通过坐标的平移变换获得相应位置的椭圆。中心在原点。焦点在坐标轴上的标准椭圆具有X轴对称、Y轴对称和原点对称特性,已知椭圆上第一象限的P点坐标是(x, y),则椭圆在另外三个象限的对称点分别是(x,-y)、(-x, y)和(-x,-y)。因此,只要画出第一象限的四分之一椭圆,就可以利用这三个对称性得到整个椭圆。 相应代码: void MP_Ellipse(int xc , int yc , int a, int b){ double sqa = a * a;double sqb = b * b;double d = sqb + sqa *(-b + 0.25);int x = 0;int y = b;EllipsePlot(xc, yc, x, y);while(sqb *(x + 1)< sqa *(y1))* 2-(a * b)* 2;while(y > 0){if(d < 0){ d += sqb *(2 * x + 2)+ sqa *(-2 * y + 3);x++;} else {d += sqa *(-2 * y + 3);} y--;EllipsePlot(xc, yc, x, y);}} 3.2 图形变换的基本原理 3.2.1平移变换 平移变换函数如下: void glTranslate{fd}(TYPE x, TYPE y, TYPE z); 三个函数参数就是目标分别沿三个轴向平移的偏移量。这个函数表示用于这三个偏移量生成的矩阵乘以当前矩阵。当参数是(0.0,0.0,0.0)时,表示对函数glTranslate*()的操作是单位矩阵,也就是对物体没有影响。 3.2.2 旋转变换 旋转变换函数如下: Void glRota{fd}TYPE angle, TYPE x, TYPE y, TYPE z); 函数中第一个参数是表示目标沿从点(x,y,z)到原点方向逆时针旋转的角度,后三个参数是旋转的方向点坐标。这个函数表示用这四个参数生成的矩阵乘以当前矩阵。当角度参数是0.0时,表示对物体没有影响。3.2.3 比例变换 比例变换函数如下: Void glScale{fd}(TYPE x, TYPE y, TYPE z); 单个函数参数值就是目标分别沿三个轴方向缩放的比例因子。这个函数表示用这三个比例因子生成的矩阵乘以当前矩阵。这个函数能完成沿相应的轴对目标进行拉伸、压缩和反射三项功能。以参数x为例,若当x大于1.0时,表示沿x方向拉伸目标;若x小于1.0,表示沿x轴方向收缩目标;若x=-1.0表示沿x轴反射目标。其中参数为负值时表示对目标进行相应轴的反射变换。 四、总体设计与功能实现 4.1 主要界面设计 4.2 设置颜色界面 4.2.1 界面设置代码: void CGraphicsView::OnClock(){ WHAT_TO_DO=ID_CLOCK; clean();int xx = 450, yy = 300, r = 150,d = 5;int i, white = RGB(255,255,255);mile(xx, yy, r, COLOR);Matrix m(xx, 240), s(xx, 200);Matrix t1(xx, yy, true), t2(-xx,-yy, true), mr(PI/1800), sr(PI/30);mile(m.getx(), m.gety(), d+1, COLOR);mile(s.getx(), s.gety(), d, COLOR);dne(m.getx(), m.gety(), xx, yy, COLOR);dne(s.getx(), s.gety(), xx, yy, COLOR); for(i=0;i<120;i++){ ::Sleep(80); mile(m.getx(), m.gety(), d+1, white);mile(s.getx(), s.gety(), d, white);dne(m.getx(), m.gety(), xx, yy, white);dne(s.getx(), s.gety(), xx, yy, white);m = t1*mr*t2*m;s = t1*sr*t2*s;mile(m.getx(), m.gety(), d+1, COLOR);mile(s.getx(), s.gety(),d, COLOR);dne(m.getx(), m.gety(), xx, yy, COLOR);dne(s.getx(), s.gety(), xx, yy, COLOR);}} 4.2.2 点击“设置--颜色”后,运行结果如下: 4.3 二维线画图元实现 4.3.1 实现代码: void CGraphicsView::MidCir(CDC *pdc, int x0, int y0, int x1, int y1, int color){ int r,x,y,deltax,deltay,d;r=sqrt(((double)x1-(double)x0)*((double)x1-(double)x0)+((double)y1-(double)y0)*((double)y1-(double)y0));x=0;y=r;deltax=3;deltay=2-r-r;d=1-r;while(x<=y){ ::Sleep(time); pdc->SetPixel(x+x0,y+y0,color); ::Sleep(time); pdc->SetPixel(-x+x0,y+y0,color); ::Sleep(time); pdc->SetPixel(x+x0,-y+y0,color); ::Sleep(time); pdc->SetPixel(-x+x0,-y+y0,color); ::Sleep(time); pdc->SetPixel(y+x0,x+y0,color); ::Sleep(time); pdc->SetPixel(-y+x0,x+y0,color); ::Sleep(time); pdc->SetPixel(y+x0,-x+y0,color); ::Sleep(time); pdc->SetPixel(-y+x0,-x+y0,color); if(d<0) { d+=deltax; deltax+=2; x++;} else { d+=deltax+deltay; deltax+=2; deltay+=2; x++; y--;}}} void CGraphicsView::midellispse(int xx, int yy, int r1, int r2, int color){ } void CGraphicsView::Ellipse(CDC *pdc, int x1, int y1, int x2, int y2, int color){ xx0=(x2+x1)/2;yy0=(y2+y1)/2;rra=abs(x2-x1)/2;rrb=abs(y2-y1)/2;if(rra==0 && rrb==0)return;Ellipse0(pdc,xx0,yy0,rra,rrb,color);} void CGraphicsView::Ellipse0(CDC *pdc, int x0, int y0, int a, int b, int color){ int i,yy;int x,y,deltax,deltay;int aa,aa2,aa3,bb,bb2,bb3;double d1,d2;aa=a*a;aa2=aa*2;aa3=aa*3;bb=b*b;bb2=bb*2;bb3=bb*3;x=0;y=b;d1=bb+aa*(-b+0.25);deltax=bb3;deltay=-aa2*b+aa2;pdc->SetPixelV(x+x0,y+y0,color);pdc->SetPixelV(x+x0,-y+y0,color);while(bb*(x+1) yy=y; if(d1<0) { d1+=deltax; deltax+=bb2; x++;} else { d1+=deltax+deltay; deltax+=bb2; deltay+=aa2; x++; y--;} ::Sleep(time); pdc->SetPixelV(x+x0,y+y0,color); ::Sleep(time); pdc->SetPixelV(-x+x0,y+y0,color); ::Sleep(time); pdc->SetPixelV(x+x0,-y+y0,color); ::Sleep(time); pdc->SetPixelV(-x+x0,-y+y0,color);} d2=bb*(x+0.5)*(x+0.5)+aa*(y-1)*(y-1)-aa*bb;deltax-=bb;deltay+=aa;while(y>0){ if(d2<0) { d2+=deltax+deltay; deltax+=bb2; deltay+=aa2; x++; y--;} else { d2+=deltay; deltay+=aa2; y--;} ::Sleep(time); pdc->SetPixelV(x+x0,y+y0,color); ::Sleep(time); pdc->SetPixelV(-x+x0,y+y0,color); ::Sleep(time); pdc->SetPixelV(x+x0,-y+y0,color); ::Sleep(time); pdc->SetPixelV(-x+x0,-y+y0,color);}} void CGraphicsView::DDALine(CDC *pdc, int x0, int y0, int x1, int y1, int color){ int xx,yy,s,s1,s2,di;float dx,dy,k,x,y;dx=x1-x0;if(dx>=0) s1=1;else s1=-1;dy=y1-y0;if(dy>=0) s2=1;else s2=-1;dx=abs(dx);dy=abs(dy);if(dx>=dy){ s=0; di=(int)dx; k=dy/dx*s2;} else { s=1; di=(int)dy; k=dx/dy*s1;} x=x0;y=y0;for(int i=0;i<=di;i++){if(s==0) { xx=(int)x; yy=(int)(y+0.5); ::Sleep(time); pdc->SetPixel(xx,yy,color); x+=s1; y+=k;} else{ xx=(int)(x+0.5); yy=(int)y; ::Sleep(time); pdc->SetPixel(xx,yy,color); y+=s2; x+=k;}}} 4.3.2 点击二维线画图元,课相应画出直线、圆和椭圆,结果如下: 4.4 画多边形功能的实现 4.4.1 部分实现代码: void CGraphicsView::OnDrawDuoBX(){ Vertex_Count dlg;if(dlg.DoModal()==IDOK){ if(dlg.m_vertex_count>MAX) { MessageBox(“输入顶点数过大”); return;} VertexTotal=dlg.m_vertex_count; CDC *pDC=GetDC(); CPen pen(PS_SOLID,2,RGB(255,255,255)); CPen *pOldpen=pDC->SelectObject(&pen); pDC->MoveTo((int)(inVertexArray[0].x+0.5),(int)(inVertexArray[0].y+0.5)); int i; for(i=1;i pDC->LineTo((int)(inVertexArray[i].x+0.5),(int)(inVertexArray[i].y+0.5)); pDC->LineTo((int)(inVertexArray[0].x+0.5),(int)(inVertexArray[0].y+0.5)); pDC->SelectObject(pOldpen); ReleaseDC(pDC); inLength=0; outLength=0; WHAT_TO_DO=ID_DrawDuoBX;}} 4.4.2 点击多边形,输入定点个数,可绘制出相应的多边形,结果如下: 4.5 画Bezier曲线功能的实现 4.5.1 部分实现代码: void CGraphicsView::OnBezier(){ // TODO: Add your command handler code here WHAT_TO_DO=ID_BEZIER;CDC *p=GetDC(); p->TextOut(10, 20, “PS:鼠标左键添加曲线,鼠标右键修改曲线.”); ReleaseDC(p);} void CGraphicsView::OnBezierClear(){ n =-1;RedrawWindow();} void CGraphicsView::DrawBezier(DPOINT *p){ if(n <= 0)return;if((p[n].x < p[0].x+1)&&(p[n].x > p[0].x-1)&&(p[n].y < p[0].y+1)&&(p[n].y > p[0].y-1)){ pDC->SetPixel(p[0].x, p[0].y, COLOR); return;} DPOINT *p1;p1 = new DPOINT[n+1];int i, j;p1[0] = p[0];for(i=1;i<=n;i++){ for(j=0;j<=n-i;j++) { p[j].x =(p[j].x + p[j+1].x)/2; p[j].y =(p[j].y + p[j+1].y)/2;} p1[i] = p[0];} DrawBezier(p);DrawBezier(p1);delete p1;} void CGraphicsView::OnBezierAdd(){ AddorMove = 1;} void CGraphicsView::OnBezierMove(){ AddorMove =-1;} void CGraphicsView::OnMouseMove(UINT nFlags, CPoint point){ switch(WHAT_TO_DO){ case ID_BEZIER: { if(current >= 0){ points[current].x = point.x; points[current].y = point.y; RedrawWindow();} if(current2 >= 0) { points[current2].x = point.x; points[current2].y = point.y; RedrawWindow();} break;} default:break;} CView::OnMouseMove(nFlags, point);} 4.5.2 点击曲线--Beizer曲线,可实现Beizer曲线的绘制功能,绘制结果如下图: 图 1 图 2 4.5.3 点击曲线--Beizer曲线,可实现Beizer曲线的移动,鼠标点击其中的任一点,可实现曲线的移动,绘制结果如下图: 上图1移动后的曲线 上图2移动后的曲线 4.6 二维图形变换的实现 可以实现一椭圆在界面上的随机移动,一圆在界面上饶某一点的旋转和一正方形由大变小在变大的变化,部分实现代码如下: void CGraphicsView::OnXuanzhuan(){ WHAT_TO_DO=ID_XUANZHUAN; time=0; OnClear(); CClientDC dc(this);CDC* pDC=&dc; int i, white=RGB(255,255,255), point [2][2]={{300,200},{300,250}}; Matrix a(point[0][0],point[0][1]), b(point[1][0],point[1][1]); int midx=(point[0][0]+point[1][0])/2,midy=(point[0][1]+point[1][1])/2; Matrix t1(midx, midy,true), t2(-midx,-midy,true); Matrix r(PI/50); Matrix temp(midx, midy,true); temp = t1*r*t2; for(i=0;i<200;i++){ ::Sleep(50); MidCir(pDC, a.getx(), a.gety(), b.getx(), b.gety(), white); a = temp*a; b = temp*b; MidCir(pDC, a.getx(), a.gety(), b.getx(), b.gety(), COLOR);} for(i=0;i<200;i++){ ::Sleep(50); MidCir(pDC,a.getx(), a.gety(), b.getx(), b.gety(), white); a = temp*a; b = temp*b; MidCir(pDC, a.getx(), a.gety(), b.getx(), b.gety(), COLOR);} time=5;} void CGraphicsView::OnUpdateXuanzhuan(CCmdUI* pCmdUI){ pCmdUI->SetCheck(WHAT_TO_DO==ID_XUANZHUAN);} void CGraphicsView::OnScale(){ WHAT_TO_DO=ID_SCALE; OnClear();CClientDC dc(this);CDC* pDC=&dc; time=0;int i,white=RGB(255,255,255), point[4][2]={{300,250},{400,250},{300,300},{400,300}};float sx=0.9,sy=0.85;int midx=(point[0][0]+point[3][0])/2,midy=(point[0][1]+point[3][1])/2;Matrix s1(sx,sy),s2(1/sx,1/sy);Matrix t1(midx, midy,true), t2(-midx,-midy,true); Matrix a(point[0][0],point[0][1]), b(point[1][0],point[1][1]);Matrix c(point[2][0],point[2][1]), d(point[3][0],point[3][1]);Matrix temp(midx, midy,true);temp = t1*s1*t2;DDALine(pDC,a.getx(),a.gety(),b.getx(),b.gety(),COLOR);DDALine(pDC,a.getx(),a.gety(),c.getx(),c.gety(),COLOR);DDALine(pDC,c.getx(),c.gety(),d.getx(),d.gety(),COLOR);DDALine(pDC,d.getx(),d.gety(),b.getx(),b.gety(),COLOR);for(i=0;i<20;i++){ ::Sleep(30); DDALine(pDC,a.getx(),a.gety(),b.getx(),b.gety(),white); DDALine(pDC,a.getx(),a.gety(),c.getx(),c.gety(),white); DDALine(pDC,c.getx(),c.gety(),d.getx(),d.gety(),white); DDALine(pDC,d.getx(),d.gety(),b.getx(),b.gety(),white); a=temp*a; b=temp*b; c=temp*c; d=temp*d; DDALine(pDC,a.getx(),a.gety(),b.getx(),b.gety(),COLOR); DDALine(pDC,a.getx(),a.gety(),c.getx(),c.gety(),COLOR); DDALine(pDC,c.getx(),c.gety(),d.getx(),d.gety(),COLOR); DDALine(pDC,d.getx(),d.gety(),b.getx(),b.gety(),COLOR);} temp = t1*s2*t2;for(i=0;i<20;i++){ ::Sleep(30); DDALine(pDC,a.getx(),a.gety(),b.getx(),b.gety(),white); DDALine(pDC,a.getx(),a.gety(),c.getx(),c.gety(),white); DDALine(pDC,c.getx(),c.gety(),d.getx(),d.gety(),white); DDALine(pDC,d.getx(),d.gety(),b.getx(),b.gety(),white); a=temp*a; b=temp*b; c=temp*c; d=temp*d; DDALine(pDC,a.getx(),a.gety(),b.getx(),b.gety(),COLOR); DDALine(pDC,a.getx(),a.gety(),c.getx(),c.gety(),COLOR); DDALine(pDC,c.getx(),c.gety(),d.getx(),d.gety(),COLOR); DDALine(pDC,d.getx(),d.gety(),b.getx(),b.gety(),COLOR);} time=5;} void CGraphicsView::OnUpdateScale(CCmdUI* pCmdUI){ pCmdUI->SetCheck(WHAT_TO_DO==ID_SCALE);} 4.7 三维图形的变换 主要实现三维图形的上下左右平移,分别绕X轴Y轴Z轴的旋转,放大和缩小,以及正方体六个面的颜色变换,除此之外,还可以选择背景颜色的改变 4.7.1 部分代码如下: void CGraphicsView::OnAoduomianti(){ WHAT_TO_DO=ID_AODUOMIANTI;CDrawDLG dlg1;dlg1.DoModal();} void CGraphicsView::OnUpdateAoduomianti(CCmdUI* pCmdUI){ pCmdUI->SetCheck(WHAT_TO_DO==ID_AODUOMIANTI);} void CDrawDLG::OnPaint() { CPaintDC dc(this);// device context for painting CWnd *pWnd=GetDlgItem(IDC_DRAW);pWnd->UpdateWindow();// CDC *PDC=pWnd->GetDC();Draw();} void CDrawDLG::Draw(){ CWnd *pWnd=GetDlgItem(IDC_DRAW);pWnd->UpdateWindow();CDC *pDC=pWnd->GetDC();CRect rect;pWnd->GetClientRect(rect);D v[8]={ {-fs,-fs,fs},{-fs,fs,fs},{fs,fs,fs},{fs,-fs,fs},{-fs,-fs,-fs},{-fs,fs,-fs},{fs,fs,-fs},{fs,-fs,-fs} },d[8]; POINT p0[4],p1[4],p2[4],p3[4],p4[4],p5[4],w[8];int z[8]; for(int i=0;i<8;i++){ d[i].x=v[i].x; d[i].y=(int)(v[i].y*cos(a*DU)-v[i].z*sin(a*DU)); d[i].z=(int)(v[i].y*sin(a*DU)+v[i].z*cos(a*DU)); v[i].x=(int)(d[i].x*cos(b*DU)+d[i].z*sin(b*DU)); v[i].y=d[i].y; v[i].z=(int)(d[i].z*cos(b*DU)-d[i].x*sin(b*DU)); d[i].x=(int)(v[i].x*cos(c*DU)-v[i].y*sin(c*DU)); d[i].y=(int)(v[i].x*sin(c*DU)+v[i].y*cos(c*DU)); d[i].z=v[i].z; w[i].x=d[i].x+cx; w[i].y=d[i].y+cy; z[i]=d[i].z;} p0[0]=w[0];p0[1]=w[1];p0[2]=w[2];p0[3]=w[3];p1[0]=w[4];p1[1]=w[5];p1[2]=w[6];p1[3]=w[7]; p2[0]=w[0];p2[1]=w[1];p2[2]=w[5];p2[3]=w[4];p3[0]=w[1];p3[1]=w[2];p3[2]=w[6];p3[3]=w[5];p4[0]=w[2];p4[1]=w[3];p4[2]=w[7];p4[3]=w[6];p5[0]=w[0];p5[1]=w[3];p5[2]=w[7];p5[3]=w[4];switch(Maxnum(z,7)){ case 0:fill(p0,p2,p5,0,2,5);break; case 1:fill(p0,p2,p3,0,2,3);break; case 2:fill(p0,p3,p4,0,3,4);break; case 3:fill(p0,p4,p5,0,4,5);break; case 4:fill(p1,p2,p5,1,2,5);break; case 5:fill(p1,p2,p3,1,2,3);break; case 6:fill(p1,p3,p4,1,3,4);break; case 7:fill(p1,p4,p5,1,4,5);break;}} BOOL CDrawDLG::OnInitDialog(){ CDialog::OnInitDialog();m_scroll1.SetScrollRange(-180,180);m_scroll1.SetScrollPos(0);m_scroll2.SetScrollRange(-180,180);m_scroll2.SetScrollPos(0);m_scroll3.SetScrollRange(-180,180);m_scroll3.SetScrollPos(0);m_scroll4.SetScrollRange(0,350);m_scroll4.SetScrollPos(200);m_scroll5.SetScrollRange(0,300);m_scroll5.SetScrollPos(115);m_scroll6.SetScrollRange(0.00,300.00);m_scroll6.SetScrollPos(50.00);a=b=c=0;fs=50.00;SetTimer(1,100,NULL);Ctrl=0;cx=200;cy=115;COLOR1=RGB(123,234,43);COLOR2=RGB(123,123,0);COLOR3=RGB(123,24,235);COLOR4=RGB(0,123,95);COLOR5=RGB(23,234,34);COLOR6=RGB(234,124,0);COLOR7=RGB(0,43,98);return TRUE;// return TRUE unless you set the focus to a control} void CDrawDLG::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar){ int nID=pScrollBar->GetDlgCtrlID();switch(nID){ case IDC_SCROLLBAR1: a=pScrollBar->GetScrollPos(); switch(nSBCode) { case SB_LINELEFT: a--;break; case SB_LINERIGHT: a++;break; case SB_PAGELEFT: a-=10;break; case SB_PAGERIGHT: a+=10;break; case SB_THUMBTRACK: a=nPos;break;} if(a<-180)a=180; if(a>180)a=-180; pScrollBar->SetScrollPos(a); break;case IDC_SCROLLBAR2: b=pScrollBar->GetScrollPos(); switch(nSBCode) { case SB_LINELEFT: b--;break; case SB_LINERIGHT: b++;break; case SB_PAGELEFT: b-=10;break; case SB_PAGERIGHT: b+=10;break; case SB_THUMBTRACK: b=nPos;break;} if(b<-180)b=180; if(b>180)b=-180; pScrollBar->SetScrollPos(b); break;case IDC_SCROLLBAR3: c=pScrollBar->GetScrollPos(); switch(nSBCode) { case SB_LINELEFT: c--;break; case SB_LINERIGHT: c++;break; case SB_PAGELEFT: c-=10;break; case SB_PAGERIGHT: c+=10;break; case SB_THUMBTRACK: c=nPos;break;} if(c<-180)c=180; if(c>180)c=-180; pScrollBar->SetScrollPos(c); break;case IDC_SCROLLBAR4: cx=pScrollBar->GetScrollPos(); switch(nSBCode) { case SB_LINELEFT: cx--;break; case SB_LINERIGHT: cx++;break; case SB_PAGELEFT: cx-=10;break; case SB_PAGERIGHT: cx+=10;break; case SB_THUMBTRACK: cx=nPos;break;} if(cx<0)cx=200; if(cx>350)cx=200; pScrollBar->SetScrollPos(cx); break;case IDC_SCROLLBAR5: cy=pScrollBar->GetScrollPos(); switch(nSBCode) { case SB_LINELEFT: cy--;break; case SB_LINERIGHT: cy++;break; case SB_PAGELEFT: cy-=10;break; case SB_PAGERIGHT: cy+=10;break; case SB_THUMBTRACK: cy=nPos;break;} if(cy<0)cy=300; if(cy>300)cy=0; pScrollBar->SetScrollPos(cy); break; case IDC_SCROLLBAR6: fs=pScrollBar->GetScrollPos(); switch(nSBCode) { case SB_LINELEFT: fs--;break; case SB_LINERIGHT: fs++;break; case SB_PAGELEFT: fs-=0.55;break; case SB_PAGERIGHT: fs+=0.55;break; case SB_THUMBTRACK: fs=nPos;break;} if(fs<0)fs=50; if(fs>300)fs=50; pScrollBar->SetScrollPos(fs); break;// UpdateData(FALSE);} // Invalidate();Draw();CDialog::OnHScroll(nSBCode, nPos, pScrollBar);} void CDrawDLG::OnOK(){ KillTimer(1); CDialog::OnOK();} int CDrawDLG::Maxnum(int *p, int n){ int max=p[0];int x;for(int i=0;i<=n;i++){ if(max<=p[i]) { max=p[i];x=i;} } return x;} void CDrawDLG::fill(POINT *x, POINT *y, POINT *z, int i,int j,int q){ CWnd *pWnd=GetDlgItem(IDC_DRAW);pWnd->UpdateWindow();CDC *pDC=pWnd->GetDC();CRect rect;pWnd->GetClientRect(rect); CDC dcmem;dcmem.CreateCompatibleDC(pDC);CBitmap bmp,*oldbmp;bmp.CreateCompatibleBitmap(pDC,rect.Width(),rect.Height());oldbmp=dcmem.SelectObject(&bmp);CBrush brush[6];brush[0].CreateSolidBrush(COLOR1);brush[1].CreateSolidBrush(COLOR2);brush[2].CreateSolidBrush(COLOR3);brush[3].CreateSolidBrush(COLOR4);brush[4].CreateSolidBrush(COLOR5);brush[5].CreateSolidBrush(COLOR6);CBrush *oldbrush=dcmem.SelectObject(&brush[i]);dcmem.FillSolidRect(rect,COLOR7);dcmem.Polygon(x,4);dcmem.SelectObject(&brush[j]);dcmem.Polygon(y,4);dcmem.SelectObject(&brush[q]);dcmem.Polygon(z,4);dcmem.SelectObject(oldbrush);for(int b=0;b<6;b++)brush[b].DeleteObject();pDC->BitBlt(rect.left,rect.top,rect.Width(),rect.Height(), &dcmem,0,0,SRCCOPY);dcmem.SelectObject(oldbmp);bmp.DeleteObject();dcmem.DeleteDC();} 4.7.2 运行结果如下: (1)实现多面体的上下左右平移(2)实现多面体的绕轴旋转: (3)实现多面体的放大缩小: (4)实现多面体及背景的颜色设置: (5)三维图形变换整体图形 五、实验心得体会 在本次课程设计过程中,基本掌握了计算机图形学关于图形绘制变换的基础知识,DDA法画直线和中心点法画圆及椭圆的方法,还对图形的变换及需要用到的一系列的函数有了相应的理解,也了解的很多有关于图形学中三维图形的变换的知识。不过都只是皮毛而已,从中锻炼了自己的动手做实验的能力,但同时也让自己看清了自己的水平,以便在以后的生活里多加强有关这方面的学习,从而提升自己在图形学方面的知识水平。 在本次课程设计中,设计方案存在着很多的死板化的实现方法,也是很不人性化的一点,只提供了画一种曲线的方法,且画出的曲线只能移动,此为本次设计方案的不足之一;然后就是能实现曲面和多边形的绘制,却没有对应的实现绘制好图形后直接对其进行平移、选择等变换,此为设计方案不足之二。再者就是三维图形只能实现变换不能实现绘制,此为设计方案不足之三。鉴于个人能力真的有限,所以只能设计出此种级别的效果了。因为实验重要的只是思想过程,效果的不美观只能是因为学习的知识还远远不够,所以不能设计出完美的全面的图形绘制变换程序。 经过此次设计,使我学到了很多东西,在没有开始做程序之前,没有任何思路,不知道该从哪里入手,可能是因为自己平时不认真听课的缘故。后来经过上网查询资料,翻阅参考书,在别人做的程序的启发下,才有了做此程序设计的眉目。在设计过程中遇到了很多的问题,在这里需要感谢王征风老师的帮助和指导,以及同学的帮助,最后一个个问题都被解决了,写出了完整的程序设计。最后也发现,其实只要努力,写出一个设计不是很困难,重要的是自己在写程序的过程中,要会学习,会查阅资料。这次的课程设计让我学习到了很多,以后我会努力提高自己在图形学方面的知识水平。 吉林大学 计算机科学与技术学院 《计算机图形学》实验报告 班级: 211923班 学号: 21190928 姓名: 林星宇 2021-2022学年第1学期 实验项目1 边标志算法的实现 实验性质 □演示性实验 验证性实验 □操作性实验 综合性实验 实验地点 计算机楼B212 机器编号 一、实现的功能 编写应用程序,采用鼠标输入顶点的方法确定待填充多边形(多边形最后一点双击);实现边标志算法完成对该多边形的填充,要求 完成使用自己学号的后四位数字对多边形内部进行填充。 二、采用的图形学算法及实现 (算法的实现函数是什么(函数名,参数,返回值,函数功能等)以及采用了哪些数据结构(数组,链表等)) 要求使用边标志算法的原理和实 现方法,所以使用了EdgeMarkFill函数,即边标志算法: void CMFCDrawTestView::EdgeMarkFill(CDC* pDC, CArray pDC为设备环境变量指针,plist为多边形点表,color为传入的RGB()值。 int zima[16][32]为学号后4位二维数组。 X1,x2,y1,y2分别为多边形上的最小最小大,y值 三、采用的交互方式及实现 (采用了哪些交互方式来完成绘制,这些交互方式应用到了哪些系统消息,是如何实现的) 边填充的实现:编写应用程序,采用鼠标输入顶点的方法确定待填充多边形(多边形最后一点双击);实现边标志算法完成对该多边形的填充,要求 完成使用自己学号的后四位数字对多边形内部进行填充。 易知,在画完多边形后,即双击左键(OnLButtonUp)后,使用EdgeMarkFill函数。 Type=2时,在OnLButtonUp中,调用EdgeMarkFill(pDC,&(obj->points), RGB(r, 0, 0)); 四、实验结果 (程序的运行结果) 应用程序运行后,标志算法完成对该多边形的填充的图形结果如下: 五、遇到的问题及解决办法 问题1:(在实现过程中遇到了什么样的问题,及采用了何种解决办法) 在获取下x1,x2,y1,y2时,因为Dos界面x、y大小颠倒的原因,获取时出现了问题。 首先,通过for(int i = 1;i < plist->GetSize();i++){ CPoint p = plist->GetAt(i); if(x1 > p.x)x1 = p.x; if(x2 < p.x)x2 = p.x; if(y1 > p.y)y1 = p.y; if(y2 < p.y)y2 = p.y; } 获取x1,x2,y1,y2.在遍历多边形过程中: int count = plist->GetSize(); for(int i = 0;i < count;i++){ CPoint p1 = plist->GetAt(i); CPoint p2 = plist->GetAt((i + 1)% count); if(p1.y == p2.y) continue; if(p1.y > p2.y) { CPoint p;p = p1;p1 = p2;p2 = p; } xs = p1.x; dxs =(p2.x-p1.x)/(double)(p2.y-p1.y); //dys = abs(p2.y-p1.y)/(p2.y-p1.y); for(ys = p1.y;ys!= p2.y;ys += 1) { Ixs = int(xs + 0.5); MARK[ys][Ixs] =!MARK[ys][Ixs]; xs = xs + dxs; } 黄线处即为处理x1,x2,y1,y2的大小。 问题2:通过数组zima[][]来确定多边形区域填充学号后4位时,zima[y ][x ]未%其字长,即zima[y % 16][x % 32]。后改为: for(y = y1;y <= y2;y++) { bool inside = false; for(x = x1;x <= x2;x++) { if(MARK[y][x]) inside =!inside; if(inside) { if(zima[y % 16][x % 32]) pDC->SetPixel(x, y, RGB(255, 0, 0)); } } } 实验项目2 立方体的比例、平移、旋转变换及投影显示 实验性质 □演示性实验 验证性实验 □操作性实验 综合性实验 实验地点 计算机楼B212 机器编号 一、实现的功能 建立立方体的数据模型;编写应用程序,利用菜单和键盘结合的方式完成对立方体的移动、比例和旋转变换,并显示透视或斜二测投影结果。要求应用程序具有如下功能: 1、通过菜单选择的方式,选择对三维空间中的立方体作斜二测投 影或透视投影; 2、通过键盘按键或鼠标移动的方式,完成对三维空间中的立方体 进行平移变换(上下左右前后),比例变换(放大或缩小)以及 旋转变换(绕 x,y,z 轴),并同时显示变换后的投影结果 3、创建对话框,通过对话框设置透视投影时候的投影中心,以及旋转变换时候的旋转轴(可以设置成分别绕 x 轴,y 轴,z 轴进 行旋转) 二、采用的图形学算法及实现 (算法的实现函数是什么(函数名,参数,返回值,函数功能等)以及采用了哪些数据结构(数组,链表等)) 题目要求实现立方体的移动、比例和旋转变换,并显示透视或斜二测投影结果。 对要求1:在菜单选TY项中选择斜二测投影(斜二=1)或透视投影(透视=1)。然后在OnDraw中调用Draw_Cubic(CDC* pDC)画出立方体。 对要求2:在OnKeyDown中调用函数,即在键盘上按“S”使立方体变小,“B”使立方体变大,“←”“→”“↑”“↓”使立方体左右上下移动。 对要求3:在菜单XYZ中选择旋转的x,y,z轴,即x=1或y=1或z=1,然后在OnKeyDown中调用函数,即按键盘上的“T”或“P”. 三、采用的交互方式及实现 (采用了哪些交互方式来完成绘制,这些交互方式应用到了哪些系统消息,是如何实现的) 由题目要求1,易知需要一个函数Draw_Cubic(CDC* pDC)画出立方体的斜二测投影或透视投影并且建立一个菜单栏TY(投影)。即在菜单选TY项中选择斜二测投影(斜二=1)或透视投影(透视=1)。然后在OnDraw中调用Draw_Cubic(CDC* pDC)画出立方体。 由题目要求2:易知直接在OnKeyDown函数上添加使立方体变大变小,前后左右平移的功能。即即在键盘上按“S”使立方体变小,“B”使立方体变大,“←”“→”“↑”“↓”使立方体左右上下移动。 由题目要求3:建立一个菜单XYZ决定旋转的轴。 四、实验结果 (程序的运行结果) 斜二测投影: 斜二测投影平移到左上角: 斜二测投影平移到右下角: 斜二测投影变大: 斜二测投影变小: 斜二测投影变为透视投影: 斜二测投影绕z轴旋转: 五、遇到的问题及解决办法 (在实现过程中遇到了什么样的问题,及采用了何种解决办法) 问题1:一开始建立立方体时,没有建立边表,导致投影困难。 后来建立了点表和对应的边表。 问题2:一开始Draw_Cubic中x1, y1,z1, x2, y2,z2定义为了int型。 实验项目3 用矩形窗口对多边形进行裁剪 实验性质 □演示性实验 验证性实验 □操作性实验 综合性实验 实验地点 计算机楼B212 机器编号 一、实现的功能 编写应用程序实现多边形裁剪。要求首先采用鼠标确定裁剪区域(矩形区域),然 后用鼠标输入待裁剪的多边形(可分别使用鼠标左键和右键来确定裁剪区域和待裁剪 的多边形)。多边形绘制完毕后进行裁剪,以不同颜色显示被裁剪对象位于窗口内(此 部分应保证多边形的完整性)及外部的部分。 二、采用的图形学算法及实现 (算法的实现函数是什么(函数名,参数,返回值,函数功能等)以及采用了哪些数据结构(数组,链表等)) 因为要编写应用程序实现多边形裁剪。要求首先采用鼠标确定裁剪区域(矩形区域),然 后用鼠标输入待裁剪的多边形(可分别使用鼠标左键和右键来确定裁剪区域和待裁剪 的多边形)。所以要使用多边形裁剪算法,即Cut_Top(),Cut_Bottom(),Cut_Left(),Cut_Right()四个函数。 Cut()函数为用绿色显示被裁剪对象位于窗口内部分。 存在int type的变量; 当type=1时,在OnLButtonUp中画出矩形框。 当type=2时,画出多边形,在左键双击后,在OnLButtonDblClk中调用如下函数:Cut_Top();Cut_Right();Cut_Bottom();Cut_Left();Cut(); 裁剪多边形在,并标出在矩形内部的部分。 三、采用的交互方式及实现 (采用了哪些交互方式来完成绘制,这些交互方式应用到了哪些系统消息,是如何实现的) 编写应用程序实现多边形裁剪。要求首先采用鼠标确定裁剪区域(矩形区域),然 后用鼠标输入待裁剪的多边形(可分别使用鼠标左键和右键来确定裁剪区域和待裁剪 的多边形)。多边形绘制完毕后进行裁剪,以不同颜色显示被裁剪对象位于窗口内(此 部分应保证多边形的完整性)及外部的部分。 根据以上绘制方法,可知需要处理WM_OnLButtonDblClk(左键双击)及WM_LButtonUp(左键抬起)消息,为了绘制橡皮线,还需处理调用WM_MouseMove(鼠标移动)消息。 因为可以用鼠标画出矩形和多边形,所以这么规定,当type=1时画矩形,即: DDALine(pDC,lx,by,lx,ty,RGB(r, g, b)); DDALine(pDC, lx, by, rx, by, RGB(r, g, b)); DDALine(pDC, rx, by, rx, ty, RGB(r, g, b)); DDALine(pDC, lx, ty, rx, ty, RGB(r, g, b)); 当type=2时画多边形,而后裁剪,即: for(int i = 0;i < pointList.GetSize();i++) { p1 = pointList.GetAt(i); p2 = pointList.GetAt((i+1)% count); DDALine(pDC, p1.x, p1.y, p2.x, p2.y, RGB(0,255,0)); } 四、实验结果 (程序的运行结果) 裁剪结果如下图所示,黑色为裁剪窗口,红色为多边形被裁剪的部分,绿色为多边形裁剪后的部分: 五、遇到的问题及解决办法 (在实现过程中遇到了什么样的问题,及采用了何种解决办法) 问题1:我在裁剪使一开始对多边形做上下左右裁剪时,这四个步骤是分别对原图形裁剪,而不是对图形接连进行裁剪。后来在裁剪函数上先除去之前图形,然后把已裁剪多边形重新构建。如下: pointList.RemoveAll(); for(int i = 0;i < m;i++) pointList.Add(CP[i]); 问题2:在多边形被矩形裁剪的部分显现不同颜色花费了挺多时间,后来我直接让裁剪的部分颜色被覆盖就可以了。如下: for(int i = 0;i < pointList.GetSize();i++) { p1 = pointList.GetAt(i); p2 = pointList.GetAt((i+1)% count); DDALine(pDC, p1.x, p1.y, p2.x, p2.y, RGB(0,255,0)); } 《计算机图形学》学习报告 东西方建筑中的理性 尽管东方“木构”的暂时性文化和西方“石砌”的永久性文化氛围造成了建筑形式风格的差异,但是它们都兼有理性和感性美。从柱式的英文“order”一词,到中国古建筑等级制的基数开间,无不透露着匠人的理性思考;从古埃及绘画中为了将人的特征最大限度表现而作的头部侧面身体正面的绘画,到文艺复兴达芬奇创造的透视画法,一步步将人们引向更为理性的世界。 西方古典主义者强调构图中的主从关系,突出轴线、讲求配称;倡导理性,主张建筑的真实,反对表现感情和情绪。随之而来的比例、节奏、韵律、秩序美,是建筑区别于雕塑和绘画两大艺术的特点。 维特鲁威提出的建筑三原则:坚固、适用、美观,时时刻刻提醒着我们建筑是要被建造起来的,它是我们的“避难所”,需要理性的结构、缜密的分析和思考。时代在进步,建筑理论从勒杜克的结构理性主义发展到现在的解构主义,再也不是建筑形式适应结构的时代了,而是两者互为促进。 我们对建筑的理解不再是像路易斯康那样再去问砖想做什么,等待它做拱卷的回答。我们向大自然学习,卡拉特拉瓦创造了许多带有理性美的仿生建筑。当我们想进一步拓宽我们的思维时,我们还能向谁求助?计算机图形学为我们打开了理性思考的一扇窗。 计算机图形学对理性建筑的贡献 半个多世纪以来,计算机技术得到了飞速的发展。它的进步不仅仅使世界变得更平,信息交流更便捷,在此平台上开发的各种绘图软件更是将建筑师从传统的手工渲染画图中解放出来,也解放了结构师的工作量。用了30年的时间,计算机的速度从K(103)到T(1012),而从T到Z(1021),我们只用了10年时间。发展的速度是越来越快,我们设计方法和速度都得到了革新。这是这样一个数字化信息化的时代,才有弗兰克盖里建筑的夸张和扎哈哈迪德设计的新奇。 原来我们随手绘出的自由曲线,现在计算机都能帮我们算出是否有建造的可能,以及建筑性能也能在建造前得到分析。在创意上,计算机也能将我们模糊的概念无限发展,给它一个规则,它可能还你一个超乎想象的造型,在理性规则中生成感性而自由的建筑。 知其然,还应知其所以然,看着电视机的变薄,图像更加逼真,这变化的一切都建立在计算机图形学的架构下,了解了基础原理,才能更高效地做高质量的建筑设计。 计算机图形学的理论知识 1.相关概念 计算机图形学是主要研究通过计算机处理用集合数据和数学模型所描述的图形的原理、算法和系统。包括图形的输入、存储、运算、转换、传送和输出。数字化技术是泛指在某特定领域利用包括硬件、软件在内的计算机与电子技术以及数学或数字模型等描述的问题进行求解、模拟或分析活动的一切应用技术。 建筑数字化技术研究应用包括建筑的数字化设计和反映建筑的数字化特征在内的数字技术。而建筑数字化技术的核心几何学科就是计算机图形学。2.反映建筑数字化特征的典型图形技术 建筑的动态特征——图形显示:如奥地利格拉茨美术馆的925盏灯形成的外墙面显示屏 建筑的互动特征——图形显示:如杜瑟赫姆市的随情感变化而色彩变化的建筑物 建筑的数字特征——几何运算:如柏林Max Reinhardt大楼模型及“莫比乌斯环”变换 建筑的虚实特征——交互式图形:如法国国立图书馆(实体与网络图书馆) 设计手段和设计媒体的数字化特征——交互式图形:如纽约韩国基督教长老会教堂 而建筑性能如声环境、热环境、光环境、风环境模拟的可视化分析中都用到了图形学。3.虚拟现实技术(VR) 虚拟现实技术是计算机生成的给人多种感官刺激的虚拟世界(环境),是一种高级的人机交互系统。 虚拟现实技术的三个基本特征:沉浸感、交互性、想象力 它具有多学科的综合性,正如建筑学是一门综合的艺术,虚拟现实技术包括图像处理、图形学、计算几何、多传感器、网络、多媒体和仿真技术等。 正如课堂上老师放映的《碟中谍4》,逼真的爆炸场景,以及从皮克斯动画开始的动物毛发到最近火热的《少年派》逼真的老虎与人共存画面,虚拟现实技术的进步影响到了我们生活的方方面面,触到了我们原来想都不敢想的世界。 而VR技术在建筑行业中,有以下作用:(1)指导设计:让建筑师通过浏览观察和了解空间关系,特别是对空间大小、方向、形状和建筑元素行为的理解。(2)建筑表现与环境仿真(3)仿真施工:检查和修改施工细节、合理性和有效性 4.虚拟现实的基础与关键技术:建模与描绘 基于几何和图形学的建模和描绘技术 直接几何建模 3D扫描建模 投影视图建模 基于图像的场景描绘技术(IBR) 图像投影变形技术 光场重建技术 混合式IBR技术 IBR技术图形的绘制独立于场景的复杂性,仅仅与所要生成画面的分辨率有关。 实验三 MFC画直线 最近自己在学习如何在VC 6.0 开发环境下的使用MFC AppWizard(exe)来绘画一条直线,虽然比较简单,通过这样的练习可以帮助你熟悉MFC的开发环境以及其中的消息传递机制,希望对于像我一样初入MFC图形绘制学习的人有帮 助 第一步:构建MFC窗体 打开Visual C++ 6.0编译器 新建→工程→MFC AppWizard(exe),工程名以DrawLine为例,然后确定。为了方便,在MFC应用程序向导—步骤1当中选择“单文档”,其余所有的步骤都为默认值,直接“完成”。这样一个简单的MFC窗体就构建好了,自己不妨Compile—Build—BuildExecute一下。 第二步:编辑菜单项 选择ResourceView视窗展开Menu文件夹,左键双击IDR_DRAWLITYPE,右边就会出现菜单图形编辑界面,为了简化,我们只在添加帮助→DrawLine功能选择项。双击空白会弹出“菜单项目 属性”对话框。ID:ID_DRAW_LINE;标明: DrawLine(&D),其它的为缺省。 第三步:建立消息命令 如果此时运行该程序,你会发现帮助—DrawLine的功能选项是灰色的,原因就在于我们还没有添加该功能的消息命令相应函数。通过“查看—Message Maps—Project:DrawLine—Class name:CDrawLineView—Object IDs:ID_DRAW_LINE—选定COMMAND—Add Function„”,其它为默认,最后确定完成。现在如果再重新运行该程序的话,会发现原来的灰色已经消除了。 第四步:添加鼠标消息响应 打开ClassView视窗,右键选定CDrawLineView,选择Add Windows Messsage Handler会弹出对话框,完成CDrawLineView类的WM_LBUTTONDOWN、WM_MOUSEMOVE、WM_LBUTTONUP三个Windows消息事件的新建。 第五步:添加响应代码 首先,在ClassView视窗中双击CDrawLineView会定位到“DrawLineView.h : interface of the CDrawLineView class”的文件,添加CDrawLineView类的成员:protected: int m_Drag;POINT m_pPrev;POINT m_pOrigin;三个成员变量。视窗中展开CDrawLineView类,双击定位OnLBUTTONDOWN()函数。在该函数消息响应 处添加如下代码: //建立好绘图的设备环境 CClientDC dc(this);OnPrepareDC(&dc); dc.DPtoLP(&point); //获取起始点坐标 m_pPrev=point;m_pOrigin=point; m_Drag=1; 然后,定位于OnMouseMove(),添加如下代码(其中关键用到了橡皮筋技术): //建立好绘图的设备环境 CClientDC dc(this); OnPrepareDC(&dc);dc.DPtoLP(&point); dc.SetROP2(R2_NOT);//橡皮筋绘图技术 //判断是否BUTTONDOWN if(m_Drag) { dc.MoveTo(m_pOrigin);dc.LineTo(m_pPrev);dc.MoveTo(m_pOrigin);dc.LineTo(point); } m_pPrev=point; 最后,在OnLBUTTONDOWN()添加代码: m_Drag=0; 程序运行效果图 实验4 实现圆的生成算法 一、实验目的 1.熟悉CDC图形程序库; 2.掌握中点画圆生成算法; 3.掌握Bresenham画圆算法。 二、实验内容 利用VisualC++6.0设计一个简易画圆绘图板,验证圆生成算法。 三、实验指导 1.生成绘图应用程序的框架,如下图所示。具体实现见第二次实验,过程不再详细说明。 2.在应用程序中增加菜单 完成相关菜单的设计,具体的效果如下图所示,并设置好相关菜单消息的映射,具体的实现在前面的实验中介绍过,再此不在详细说明。 3.在绘图函数中添加代码 通过以上步骤,得到了与菜单对应的消息映射,就可以在函数中添加代码绘制图形了。(1)利用中点画圆算法实现圆的生成(算法原理见教材)。void CDraw_CirView::OnMid(){ // TODO: Add your command handler code here CDC*pDC=GetDC();//得到绘图类指针 RedrawWindow();//重绘窗口 int x,y,x0=200,y0=200,r=100;//圆的圆心为(x0,y0),半径为r float d;x=0;y=r;d=1.25-r; pDC->SetPixel(x+x0,y+y0,RGB(255,0,0));pDC->SetPixel(y+x0,x+y0,RGB(255,0,0));pDC->SetPixel(y+x0,-x+y0,RGB(255,0,0));pDC->SetPixel(x+x0,-y+y0,RGB(255,0,0));pDC->SetPixel(-x+x0,-y+y0,RGB(255,0,0));pDC->SetPixel(-y+x0,-x+y0,RGB(255,0,0));pDC->SetPixel(-y+x0,x+y0,RGB(255,0,0));pDC->SetPixel(-x+x0,y+y0,RGB(255,0,0));while(x<=y){ if(d<0) { d=d+2*x+3; x++; } else { d=d+2*(x-y)+5; x++; y--;} pDC->SetPixel(x+x0,y+y0,RGB(255,0,0)); pDC->SetPixel(y+x0,x+y0,RGB(255,0,0)); pDC->SetPixel(y+x0,-x+y0,RGB(255,0,0)); pDC->SetPixel(x+x0,-y+y0,RGB(255,0,0)); pDC->SetPixel(-x+x0,-y+y0,RGB(255,0,0)); pDC->SetPixel(-y+x0,-x+y0,RGB(255,0,0)); pDC->SetPixel(-y+x0,x+y0,RGB(255,0,0)); pDC->SetPixel(-x+x0,y+y0,RGB(255,0,0));} } 由以上代码绘出的图形如下: (2)利用Bresenham算法生成圆(算法原理见教材)。void CDraw_CirView::OnBre(){ // TODO: Add your command handler code here CDC*pDC=GetDC();//得到绘图类指针 //RedrawWindow();//重绘窗口 int x,y,x0=200,y0=200,r=50;//圆的圆心为(x0,y0),半径为r int delta,delta1,delta2,direction;x=0;y=r;delta=2*(1-r);while(y>=0){ pDC->SetPixel(x+x0,y+y0,RGB(0,0,255)); pDC->SetPixel(x+x0,-y+y0,RGB(0,0,255)); pDC->SetPixel(-x+x0,y+y0,RGB(0,0,255)); pDC->SetPixel(-x+x0,-y+y0,RGB(0,0,255)); if(delta<0) { delta1=2*(delta+y)-1; if(delta<=0)direction=1; else direction=2; } else if(delta>0) { delta2=2*(delta-x)-1; if(delta2<=0)direction=2; else direction=3; } else direction=2; switch(direction) { case 1:x++; delta+=2*x+1; break; case 2:x++;y--; delta+=2*(x-y+1); break; case 3:y--; delta+=(-2*y+1); break; } } } 由以上代码绘出的图形如下: (3)以上是本次实验的基本部分,利用中点画圆和Bresenham画圆算法实现的基本图形的绘制。能不能利用该算法,完成一些复杂图形的生成,比如利用基本的画圆算法绘制一个奥运五环。甚至根据画圆算法,实现二次曲线的生成,如椭圆的生成等等。请同学们认真考虑,完成这部分的内容,上机调试。 四、思考 1.如何实现圆心为任意位置的圆的绘制; 2.两种画圆算法的比较。 计算题图形学课程学习体会 计算机图形学是研究用计算机生成、处理和显示图形的一门学科。他的重要性体现在人们越来越强烈的需要和谐的人机交互环境,UI已经成为软件的重要组成部分,以图形的方式表示抽象的概念和数据已经成为信息领域的发张趋势。这门课我们通过自学和同学间互相上课,了解和掌握了计算机图形学的概念、方法和基本的算法。 学习的过程中,感触比较深的是,常常被那些算法所困扰,算法很难理解,解释的枯燥而且难学。原因首先是计算机图形学这门学科本身特点就是综合性很强,涉及的内容和应用广泛,学科交叉复杂。综合了计算机科学、数学、物理学等其他相关学科的知识。而且学科发展日新月异,新的应用领域不断拓展,相关学科相互渗透。其次是与计算机图形学课程中的算法特点有关。很多的算法是为了追求高效率,精益求精,构思独特、实现精巧,算法本身就很难看懂和理解。第三方面就是这门课程是一门理论性和实践性兼顾的综合性课程,实践性很强,不实践就显得空洞,枯燥乏味。 这门课学习的目的是让我们掌握计算机图形学的相关概念、原理和知识,算法的难学难理解,是我们学习的主要障碍。课程实践中,教员让我们自学,互相授课,增强时间体会。在自学和自作可见互相授课过程中,要求要注重基础,强调基本 这些动画,对增强原理、算法的理解性具有很大的作用。 以上是本人在计算机图形课学习过程中的体会,字数不多,确是心得,不足之处还请曹老师指正。第二篇:《计算机图形学》实验报告
第三篇:计算机图形学学习心得
第四篇:计算机图形学实验
第五篇:计算机图形学学习体会