范文网 论文资料 图形学实验与课程设计(精选)

图形学实验与课程设计(精选)

图形学实验与课程设计第一篇:图形学实验与课程设计计算机图形学课程设计 图形绘制变换分解计算机图形学 实验报告课程名称 : 计算机图形学 实验名称 : 图形绘制与变换 学 院 : 电子信息工程学院 专 业 : 计算机科学与技术 班 级 :。

图形学实验与课程设计

第一篇:图形学实验与课程设计

计算机图形学课程设计 图形绘制变换分解

计算机图形学 实验报告

课程名称 : 计算机图形学 实验名称 : 图形绘制与变换 学 院 : 电子信息工程学院 专 业 : 计算机科学与技术 班 级 : 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++提供的

3 高度可视化的应用程序开发工具和 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)中心点算法画圆

在一个方向上取单位间隔,在另一个方向的取值由两种可能取值的中点离圆的远近而定。实际处理中,用决策变量的符号来确定象素点的选择,因此算法效率较高。生成圆弧的中点算

5 法和上面讲到的生成直线段的中点算法类似。

考虑第一象限内x[0,R/2]的八分之一圆弧段。经过计算,得出判别式的递推公式为:

di1di2xi3di2(xiyi)5d0d0

(xi, M SE yi,r) E 这两个递推公式的初值条件为:

(x0,y0,r)(0,R)d05/4R

编写成员函数如下:

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);

6 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*()的操作是单位矩阵,也就是对物体没有影响。

7 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;

10 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;}}}

12 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 )

14 { 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移动后的曲线

15 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]);

16 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()

17 { 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);

21 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)实现多面体的上下左右平移

22 (2)实现多面体的绕轴旋转:

(3)实现多面体的放大缩小:

23

(4)实现多面体及背景的颜色设置:

(5)三维图形变换整体图形

24

五、实验心得体会

在本次课程设计过程中,基本掌握了计算机图形学关于图形绘制变换的基础知识,DDA法画直线和中心点法画圆及椭圆的方法,还对图形的变换及需要用到的一系列的函数有了相应的理解,也了解的很多有关于图形学中三维图形的变换的知识。不过都只是皮毛而已,从中锻炼了自己的动手做实验的能力,但同时也让自己看清了自己的水平,以便在以后的生活里多加强有关这方面的学习,从而提升自己在图形学方面的知识水平。

在本次课程设计中,设计方案存在着很多的死板化的实现方法,也是很不人性化的一点,只提供了画一种曲线的方法,且画出的曲线只能移动,此为本次设计方案的不足之一;然后就是能实现曲面和多边形的绘制,却没有对应的实现绘制好图形后直接对其进行平移、选择等变换,此为设计方案不足之二。再者就是三维图形只能实现变换不能实现绘制,此为设计方案不足之三。鉴于个人能力真的有限,所以只能设计出此种级别的效果了。因为实验重要的只是思想过程,效果的不美观只能是因为学习的知识还远远不够,所以不能设计出完美的全面的图形绘制变换程序。

经过此次设计,使我学到了很多东西,在没有开始做程序之前,没有任何思路,不知道该从哪里入手,可能是因为自己平时不认真听课的缘故。后来经过上网查询资料,翻阅参考书,在别人做的程序的启发下,才有了做此程序设计的眉目。在设计过程中遇到了很多的问题,在这里需要感谢王征风老师的帮助和指导,以及同学的帮助,最后一个个问题都被解决了,写出了完整的程序设计。最后也发现,其实只要努力,写出一个设计不是很困难,重要的是自己在写程序的过程中,要会学习,会查阅资料。这次的课程设计让我学习到了很多,以后我会努力提高自己在图形学方面的知识水平。

25

第二篇:《图形创意设计与表现》的课程设计

艺术学院 陈金花

摘要: 《图形创意设计与表现》通过大量的图形训练有效的解决平面设计中的视觉创意问题,培养学生形象思维的能力,课程设计为图形创意概述、图形创意思维方法、图形创意设计方法、图形创意的表现形式、图形创意程序、图形创意应用六大模块。

