E N D
计算机图形学 制作人:李彦
目录介绍 1、课程简介 2、实验内容
返回主 目录? 课程概述 本书介绍了计算机图形学的基础知识及应用实例,主要内容包括:计算机图形软、硬件系统基本知识,基本图形生成与多边形填充,字符生成,二维裁剪,二维变换,三维变换,典型曲线曲面,消隐,真实感图形表现,图形学基本应用等。针对主要知识点,每章提供若干图形界面的应用实例的实现过程与执行结果,帮助读者分析计算机图形学原理,并通过大量生动的图片与实例,将枯燥的理论转变为可视化的实践操作,书中所有程序均在Visual C¨6.0环境中验证通过。同时,还特别提供了两个阶段性的应用程序:二维图形综合设计实例与真实感综合设计实例。本书是学习计算机图形学的入门书籍,既能使读者全面了解计算机图形学的基础理论,又能通过大量应用实例提高其编程能力。本书适合作为普通高校计算机、信息处理、艺术设计等专业的计算机图形学课程及其实验教材或教师参考用书,也可作为工程技术人员或图形学爱好者的自学用书,还可作为相关课程设计的参考教材。 • 课程简介
返回主 目录? 实验内容 实验一:基本图形生成算法 实验二:多边形的填充 实验三:二维图形剪裁和变换 实验四:平面图形综合设计
实验一 实验一:基本图形生成算法 实验内容:1、熟悉VC ++6.0和常用的绘图函数 2、直线、圆和椭圆的生成 实验类型:设计型 实验类别:学科基础 每组人数: 1人 实验目的: 1、熟悉VC++ 6.0环境,并掌握常用的绘图函数 2、熟悉并掌握直线、圆和椭圆等基本图形的生成算法和实现方法
实验步骤 已知待扫描转换的直线为(x0,y0),,又,则设k=1/m=(即k∈(0,1])。直线方程为,即。 以一个像素为单位分割区间[y0,y1],由x0<x1,故y0<y1,得到[y0,y1]上的一个划分:,,…. ,其中=+1,得到点列,由公式 故从直接得到。可能为浮点数,要对它取整,实际得到像素集。初值为:()=(x0,y0)。
实验步骤 void CMy1View::ddaline(CDC *pDC, int x0, int y0, int x1, int y1, COLORREF color) { int length,i; float x,y,dx,dy; length=abs(x1-x0); if (abs(y1-y0)>length) length=abs(y1-y0); dx=(x1-x0)/length; dy=(y1-y0)/length; x=x0+0.5;y=y0+0.5; for (i=1;i<=length;i++) { pDC->SetPixel((int)x,(int)y,color); x=x+dx;y=y+dy; } } 编写自定义的成员函数ddaline()程序:
void CMy1View::OnDraw(CDC* pDC) { CMy1Doc* pDoc = GetDocument(); ASSERT_VALID(pDoc); // TODO: add draw code for native data here ddaline(pDC,100,100,400,100,RGB(255,0,0)); ddaline(pDC,400,100,400,400,RGB(0,255,0)); ddaline(pDC,400,400,100,400,RGB(0,0,255)); ddaline(pDC,100,400,100,100,RGB(255,255,0)); ddaline(pDC,100,100,400,400,RGB(255,0,255)); ddaline(pDC,100,400,400,100,RGB(0,255,255)); } 实验步骤 编写OnDraw()函数
实验二 实验二:多边形的填充 实验内容:1、多边形的扫描转换 2、多边形的区域填充 实验类型:设计型 实验类别:学科基础 每组人数: 1人 实验目的: 1、熟悉区域的表示和类型,掌握并实现多边形的扫描转换方法。 2、熟悉并掌握多边形的区域填充方法。
实验内容 1.图元填充 利用多种图元填充的方法绘制一面五星红旗。 方法有: 扫描转换多边形的逐点判断法(编码算法),扫描线算法, 区域填充的扫描线算法。 2.扫描转换多边形 2.1把多边形的顶点表示转换为点阵表示,也就是从多边形的给定边界出发,求出位于其内部的各个象素,并给帧缓冲器内的各个对应元素设置相应的灰度和颜色,通常称这种转换为多边形的扫描转换。 几种方法:逐点判断法;扫描线算法;边缘填充法; 2.2逐点判断法 逐个判断绘图窗口内的像素。如何判断点在多边形的内外关系?有1)射线法:2)累计角度法3)编码法;这里用的是编码算法。://exam2.timber.com
int Edge_code(point node,point start,point end) {int w,v,s=0; point p; float x0,y0; if(start.x>node.x&&start.y>node.y) v=0; if(start.x<=node.x&&start.y>node.y) v=1; if(start.x<=node.x&&start.y<=node.y) v=2; if(start.x>node.x&&start.y<=node.y) v=3; if(end.x>node.x&&end.y>node.y) w=0; if(end.x<=node.x&&end.y>node.y) w=1; if(end.x<=node.x&&end.y<=node.y) w=2; if(end.x>node.x&&end.y<=node.y) w=3; s=w-v; if(s==2||s==-2) { x0=(end.x+start.x)/2; y0=(end.y+start.y)/2; p.x=x0;p.y=y0; s=Edge_code(node,start,p)+Edge_code(node,p,end); } if(s==3) s=-1; if(s==-3) s=1; return s; } point Getmax(point points[10]) { int i; float maxx,maxy; point p; maxx=points[0].x;maxy=points[0].y; for(i=1;i<10;i++) {if(points[i].x>maxx) maxx=points[i].x; if(points[i].y>maxy) maxy=points[i].y;} p.x=maxx;p.y=maxy; return p; } 实验步骤
point Getmin(point points[10]) {int i; float minx,miny; point p; minx=points[0].x;miny=points[0].y; for(i=1;i<10;i++) {if(points[i].x<minx) minx=points[i].x; if(points[i].y<miny) miny=points[i].y;} p.x=minx;p.y=miny; return p; } for(i=0;i<10;i++) {if(i%2==0) {points[i].x=x[i/2];points[i].y=y[i/2]; } else {points[i].x=a[i/2];points[i].y=b[i/2]; } } p1=Getmax(points);p2=Getmin(points); for(n=p2.y;n<p1.y;n++) for(m=p2.x;m<p1.x;m++) if(getpixel(m,n)!=YELLOW) {node.x=m;node.y=n; j=Edge_code(node,points[0],points[1]); for(i=1;i<9;i++) j+=Edge_code(node,points[i],points[i+1]); j+=Edge_code(node,points[9],points[0]); if(j==4||j==-4) putpixel(m,n,YELLOW);} 实验步骤
实验三 实验三:二维图形剪裁与变换 实验内容:1、点、线段和多边形的剪裁 2、二维基本几何变换的实现 3、二维复合变换的实现 实验类型:设计型 实验类别:学科基础 每组人数: 1人 实验目的: 1、掌握二维图形的各种裁剪算法,包括点、线段及多边形的裁剪 2、熟悉并掌握二维图形的基本几何变换算法,及其实现方法 。
实验内容 • 裁剪算法的实现思路 • 这个裁剪算法适用于任何凸多边形,它是从Sutherland-Hodgman算法推广来的。Sutherland-Hodgman算法着重于用竖直线裁剪,在这里首先把它推广到任意直线。 • 两点确定一条直线,在这里我们规定这两点有先后顺序,这就使直线具有了方向。在这个基础上,设直线方程为F(x,y)=0,当直线方向从左至右时,保存使F>=0的顶点,从右至左时,保存使F<=0的顶点。这样就把它推广到了任意直线。 • 对于任意凸多边形,我们把它看成是由逆时针方向的直线组成的。依次用它们来裁剪,最终得到的多边形就是所求图形。 • 注:同学们也可以直接用Sutherland-Hodgma算法实现,也可以用编码算法,或者NICHOLL-LEE-NICHOLL等算法实现对二维图形的裁剪。 能综合利用前面所学的知识进行二维图形综合设计与实现
实验步骤 • 在主程序的程序头部定义符号常量 • #define LEFT 1 • #define RIGHT 2 • #define BOTTOM 4 • #define TOP 8 • 定义成员变量和成员函数 • int WT; • int WB; • int WR; • int WL; • int C_S_Line(CDC* pDC,int x1,int y1,int x2,int y2); • void encode(int x,int y,int *code); • 在构造函数中为窗口边界变量赋初值: • WL=100;WR=400;WB=100;WT=300;
实验步骤 • int CMy1_1View::C_S_Line(CDC *pDC, int x1, int y1, int x2, int y2) • { • int code1,code2,code,x,y; • encode(x1,y1,&code1); //(x1,y1)处的编码 • encode(x2,y2,&code2); //(x2,y2)处的编码 • while (code1!=0||code2!=0) //当 code1 不等于 0 或 code2 不等于 0 • { • if ((code1&code2)!=0) return 0; //当 code1 与 code2 不等于 0,在同侧; • code=code1; • if (code1==0) code=code2; • if ((LEFT&code)!=0) //求交点 • { • x=WL; • y=y1+(y2-y1)*(WL-x1)/(x2-x1); • }else if ((RIGHT&code)!=0) • { x=WR; • y=y1+(y2-y1)*(WR-x1)/(x2-x1); • } • else if ((BOTTOM&code)!=0) • { y=WB; • x=x1+(x2-x1)*(WB-y1)/(y2-y1); • } • else if ((TOP&code)!=0) • { y=WT; • x=x1+(x2-x1)*(WT-y1)/(y2-y1); • } • if (code==code1) • { • x1=x;y1=y; • encode(x,y,&code1); • } • else • { • x2=x;y2=y; • encode(x,y,&code2); • } • }
实验步骤 • int CMy1_1View::C_S_Line(CDC *pDC, int x1, int y1, int x2, int y2) • { • int code1,code2,code,x,y; • encode(x1,y1,&code1); //(x1,y1)处的编码 • encode(x2,y2,&code2); //(x2,y2)处的编码 • while (code1!=0||code2!=0) //当 code1 不等于 0 或 code2 不等于 0 • { • if ((code1&code2)!=0) return 0; //当 code1 与 code2 不等于 0,在同侧; • code=code1; • if (code1==0) code=code2; • if ((LEFT&code)!=0) //求交点 • { • x=WL; • y=y1+(y2-y1)*(WL-x1)/(x2-x1); • }else if ((RIGHT&code)!=0) • { x=WR; • y=y1+(y2-y1)*(WR-x1)/(x2-x1); • } • else if ((BOTTOM&code)!=0) • { y=WB; • x=x1+(x2-x1)*(WB-y1)/(y2-y1); • } • else if ((TOP&code)!=0) • { y=WT; • x=x1+(x2-x1)*(WT-y1)/(y2-y1); • } • if (code==code1) • { • x1=x;y1=y; • encode(x,y,&code1); • } • else • { • x2=x;y2=y; • encode(x,y,&code2); • } • }
实验步骤 • //end while,表示 code1,code2 都为 0,其中的线段为可视部分 • pDC->MoveTo(x1+350,y1); • pDC->LineTo(x2+350,y2); • } • void CMy1_1View::encode(int x, int y, int *code) • { • int c=0; • if (x<WL) c=c|LEFT; • else if (x>WR) c=c|RIGHT; • if (y<WB) c=c|BOTTOM; • else if (y>WT) c=c|TOP; • *code=c; • } • 编写OnDraw()程序: • void CMy1_1View::OnDraw(CDC* pDC) • { • CMy1_1Doc* pDoc = GetDocument(); • ASSERT_VALID(pDoc); • // TODO: add draw code for native data here • //定义三条直线的坐标 • int x11,y11,x21,y21,x12,y12,x22,y22,x13,y13,x23,y23; • x11=50;y11=150;x21=450;y21=250; • x12=150;y12=150;x22=350;y22=240; • x13=50;y13=400;x23=500;y23=350; • //定义画笔 • CPen PenRed(PS_SOLID,1,RGB(255,0,0));//定义红色笔 • CPen PenBlue(PS_SOLID,1,RGB(0,0,255));//定义蓝色笔 • CPen Penwhite(PS_SOLID,1,RGB(255,255,255));//定义白色笔 • //先画出窗口,用蓝色
实验步骤 • pDC->SelectObject(&PenBlue); • pDC->Rectangle(WL,WB,WR,WT); • //先画出三条直线,用红线 • pDC->SelectObject(&PenRed); • pDC->MoveTo(x11,y11);pDC->LineTo(x21,y21); • pDC->MoveTo(x12,y12);pDC->LineTo(x22,y22); • pDC->MoveTo(x13,y13);pDC->LineTo(x23,y23); • //画出剪裁后的窗口,用蓝色 • pDC->SelectObject(&PenBlue); • pDC->Rectangle(WL+350,WB,WR+350,WT); • //用蓝线,画出裁剪三条线 • pDC->SelectObject(&PenBlue); • C_S_Line(pDC,x11,y11,x21,y21); • C_S_Line(pDC,x12,y12,x22,y22); • C_S_Line(pDC,x13,y13,x23,y23); • }
实验四 实验三:平面图形综合设计 实验内容:1、实现交互,完成鼠标绘图 2、平面曲线图案综合设计 实验类型:设计型 实验类别:学科基础 每组人数: 1人 实验目的: 1、了解并熟悉计算机图形的交互技术,并能实现简单的交互,如鼠标绘图 2、能综合利用前面所学的知识进行二维图形综合设计与实现
实验内容 • Bezier曲线是一种广泛应用于外形设计的参数曲线,它通过对一些特定点的控制来控制曲线的形状,我们称这些点为控制顶点。现在我们来给出Bezier曲线的数学表达式。 • 在空间给定个点,称下列参数曲线为次Bezier曲线: • 其中是Bernstein基函数,其表达式为: • ,接着我们讨论3次Bezier曲线,我们也采用将表达式改写为矩阵形式的方法,我们得到:
实验步骤 • #include<math.h> • double CMy4_1View::b03(double t) • { • return(pow(1-t,3)); • } • double CMy4_1View::b13(double t) • { • return(3*t*pow(1-t,2)); • } • double CMy4_1View::b23(double t) • { • return(3*(1-t)*t*t); • } • double CMy4_1View::b33(double t) • { • return(t*t*t); • }
实验步骤 • 编写OnDraw函数: • void CMy4_1View::OnDraw(CDC* pDC) • { • CMy4_1Doc* pDoc = GetDocument(); • ASSERT_VALID(pDoc); • // TODO: add draw code for native data here • int i; • int x0,y0,x1,y1,x2,y2,x3,y3,curx,cury; • double t,dt; • // 创建两个不同颜色的画笔 • CPen PenRed(PS_SOLID,1,RGB(255,0,0)); • CPen PenBlue(PS_SOLID,1,RGB(0,0,255)); • // 设置控制点,绘出特征多边形 • x0=220;y0=10;x1=410;y1=10;x2=225;y2=150;x3=410;y3=100; • pDC->SelectObject(PenBlue); //使用蓝色画笔 • pDC->MoveTo(x0,y0); • pDC->LineTo(x1,y1); • pDC->LineTo(x2,y2); • pDC->LineTo(x3,y3); • //绘制 Bezier 曲线 • pDC->MoveTo(x0,y0); • t=0; dt=0.01; //t 从 0 到 1,每步增加 0.01,取 100 个点 • pDC->SelectObject(PenRed); //使用红色画笔 • for (i=0;i<=100;i++) • { curx=(int)(b03(t)*x0+b13(t)*x1+b23(t)*x2+b33(t)*x3); • cury=(int)(b03(t)*y0+b13(t)*y1+b23(t)*y2+b33(t)*y3); • pDC->LineTo(curx,cury); • t=t+dt; • } • }