计算机图形学实验指导书.docx
《计算机图形学实验指导书.docx》由会员分享,可在线阅读,更多相关《计算机图形学实验指导书.docx(23页珍藏版)》请在冰豆网上搜索。
计算机图形学实验指导书
计算机图形学
实验指导书
安徽建筑工业学院
前言
计算机图形学是计算机类专业的一门主干必修专业课程,又是一门实践性很强的课程,它包括理论和实验两部份,计算机图形学实验是对理论的应用和理解。
计算机图形学实验要求学生能用《程序设计方法》、《计算方法》、《数据结构》课程的知识进行综合编程,同时强调编程技能。
本实验指导书的目的是根据实验项目的要求,对基本算法给出提示,并附某些算法的参考程序,让学生加深理解图形学的基本概念和算法,提高编程技能。
通过本课程的学习与上机实践,让学生不仅能掌握二、三维图形系统的原理与算法,并具有一定的二、三维图形应用系统开发能力。
为今后从事计算机辅助设计和制造、科学计算可视化、计算机图形处理等方面的工作打下良好的基础。
本实验指导书就是根据《计算机组图形学》课程教学大纲和实验教学大纲的基本要求而编写的。
本书内容包括用C语言绘制图形和简单动画、直线及圆弧的生成算法、Bezier曲线和样条曲线的生成算法、实现二维图形的几何变换、绘制三维图形、实现三维图形的几何变换、绘制Bezier曲面、进行多边形的裁剪及填充、编制动画程序、变形龙游戏的设计与实现等十个实验。
每个实验后面都附有实验报告。
目录
基础知识C程序绘图基础4
实验一直线的生成算法17
实验二Bezier曲线生成算法21
实验三编制动画程序25
基础知识C程序绘图基础
一、用C语言绘制图形的步骤
1、为了调用C语言提供的图形库函数,在程序的开头写上文件的包含命令;
#include
2、图形系统初始化及关闭图形方式
初始化是通过调用initgraph()函数来完成,它的调用格式为:
initgraph(*gdriver,*gmode,*path);
该函数的功能是通过从磁盘上装入一个图形驱动程序来初始化图形系统,并将显示器设置到指定图形方式下。
参数gdriver,gmode,path的含义参见教材的有关章节。
在运行图形程序结束后,又要回到文本方式,以进行其它工作,这时应关闭图形方式。
其格式为:
closegraph()。
3、图形显示器的工作方式
1)文本模式与字符坐标系
在未通过图形初始化之前的屏幕上,只能显示字符的方式称为文本模式。
C语言能在指定位置显示字符,该坐标系以屏幕的左上角为坐标原点,水平向为x轴,自左向右;垂直方向为y轴,自上向下,坐标原点为(1,1)。
能显示的行数、列数及颜色与显示方式有关。
TurboC支持6种不同的文本显示方式。
2)图形模式与点坐标系
在屏幕上能显示图形的方式称为图形方式。
屏幕是由像素点组成的,通过initgraph函数的gmode参数来指定屏幕的分辨率,分辨率决定了像素点的多少。
在图形方式下,屏幕上每个像素的显示位置用点坐标系来描述。
在该坐标系中,屏幕的左上角为坐标原点O(0,0),水平向为x轴,自左向右;垂直方向为y轴,自上向下。
如图1-1所示。
分辨率不同,水平方向和垂直方向上的点数也不一样,即其maxx、maxy的数值不同。
在TurboC中,坐标数据有两种形式给出:
一种是绝对坐标;另一种是相对坐标。
绝对坐标的参考点是坐标的原点O(0,0),x和y的值只能取规定范围内的正整数,其坐标值在整个屏幕范围内确定。
相对坐标是相对于“当前点”的坐标,所以其参考点不是坐标系的原点,而是当前点。
要相对坐标中,x和y的取值是相对于当前点在X方向和Y方向上的增量,这个增量可以是正的,也可以是负的,所以x和y的值可以是正整数,也可以是负整数。
此外,把在一个窗口范围内确定的坐标也称为
相对坐标。
二、C语言中的基本绘图函数及其用法
1、绘图函数
在用绘图函数作图时,有的绘图函数坐标是相对于坐标原点,用绝对坐标。
有的绘图函数用相对坐标,这时要随时注意图形的“当前点位置”,它是绘图的起始位置。
也就是说,图形总是从当前点开始画图。
画完一个图形后,有的当前点不变,仍在原来的位置;而有时会移到新的位置。
1)直线类绘图函数
用直线类函数绘制直线图形,可以用两种坐标:
一种是绝对坐标;另一种是相对坐标。
几个常用的函数:
①点的绝对定位函数moveto(x,y)
②点的相对定位函数moverel(deltayx,deltay)
它们不绘制图形,只改变当前点的位置,接着用绘图函数绘图。
③指定两个绝对点绘直线函数:
line(x1,y1,x2,y2)
该函数不改变当前点的位置。
④从当前点到指定的绝对点绘直线函数:
lineto(x,y)
该函数画线的同时,将当前点的位置移到(x,y)。
⑤从当前点到指定的相对点绘直线函数:
linerel(dx,dy)
该函数画线的同时,将当前点的位置移到(x+dx,y+dy)。
设当前坐标为(x,y)则
linerel(dx,dy)与lineto(x+dx,y+dy)等价。
⑥读取当前点的位置x,y函数分别为:
getx(void),gety(void)
⑦读取x,y轴的最大值函数分别为:
getmaxx(void),getmaxy(void)
2)多边形类绘图函数
1画矩形函数
rectangle(x1,y1,x2,y2);
2画多边形函数:
drawpoly(n,*polypoints)
其中参数,n为多边形数;*polypoints指向一个整形数组,共有2n个整数组成,每对整数给出了一个多边形顶点(x,y)坐标。
2、图形属性的设置
图形属性的设置包括绘制该图形所用的颜色和线型。
颜色又分为背景色和前景色:
背景色指的是屏幕的颜色,即绘图时的底色;前景是指绘图时图形线条所用的颜色。
背景色和前景色的设置,只对设置后所绘制的颜色和线型有作用,对已经绘制的图形无作用。
1)设置前景色
设置前景颜色所用的函数setcolor。
其调用格式为:
setcolor(color);
其中color为一个整型数值,代表所取的颜色。
2)设置背景色
设置背景颜色所用的函数sebktcolor。
其调用格式为:
setbkcolor(color);
其中color为一个整型数值,代表所取的颜色。
3)设置线型
设置当前绘图所用的线型和线宽,用函数setlinestyle。
线型和线宽的设置仅限于对直线类图形有效。
其调用格式为:
setlinestyle(sty,pat,b);
sty:
整型值,用来定义所画直线的类型;pat用户定义线型使用;b整型值,用来定义定义所画直线的线宽。
在屏幕上绘制出各种简单的几何图形,要求设置不同的线形和颜色。
3、填充
填空是指用指定的模式和颜色来填空一个指定的封闭区域。
1)设置当前的填充模式和颜色
设置填充模式和颜色,用函数setfillstyle,其调用格式为:
setfillstyle(pattern,color);
2)实施填充
对于指定的一块有界的封闭区域进行填充操作,用函数floodfill,其调用格式为:
floodfill(x,y,,bcolor);
参数(x,y)指位于填充区域内任意一点的坐标,该点作为填充的起始点,参数bcolor作为填充区域的边界颜色。
如果起始点在封闭区域内,则区域内部被填充;如果起始点在封闭区域外,则区域外部被填充。
同学们可以自行验证。
3)其它填充函数
以下几个填充函数,均须事先由setfillstyle函数指定当前的填充模式和颜色。
①绘制并填充实椭圆函数:
fillellipse(x,y,rx,ry);
②绘制并填充实椭圆扇区函数:
sector(x,y,angs,ange,rx,ry)
③绘制并填充多边形函数:
fillpoly(nps,*pxy)
4、屏幕管理
TurboC2.0提供了11个函数,用于对屏幕和视区进行管理。
1)设置视图区
在图形方式下,可用函数setviewport在屏幕上定义一个视图区。
视图区相当于一个用于绘图的窗口。
视图区的位置和大小用屏幕的绝对坐标定义,并且可把视图区设置为裁剪和不裁剪两种状态。
函数setviewport的调用格式为:
setviewport(x1,y1,x2,y2,c);
参数x1,y1:
为视图区矩形的左上角顶点坐标;x2,y2:
为视图区矩形的右下角顶点坐标。
c为裁剪状态参数。
c=1,超出视图区的图形部分被自动裁剪掉;c=0时,对超出部分不作裁剪处理。
应注意:
视图区建立以后,所有的图形输出坐标都是相对于当前视图区的,即视图区左上角点为坐标(0,0)点,而与视图区和图形在屏幕上的位置无关。
在默认情况下,整个屏幕为一个视图区。
2)清除视图区
清除视图区用函数clearviewport。
它的作用是清除掉当前视图区,将当前点的位置设置于屏幕左上角(0,0)点。
调用格式为:
clearviewport();
3)清屏
清屏的函数为cleardevice();
实验一直线的生成算法
一、实验目的
几种直线生成算法的比较,特别掌握用Bresenham直线生成算法。
二、基本要求
用不同的生成算法在屏幕上绘制出直线的图形,对不同的算法可设置不同的线形或颜色表示区别。
三、算法提示
1、有关直线生成算法有:
DDA(数值微分)直线算法、直线Bresenham生成算法。
直线Bresenham生成算法思想如下(第一象限,且斜率k<1的情况图2-1a中的1a):
1)画点(x1,y1),dx=x2-x1,dy=y2-y1,计算误差初值P1=2dy-dx,i=1;
2)求直线下一点位置xi+1=xi+1如果Pi>0,则yi+1=yi+1,否则yi+1=yi;
3)画点(xi+1,yi+1);
4)求下一个误差Pi+1点,如果Pi>0,则Pi+1=Pi+2dy-2dx,否则Pi+1=Pi+2dy;
5)i=i+1,如果iBresenham生成算法的优点如下;
1)不必计算直线的斜率,因此不做除法。
2)不用浮点数,只用整数。
3)只做整数加减运算和乘2运算,而乘2运算可以用移位操作实现。
Bresenham算法的速度很快,并适于用硬件实现。
对于图2-1a中的2a,只需将xi+1=xi+1改为xi+1=xi-1。
四、参考源程序
1、数值微分法生成斜率小于90的直线
/*DDAline数值微分法生成斜率小于90的直线*/
#include”graphics.h”
#include"conio.h"
voidmain()
{
intgdriver=CGA,gmode=0;
initgraph(&gdriver,&gmode,””)
}
main()
{
intxo,yo,xa,ya,i,j;
intdx,dy,c;
floatddx,ddy,x,y;
Initialize();
printf("inputstartx,y(x=0-640,y=0-480)\n");
scanf("%d,%d",&xo,&yo);/*输入直线的两个点*/
printf("xa:
%d--639",xo);
scanf("%d",&xa);
printf("ya:
0..%d",yo);
scanf("%d",&ya);
printf("redlineissystem,yellowiscreate\n");
if(xa>=xo&&xa<=639&&ya>=0&&ya<=yo)
/*数值微分法生成直线算法*/
{
outtextxy(xo,yo+5,"o");
outtextxy(xa,ya-10,"a");
dx=xa-xo;
dy=yo-ya;
if(dx>dy)c=dx;
elsec=dy;
ddx=dx*1.0/c;
ddy=dy*1.0/c;
x=xo*1.0;
y=yo*1.0;
setcolor(12);
line(xo,yo,xa,ya);
getch();
while(c>=0)
{i=round(x);
j=round(y);
putpixel(i,j,14);
x=x+ddx;
y=y-ddy;
c=c-1;
}
}
elseprintf("dataerror");
getch();
closegraph();
}
intround(ff)
floatff;
{intk;
if((ff-(int)ff)>0.5)k=(int)ff+1;
elsek=(int)ff;
k=(int)ff;
return(k);
}
实验二Bezier曲线的生成算法
一、实验目的
1、复习Bezier曲线参数表示法。
2、编程实现用二次Bezier曲线绘制。
3、编程实现用三次Bezier曲线绘制和分段光滑Bezier曲线图形的绘制。
二、基本要求
1、编程实现在屏幕上绘制出两次Bezie曲线的几何图形和特征多边形图形,对于直线和曲线设置不同的线形和颜色。
2、现在屏幕上绘制出三次Bezie曲线的几何图形和特征多边形图形,对于直线和曲线设置不同的线形和颜色。
3、编程实现用分段三次Bezier曲线绘制光滑Bezier曲线图形。
三、算法提示
1、二次Bezier曲线的计算公式为:
P(t)=(P0-2P1+P2)t2+(-2P0+2P1)t+P0
X(t)=(X0-2X1+X2)t2+(-2X0+2X1)t+X0
Y(t)=(Y0-2Y1+Y2)t2+(-2Y0+2Y1)t+Y0
其中P0、P1、P2为三个已知的点,坐标分别为(X0、Y0)、(X1、Y1)、(X1、Y2)。
2、三次Bezier曲线的计算公式为:
P(t)=(-P0+3P1-3P2+P3)t3+(3P0-6P1+3P2)t2+(-3P0+3P1)t+P0
X(t)=(-X0+3X1-3X2+X3)t3+(3X0-6X1+3X2)t2+(-3X0+3X1)t+X0
Y(t)=(-Y0+3Y1-3Y2+Y3)t3+(3Y0-6Y1+3Y2)t2+(-3Y0+3Y1)t+Y0
其中P0、P1、P2、P3为四个已知的点,坐标分别为(X0、Y0)、(X1、Y1)、(X1、Y2)、(X3、Y3)。
3、程序设计方法
根据Bezier曲线的定义,输入Bezier曲线的特征多边形(例如三次Bezier曲线输入四个型值点),然后把t从0~1分成n等分,按相应的Bezier曲线公式计算出Bezier曲线上的点,用绘直线段的方法依次这些点连接起来,就得到Bezier曲线。
如果要画多段Bezier曲线,可设置一些变量存放Bezier曲线的条数,按条数依次绘制出来即可。
四、上机作业题
1、编程绘制三次Bezier曲线。
2、改变已知点的坐标值,曲线形状有什么变化?
五、参考实例源程序
1、绘制二次Bezier曲线的源程序
/*二次Bezier曲线一般算法*/
#include”graphics.h”
#include"conio.h"
voidmain()
{
intgdriver=CGA,gmode=0;
initgraph(&gdriver,&gmode,””)
}
voidBezier_2(intcolor,doublep[3][2])
{doublet,xt,yt;
intrate=200,x,y;
setcolor(color);
moveto(p[0][0],p[0][1]);
for(t=0;t<=1;t+=1.0/rate)
{yt=1-t;
xt=p[0][0]*yt*yt+p[1][0]*2*yt*t+p[2][0]*t*t;
yt=p[0][1]*yt*yt+p[1][1]*2*yt*t+p[2][1]*t*t;
x=(int)(xt);
y=(int)(yt);
lineto(x,y);
}
}
voidmain(void)
{staticdoublep[3][2]={50,400,340,20,635,420};
constN0=3;/*特征顶点个数*/
inti;
Initialize();/*SetsystemintoGraphicsmode*/
setcolor(WHITE);
moveto(p[0][0],p[0][1]);
for(i=1;iBezier_2(LIGHTRED,p);
while(getch()!
=ESC);/*按ESC键退出*/
closegraph();/*Returnthesystemtotextmode*/
}
实验三制动画程序
一、实验目的
1、复习实现动画的几种编程方法,比较不同方法的差别。
2、综合运用所学知识绘制复杂性图形(包括前景图和背景图)。
3、学会用多图形页功能设计动画程序。
4、学会用位图像函数设计动画程序。
二、基本要求
1、发挥你的想象能力,利用重画技术设计一个动画程序。
2、利用多图形页功能设计一个动画程序。
3、用位图像函数设计一个动画程序。
三、几种常见动画的程序设计思想
1、利用重画技术设计动画程序
在屏幕上绘制一幅图形,用delay函数廷时一段时间,及cleardevice函数清屏,在屏幕上的新位置绘制另一幅图形。
再廷时一段时间,这样不断重复,能使整个屏幕产生动起来的效果。
2、利用多图形页功能设计动画程序
对于支持多个图形页功能的图形卡来说,可以用setactivepage函数把指定图形页设成活动页,用setvisualpage函数把指定图形页设成显示页(可见页)。
活动页可以是当前显示页,也可以是非显示页,但当前的运行程序只能在活动页上绘制。
所以,当用setactivepage函数选定某一页为活动页后,其后所有的图形函数的输出都是针对该页的。
因为存在有多个图形页,所以在程序中,可以把一个页设置成显示页,显示这一页的图形;而在同时把另一页设置成活动页,程序在活动页上绘图。
当活动页上绘完图后,再互换这两个页的设置。
这就相当于在“后头”绘图,整个绘图过程在后头完成;然后拿到前头支显示,在前头显示的是绘制完整的图形画面,如此重复。
这样画面的连续性就会有所改善。
函数setactivepage和函数setvisualpage的用法为:
setvisualpage(intpagenum)setvisualpage(intpagenum)
其中参数pagenum为页号。
对于支持两个图形页的图形卡,页号取0和1。
系统默认值取0。
3、用位图像函数设计动画程序
TurboC中有两个函数getimage和putimage,是用于存取和输出屏幕位图图像信息的。
其中,getimage函数的功能是将屏幕上指定区域中的一个位图图像取下并存到内存中;putimage函数的功能是将内存中的位图图像按指定的方式输出到屏幕上的指定位置上。
这两个函数的调用方法为:
3)getimage的调用方法
getimage(x1,yt,xr,yb,*bitmap);
其中参数x1,yt,xr,yb为整型变量,指定位图所在的矩形区域的对角点坐标。
*bitmap内存中存放位图信息的地址。
4)putimage的调用方法
putimage(x,y,*bitmap,op);
其中参数x,y为整型变量,指定图像在屏幕上输出位置的定位点坐标。
*bitmap内存中存放位图信息的地址。
op为位图图像的输出方式,见表9-1。
符号常量
数值
说明
Op
COPY_PUT
XOR_PUT
OR_PUT
AND_PUT
NOT_PUT
0
1
2
3
4
拷贝
异或
或
与
拷贝源图像的非
四、上机作业题
1、发挥你的想象能力,利用多图形页功能设计一个动画程序。
2、发挥你的想象能力,用位图像函数设计一个动画程序。
五、实例程序:
以下实例程序在TurboC下调试通过
1、用重画技术为实现汽车从左向右运行,同时天空的月亮从右向左运行
/*cglrmxam0509.c*/
#include"graphics.h"
#include"conio.h"
#defineTIME4500
/*ThefunctiontopaintMOON"*/
voidmoon(intx,inty,intr)
{
setcolor(WHITE);
arc(x,y,-120,120,r);
arc(x-0.5*r,y,-90,90,0.87*r);
setfillstyle(SOLID_FILL,WHITE);
floodfill(x+0.5*r,y,WHITE);
return;
}
/*ThefunctiontopaintCAR"*/
voidcar(intdx,intcolor,intnu,int*p)
{
inti;
for(i=0;i<2*nu;i+=2)
*(p+i)=*(p+i)+dx;
setcolor(color);
setfillstyle(SOLID_FILL,color);
fillpoly(nu,p);
setfillstyle(SOLID_FILL,DARKGRAY);
fillellipse(*p+15,350,10,10);
fillellipse(*p+65,350,10,10);
return;
}
voidmain(void)
{
intgdriver=DETECT,gmode,errorcode;
intpcar[9][2]={5,350,90,350,90,335,70,335,65,320,25,320,20,335,
5,335,5,350};
introad[5][2]={0,360,0,479,639,479,639,360,0,360};
inti;
initgraph(&gdriver,&gmode,"E:
\\TC");
cleardevice();
setbkcolor(LIGHTBLUE);
setfillstyle(SOLID_FILL,GREEN);
fillpoly(5,road);
moon(480,120,50);
car(5,RED,9,pcar);
settextstyle(TRIPLEX_FONT,HORIZ_DIR,4);
outtextxy(40,40,"PRESSANYKEYTOSTART");
getch();
for(i=0;i<54;i++)
{
cleardevice();
setfillstyle(SOLID_FILL,GREEN);
fillpoly(5,road);
moon(480-6*i,120,50);
car(10,RED,9,pcar)