关键词:图形创意设计;图形创意表现;课程设计

《图形创意设计与表现》是高职装潢艺术设计专业职业能力课中的职业通用能力课程,为必修课。旨在通过大量的图形训练有效的解决平面设计中的视觉创意问题,培养学生形象思维的能力。本课程不仅训练学生的创造性思维,它的直接成果是为艺术设计打开一个开放式的思维过程。上课过程中重在培养学生学会从新的角度去观察、认识、理解事物并能准确运用图形创意的方法来传达特定的信息。通过本课程的学习和训练,使大家掌握用什么手段让平时很普通的很常见的图形变的更有内涵,能传达出更深层次的意义。要求我们以创造型的思维模式,培养审美的现代感和设计感,为我们的专业设计打好基础。开设本课程的主要目的是:培养学生创作图形形象的能力,包括构思和表现两方面的能力,建立一种全新的视觉想象与呈现的手段;更重要的是对学生进行创造性的思维的挖掘与培养,如何在面对问题时通过恰当的思维过程多方位的挖掘解决问题的新方法。

应该说《图形创意设计与表现》作为一门设计基础课程是有其重要的意义的,它与其他课程共同建起学生较为完整的基础知识和能力。比如构成意在培养学生对形态的概括和演绎能力以及立体感觉和技术表达技巧,而现代的图形创意设计与表现课的重点则是培养学生创造视觉语言形象的思维和表现能力。

根据高职装潢艺术设计专业的人才培养模式,本课程的培养目标设定为以下几点:

1.能力目标:要求学生掌握图形创意的思维方式、图形创意的构成形式并能够按照特定的主题设计出图形创意作品。

2.知识目标:要求学生了解图形创意的思维模式和方法以及图形创意的程序和步骤。

3.素质目标:让学生掌握用图形创意的方法解决设计构思,培养学生良好的专业素质及对作品认真钻研的精神以及学生团队合作和协调沟通能力。

《图形创意设计与表现》在艺术设计的教学过程中处于一种承前启后的过渡位置,它引导学生将前期已经具备的表现能力转向后期的专业设计中,而这个过渡就是通过创意思维来实现的。所以在课程内容的设置上,本课程着眼于训练学生的创意思维,运用大量的练习提高他们的形象思维能力、创造形象的能力及审美能力。为了让学生能在课堂上掌握课程内容,提高职业能力,根据学情,以实训为切入点将课程设计为图形创意概述、图形创意思维方法、图形创意的构成形式、图形创意的表现形式、图形创意程序、图形创意应用六大模块。

一、图形创意概述模块,通过了解图形的起源和图形在人类历史发展进程中的变迁及其作用,对存在于言语期和文字期之间的图形期的先祖们在劳动和生活活动中的信息交流方式与媒介有一个初步的认识,理解图形与象形文字的密切联系及图形设计的意义。通过基本元素的联想和想象练习以及概念联想的图形化表达来进入图形创意的学习。

二、图形创意思维方法模块,掌握和理清创意思维这个复杂过程中的一般规律,从各种联想中去发现和启迪创造思维,寻找更深远、更有意义的新概念,为创造图形进行感性和理性的探索,这对于开阔设计思路有极大的帮助。创意是图形设计的核心,将使图形具有让人惊叹而难以忘怀的力量,设计必须以创意为先导而进行。设计必须以创意为动力而获得发展,因为创造性思维必然使我们能开拓出前进的道路。

联想是图形创意中实现创造性思维的最基本又最普遍的思维方式。联想是由一事物想到与之相关的另一事物的思维过程,通过这一思维过程实现事物之间在人的意识中的联系。往往两种事物之间的任意关联性都会成为产生联想的依据。比如笔与纸、墨与砚等;春天与花朵、冬天与严寒等;毒品与死亡、饮酒与车祸等。

在教学过程中,会给同学们介绍几种具体的联想方式,如相似联想、相关联想、相反联想、因果联想、意识流联想等。通过发散性思维训练要求同学们建立自己的思维树,并学会从文字转化为图形。 在具体的图形创意设计过程中,还要求大家具有对图形形象进行想象再创造的能力,因为在现在的生活中,普通的写实主义已不能满足人们视觉的需要,在教学过程中围绕一个形象元素,让学生进行多角度的想像、变形,赋予图形新的视觉效果和艺术效果。

三、图形创意的构成形式模块,在实际的设计中,图形创意的构成形式是多样的,要想在众多的作品中收到更多的关注,就要掌握适合的图形创意的构成形式,将巧妙的构思融入到作品中才真正掌握了如何让图形能够准确传达特定信息。在教学中过程中主要介绍以下几种:

1、异影图形

在图形创意中以影子为创意的着眼点,根据主题内容,利用物影相异的特点,对图形进行变形再创造,使其具有内涵和寓意。利用影子进行的图形创意可以将事物不同时间下的状态、事情的因果关系、事物的正反两面、现象与本质等不同元素巧妙地组合起来。异影图形常用来反映事物内部的矛盾关系;当实形代表现象时,异影则反映着本质;实形代表现在,异影则反映过去或将来;实形代表现实,异影则代表幻觉,等等。

对影子的改变方式多种多样,可以用置换的方法,以形态上具有一定相似性的物体影子替换掉原来的影子;也可以赋予影子新的生命力,改变通常形影相随的现象,甚至影子反作用于原形。需要注意的是,利用影子的图形表现要重视形与影在造型上、寓意上的逻辑性,不能生搬硬套。在进行异影图形的创作时,要注意改变后的影子与原物之间相对关系的自然过渡。

2、同构图形

植物的嫁接可以产生新的品种,以成为科研创新的方式,在图形设计上也可以像科学实验一样,将表面上毫不相关但具有内在联系的不同物象,向植物嫁接一样构合为一体,产生具有创造意义的新形象,这就是同构图形。在教学过程中 ,可以给同学们介绍几种主要的图形同构的形式,如:异形同构法,异质同构法,置换同构法等。

3、正负图形

所谓正形是指画面中被认为是图的部分,它从背景中分离出来,具有积极的意义。与此相对应的是负形,即图之外的背景部分。人们十分注重实空间的利用,实空间的外形,而很多人往往忽略了对虚空间的利用和把握。正负形的训练目的正是强调虚实的同等重要性。在现代图形设计中,负形已不只是作为衬托正形的底色和背景,而可以通过种种联想,在保留正形完整的基础上,把它也设计成一个完善的形态。正形和负形相互借用,相互依存,这样不仅可以体现一定的精神内涵,同时,在视觉上可以形成一种独特的错视效果,从而使图形能够出色地完成吸引受众、传递信息的使命。

4、空间图形

无理图形,改变真实事物的客观存在,将不现实的变为现实,将不可能的变为可能,将不相关的变为相关,图形由此产生新意义。

矛盾空间,将二维与三维幻想与真实混合交错在一起。

四、图形创意的程序模块,让学生能够根据主题的需要,收集有关素材,并从中选取最适合于表达主题思想的素材把所选的材料加以改造和组织,将它们组合成为有机的结构,再通过适当的方式将构思的成果形象的表现出来。

五、图形创意的表现形式模块,让学生学会运用合适的表现形式将创意图形展示出来,在教学过程中,主要介绍图形的几种表现形式,如夸张、拟人、简化、添加、平面装饰、卡通化等具体的表现形式。

六、图形创意的应用模块,认识和理解图形创意在设计中的应用优势,其中包括广告设计、包装设计、标志设计,甚至包括空间设计都可以运用图形创意的思路,在材质、形态、结构、表现语言等方面寻找创新的思路。

在具体的教学过程中,教师应该根据学生的实际学习情况做出适当的调整。

参考文献

1. 周承君 罗瑞兰 ,图形创意,[M],北京大学出版社,2010.8 2. 林家阳,图形创意,[M],黑龙江美术出版社,1999 3. 卢少夫,图形创意设计,[M],上海人民美术出版社,2004 4. 陈珊妍,图形创意设计,[M],南京大学出版社,2008

第三篇:计算机图形学实验

实验三 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;

程序运行效果图

2

实验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() {

5 // 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. 两种画圆算法的比较。

第四篇:计算机图形学实验报告

实 验 报 告

一、 实验目的

1、掌握有序边表算法填充多边形区域;

2、理解多边形填充算法的意义;

3、增强C语言编程能力。

二、 算法原理介绍

根据多边形内部点的连续性知:一条扫描线与多边形的交点中,入点和出点之间所有点都是多边形的内部点。所以,对所有的扫描线填充入点到出点之间所有的点就可填充多边形。

判断扫描线上的点是否在多边形之内,对于一条扫描线,多边形的扫描转换过程可以分为四个步骤:

(1)求交:计算扫描线与多边形各边的交点; (2)排序:把所有交点按x值递增顺序排序;

(3)配对:第一个与第二个,第三个与第四个等等;每对交点代表扫描线与多边 形的一个相交区间; (4)着色:把相交区间内的象素置成多边形颜色,把相交区间外的象素置成背景色。

p1,p3,p4,p5属于局部极值点,要把他们两次存入交点表中。 如扫描线y=7上的交点中,有交点(2,7,13),按常规方法填充不正确,而要把顶点(7,7)两次存入交点表中(2,7,7,13)。p2,p6为非极值点,则不用如上处理。

为了提高效率,在处理一条扫描线时,仅对与它相交的多边形的边进行求交运算。把与当前扫描线相交的边称为活性边,并把它们按与扫描线交点x坐标递增的顺序存放在一个链表中,称此链表为活性边表(AET)。

对每一条扫描线都建立一个与它相交的多边形的活性边表(AET)。每个AET的一个节点代表一条活性边,它包含三项内容

1. x -当前扫描线与这条边交点的x坐标;

2. Δx -该边与当前扫描线交点到下一条扫描线交点的x增量; 3. ymax -该边最高顶点相交的扫描线号。

每条扫描线的活性边表中的活性边节点按照各活性边与扫描线交点的x值递增排序连接在一起。

当扫描线y移动到下一条扫描线y = y+1时,活性边表需要更新,即删去不与新扫

描线相交的多边形边,同时增加与新扫描线相交的多边形边,并根据增量法重新计算扫描线与各边的交点x。

当多边形新边表ET构成后,按下列步骤进行:

① 对每一条扫描线i,初始化ET表的表头指针ET[i]; ② 将ymax = i的边放入ET[i]中;

③ 使y =多边形最低的扫描线号; ④ 初始化活性边表AET为空; ⑤ 循环,直到AET和ET为空。

 将新边表ET中对应y值的新边节点插入到AET表。  遍历AET表,将两两配对的交点之间填充给定颜色值。

 遍历AET表,将 ymax= y的边节点从AET表中删除,并将ymax> y的各边节点的x值递增Δx;并重新排序。  y增加1。

三、 程序源代码

#include "graphics.h" #define WINDOW_HEIGHT 480 #define NULL 0 #include "alloc.h" #include "stdio.h" #include "dos.h" #include "conio.h" typedef struct tEdge /*typedef是将结构定义成数据类型*/ { int ymax; /* 边所交的最高扫描线号 */ float x; /*当前扫描线与边的交点的x值 */ float dx; /*从当前扫描线到下一条扫描线之间的x增量*/ struct tEdge *next; }Edge;

typedef struct point{int x,y;}POINT; /*将结点插入边表的主体函数*/

void InsertEdge(Edge *list,Edge *edge)/*活性边edge插入活性边表list中*/ { Edge *p,*q=list; p=q->next; /*记住q原来所指之结点*/ while(p!=NULL) /*按x值非递减顺序增加边表*/ {

if(edge->xx) /*要插入的边的x较大不应该在当前插入*/

p=NULL;

else /*要插入的边的x较小应该在当前插入*/

{q=p;

p=p->next;

} } edge->next=q->next; /*使欲插入之结点edge指向q原来所指之结点*/ q->next=edge; /*使q指向插入之结点*/ }

int yNext(int k,int cnt,POINT *pts) /*对于多边形中的某个顶点序号k(0,1...6),返回下一顶点的纵坐标,如果这2个顶点所在边是 水平的,则顺延,即返回第(k+2)个顶点的纵坐标),cnt是顶点个数+1,pts指向多边形顶点结构体的指针*/

{ int j; if((k+1)>(cnt-1))/*当前顶点为最后一个顶点,则下一个顶点为第0个顶点 */

j=0; else

j=k+1; /*当前顶点不是最后一个顶点,下一个顶点为数组下标加一*/ while(pts[k].y==pts[j].y) /*扫描线扫过平行顶点,需分情况找到当前顶点下下个顶点*/ if((j+1)>(cnt-1))

j=0;

else

j++; return(pts[j].y); /*返回下一个顶点的y值 */ }

/* 计算增量,修改AET*/ /*生成边表结点,并插入到边表中的主体函数*/ void MakeEdgeRec(POINT lower,POINT upper,int yComp,Edge *edge,Edge *edges[]) /*把边结点edge,放到lower.y扫描线所在的边结点指针数组edges[]中 */ {edge->dx=(float)(upper.x-lower.x)/(upper.y-lower.y); edge->x=lower.x; if(upper.yymax=upper.y-1; /*缩短上层顶点*/ /*奇点,应该把这点当作两个点而分开,所以把y的最大值减一,向下移动*/ else edge->ymax=upper.y; /*不是奇点,不需改变y值 */ insertEdge(edges[lower.y],edge); /*插入一个边缘扫描线,插入到列表 */ }

/*创建边表的主体函数*/ void BuildEdgeList(int cnt,POINT *pts,Edge *edges[]) /*建立新边表,cnt:多边形顶点个数+1,edges[]:指向活性边结点的指针数组*/ { Edge *edge; POINT v1,v2; int i,yPrev=pts[cnt-2].y; /*当前顶点的前一个顶点的y值,在当前顶点不是奇点时使用该参数*/ v1.x=pts[cnt-1].x; v1.y=pts[cnt-1].y; for(i=0;i

edge=(Edge *)malloc(sizeof(Edge));

edge=(Edge*)malloc(sizeof(Edge)); if(v1.y

yNext*/ MakeEdgeRec(v1,v2,yNext(i,cnt,pts),edge,edges); /*确定v1,v2边较高端点的开闭*/

else

MakeEdgeRec(v2,v1,yPrev,edge,edges); /*当前顶点

是奇点*/ } yPrev=v1.y; v1=v2; } }

/*建立活性边表的主体函数:建立第scan条扫描线的活性边表*/ void BuildActiveList(int scan,Edge *active,Edge *edges[]) /*建立扫描线scan的活性边表,把活性边结点放入扫描线scan的结点指针数组 edges[scan]中*/ { Edge *p,*q; p=edges[scan]->next; /*查找当前扫描线对应的y桶*/ while(p) /*y桶不空*/

{q=p->next; /*找到最后一个边结点,插入*/

InsertEdge(active,p); /*把更新后的边表重新插入边表中保存*/

p=q;

} }

/*填充一对交点的主体函数*/ void FillScan(int scan,Edge *active,int color) /*填充扫描线:填充扫描线上,且在下一结点到再下一结点之间的点*/ { Edge *p1,*p2; int i; p1=active->next; while(p1) {

p2=p1->next;

for(i=p1->x;ix;i++)

putpixel((int)i,scan,color); /*画出图形内部的点*/ p1=p2->next; /*活性表的下一条边表 */ } }

void DeleteAfter(Edge *q) /*删除链表中结点,删除边结点q的后续结点p*/ { Edge *p=q->next; q->next=p->next; /*删除结点*/ free(p); } /* 删除 y=ymax 的边 */

/*填充完后,更新活动边表的主体函数*/ void UpdateActiveList(int scan,Edge *active) /*删除扫描线scan完成交点计算的活性边,同时更新交点x域*/ { Edge *q=active,*p=active->next; while(p) if(scan>=p->ymax) /*扫描线超过边的最大y值,此条边的节点应该删掉*/ { p=p->next; deleteAfter(q); } else /*扫描线未超过边的最大y值,相应的x值增加*/ { p->x=p->x+p->dx; q=p;p=p->next; } }

/*对活性边表结点重新排序的主体函数*/ void ResortActiveList(Edge *active) /*活性边表active中的结点按x域从小到大重新排序*/ { Edge *q,*p=active->next; active->next=NULL; while(p) {q=p->next; InsertEdge(active,p); /*把更新后的边表重新插入边表中保存 */ p=q; } }

/*多边形填充的主体程序*/ void ScanFill(int cnt,POINT *pts,int color) /*填充函数,输入:多边形顶点个数+1=cnt, 指向多边形顶点的指针数组pts*/

{ Edge *edges[WINDOW_HEIGHT],*active; int i,scan,scanmax=0,scanmin=WINDOW_HEIGHT; for(i=0;i

{if(scanmax

if(scanmin>pts[i].y)scanmin=pts[i].y;

} for(scan=scanmin;scan<=scanmax;scan++) /*初始化每条扫面线的边链表*/ {edges[scan]=(Edge *)malloc(sizeof(Edge)); /*建

edges[scan]->next=NULL;

} BuildEdgeList(cnt,pts,edges); /*建立有序边表*/ active=(Edge *)malloc(sizeof(Edge)); “桶”*/ active->next=NULL; for(scan=scanmin;scan<=scanmax;scan++) /*扫描每条扫描线,求活性表*/ {

BuildActiveList(scan,active,edges); /*建立活性边表*/

if(active->next) /*活性边表不为空*/

{ FillScan(scan,active,color); /*填充当前扫描线*/ UpdateActiveList(scan,active); /*更新活化边表*/ ResortActiveList(active); /*重排活化边表*/

} } }

/*开始菜单*/ void main() { POINT pts[7]; /*保存数组*/ int gdrive=DETECT,gmode; pts[0].x=100;pts[0].y=40; /*多边形顶点x、y坐标*/ pts[1].x=220;pts[1].y=140; pts[2].x=280;pts[2].y=80; pts[3].x=350;pts[3].y=300; pts[4].x=200;pts[4].y=380; pts[5].x=50;pts[5].y=280; pts[6].x=100;pts[6].y=40; /*合并桶中的新边,按次序插入到 AET 中*/ initgraph(&gdrive,&gmode,"C:TC3.0BGI"); /*设置graphic模式*/ ScanFill(7,pts,2); getch(); }

四、 实验结果

图1 用有序边表算法生成的多边形

五、 总结与体会

实验步骤

1) 分析多边形区域扫描线填充算法的原理,确定算法流程

① 初始化:构造边表,AET表置空

② 将第一个不空的ET表中的边插入AET表

③ 由AET表取出交点进行配对(奇偶)获得填充区间,依次对这些填充区间着色

④ y=yi+1时,根据x=xi+1/k修改AET表所有结点中交点的x坐标。同时如果相 应的ET表不空,则将其中的结点插入AET表,形成新的AET表 ⑤ AET表不空,则转(3),否则结束。 2) 编程实现

① 首先确定多边形顶点和ET/AET表中结点的结构

② 编写链表相关操作(如链表结点插入、删除和排序等)

③ 根据1)中的算法结合上述已有的链表操作函数实现多边形区域扫描线填充的主体功能

④ 编写主函数,测试该算法 通过运用C语言环境下的图像显示设置,本次实验我学会了多边形区域扫描线填充的有序边表算法,设计相关的数据结构(如链表结构、结点结构等),并将实现的算法应用于任意多边形的填充,为深一步的学习做好了铺垫。

六、 参考文献

[1]张家广 等编著.计算机图形学(第3版).北京:清华大学出版社,1998年9月.

[2]陈传波,陆枫主编,《计算机图形学基础》,电子工业出版社,

2002年3月.

第五篇:计算机图形学 实验六-西南交大

学号:姓名:班级:

计算机图形学

实验报告

2016年6月日

实验名称:三维交互式图形程序设计

一、实验目的:

1)掌握真实感图形生成的基本原理,如消隐、光照、材质等知识; 2)学习使用OpenGL、GLUT等生成基本图形,如球体、正方体、茶壶等;

3)学习使用OpenGL生成各种光源:点光源、平行光、聚光灯等; 4)学习使用OpenGL设置绘制对象的颜色、材质;

5)进一步熟悉OpenGL图形变换技术:几何变换、视图变换、观察变换等:

(1)对模型实现各种几何变换(测试代码保留在程序中),包括对 glLoadMatrix 、 glMultMatrix 、 glTranslate 、 glRotate 、 glScale 等的使用;

(2)视口变换,测试不同大小的视口 glViewport ;

(3)投影变换,要对对平行投影与透视投影分别测试,使用不同的观察体参数,观察效果

二、实验任务:

1)使用MFC AppWizard 建立一个SDI 程序,根据参考资料2 和3 中的步骤设置OpenGL 图形绘制环境。增加绘制如下表图形(选择其中任意一个,注意模型坐标系的选择和顶点坐标的计算)、球体或茶壶等(使用glut 函数)。环境中创建点光源、平行光、聚光灯(可利用对话框输入参数创建)、设置所绘制对象的材质,呈现出塑料、金属等材质特性。对光源的位置、方向、类型进行控制,改变材质参数,观察效果(测试代码保留在程序中);

三.实验过程: 1.观察参数的设置

glViewport(0.0, 0.0, width, height) //视口大小设置 gluLookAt(0,0,10,0,0,0,0,1,0); //观察点设置,参数分别为观察点位置,向哪点(何处)观察,上方向的定义 2.投影变换

glOrtho(-15.0*aspect, 15.0*aspect,-15.0,15.0,1,100);//平行投影,参数是投影面大小和投影的物体距离范围

gluPerspective(45,aspect, 1, 100.0); //透视投影,参数为视角,长宽比,投影距离范围 3.几何变换

glLoadMatrixf(a); //设置当前矩阵为a glTranslatef(2,0,0); //当前矩阵*偏移矩阵 glRotatef(45, 0.0, 0.0, 0.0); //旋转

glScalef(m_scalX,m_scalY,m_scalZ);//当前矩阵*比例矩阵 4.光源参数的设置

glLightfv(GL_LIGHT0, Type, vlight); //light为float数组 glLightf(GL_LIGHT0, Type, light); //light为float Type=GL_LIGHT0, GL_AMBIENT //环境光 Type=GL_LIGHT0, GL_DIFFUSE

//漫反射 Type=GL_LIGHT0, GL_SPECULAR //镜面光 Type=GL_POSITION

//光源位置 Type=GL_CONSTANT_ATTENUATION //常数衰减因 Type=GL_LINEAR_ATTENUATION //线性衰减因子 Type=GL_QUADRATIC_ATTENUATION //二次衰减因子 Type=GL_SPOT_DIRECTION

//聚光方向矢量 Type=GL_SPOT_EXPONENT

//聚光指数 Type=GL_SPOT_CUTOFF

//聚光截止角 光源类型控制

平行光源::设置AMBIENT,DIFFUSE ,SPECULAR,GL_POSITION4个参数。其中GL_POSITION第4个参数为0,表示距离无限远

点光源:平行光源基础上添加常数衰减,因线性衰减因子,二次衰减因,其中GL_POSITION第4个参数为1 表示光源位置为确切位置,

聚光灯光源 :在点光源基础上添加聚光方向矢量,聚光截止角,聚光指数

本实验使用了3个光源,分别作为平行光源,点光源和聚光灯光源,通过不同菜单选择在输入参数的同时启用不同的光源,以达到光源控制的效果

四.实验结果

原图:

材质选择:

光源基本参数设置

设置聚光灯光源(位置,方向,聚光指数,聚光截止角,衰减因子)

聚光衰减属性(聚光灯)

五.实验体会

通过此次实验,基本掌握了真实图形生成的基本原理,对于3D图新的材质变换,光源变换等有了更深层次的理解。初步学习并掌握了几何变换、视图变换、观察变换等。对于对话框、组建的设置更是理解的透彻。深入掌握了课堂上的些许知识。但对于之后的图形学设计,还是有很多的不足之处。所以,需要继续努力,掌握更多的图形设计学习。

上一篇
下一篇
返回顶部