计算机图形学结课论文.docx
《计算机图形学结课论文.docx》由会员分享,可在线阅读,更多相关《计算机图形学结课论文.docx(18页珍藏版)》请在冰点文库上搜索。
计算机图形学结课论文
2017届结课论文
《计算机图形学基础教程》
—小球的弹跳运动
学生姓名
学号
所属学院
专业计算机科学与技术
班级
塔里木大学教务处制
小球的弹跳运动
摘要计算机图形学(ComputerGraphics,简称CG)是一种使用数学算法将二维或三维图形转化为计算机显示器的栅格形式的科学。
简单地说,计算机图形学的主要研究内容就是研究如何在计算机中表示图形、以及利用计算机进行图形的计算、处理和显示的相关原理与算法。
图形是客观物质世界在人大脑中的反映、图形蕴含信息密度大、易于理解接受,是当今信息社会中人们用于传递信息的重要手段。
计算机技术和图形的结合使得图形在深度、广度和形式上都发生了深刻的变化,其应用也波及社会的各个领域。
本次课程论文主要阐述通过计算机图形学中动画的实现,来实现简单的小球运动动画过程。
关键词:
计算机图形学、计算机动画、计算机技术
1.背景
1.1计算机图形学概述
图形通常由点、线、面、体等几何元素和灰度、色彩、线型、线宽等非几何属性组成。
从处理技术上来看,图形主要分为两类,一类是基于线条信息表示的,如工程图、等高线地图、曲面的线框图等,另一类是明暗图,也就是通常所说的真实感图形。
计算机图形学一个主要的目的就是要利用计算机产生令人赏心悦目的真实感图形。
为此,必须建立图形所描述的场景的几何表示,再用某种光照模型,计算在假想的光源、纹理、材质属性下的光照明效果。
所以计算机图形学与另一门学科计算机辅助几何设计有着密切的关系。
事实上,图形学也把可以表示几何场景的曲线曲面造型技术和实体造型技术作为其主要的研究内容。
同时,真实感图形计算的结果是以数字图像的方式提供的,计算机图形学也就和图像处理有着密切的关系。
1.2计算机图形画面的分类
计算机动画是计算机图形学和艺术相结合的产物,它是伴随着计算机硬件和图形算法高速发展起来的一门高新技术。
动画是运动中的艺术,运动是动画的要素。
计算机动画以其制作方法和特征通常分为二维动画和三维动画两种形式。
(1)二维图形
传统的图形画面的实现是连续播放多帧画面,每幅画面表述的是运动物体若干个瞬间,利用观看者的瞬间视觉残留而得到运动的视觉感受。
二维图形画面显示的主要是平面图形,制作时就像在纸上作画,通过对象的移动、变形、变色等手法表现其运动的效果;计算机动画原理也是一样,计算机图形画面的每一帧画面都是一幅数字化的图像。
(2)三维立体图形
三维画面则显示立体图形,其制作就像是在摄影棚中拍电影:
首先在三维视图中布置摄影对象的位置、规定其运动、安排好各种灯光,然后在特定位置架设好“摄影机”,可设定摄影机的推拉摇移,最后计算机计算出在这一立体空间下“摄影机所见的”动态图像效果。
尽管在常见的二维画面中也可以模拟三维的立体空间,但其图像的精确度等远不及三维图像画面。
2.OpenGL概述
OpenGL是一个开放的三维图形软件包,它独立于窗口系统和操作系统,以它为基础开发的应用程序可以十分方便地在各种平台间移植;OpenGL可以与VisualC++紧密接口,便于实现机械手的有关计算和图形算法,可保证算法的正确性和可靠性;OpenGL使用简便,效率高。
OpenGL基本函数均使用gl作为函数名的前缀,如glClearColor();实用函数则使用glu作为函数名的前缀,如gluSphere()。
OpenGL基本常量的名字以GL_开头,如GL_LINE_LOOP;实用常量的名字以GLU_开头,如GLU_FILL。
一些函数如glColor*()(定义颜色值),函数名后可以接不同的后缀以支持不同的数据类型和格式。
如glColor3b(...)、glColor3d(...)、glColor3f(...)和glColor3bv(...)等,这几个函数在功能上是相似的,只是适用于不同的数据类型和格式,其中3表示该函数带有三个参数,b、d、f分别表示参数的类型是字节型、双精度浮点型和单精度浮点型,v则表示这些参数是以向量形式出现的。
OpenGL定义了一些特殊标识符,如GLfloat,GLvoid。
它们其实就是C中的float和void。
在gl.h文件中可以看到以下定义:
……
typedeffloatGLfloat;
typedefvoidGLvoid;
……
一些基本的数据类型都有类似的定义项。
2.1程序的基本结构
OpenGL程序的基本结构可分为三个部分:
第一部分是初始化部分。
主要是设置一些OpenGL的状态开关,如颜色模式(RGBA或ALPHA)的选择,是否作光照处理(若有的话,还需设置光源的特性),深度检验,裁剪等等。
这些状态一般都用函数glEnable(...),glDisable(…)来设置,…表示特定的状态。
第二部分设置观察坐标系的取景模式和取景框位置大小。
利用了三个函数:
函数voidglViewport(left,top,right,bottom):
设置在屏幕上的窗口大小,四个参数描述屏幕窗口四个角上的坐标(以象素表示);
函数voidglOrtho(left,right,bottom,top,near,far):
设置投影方式为正交投影(平行投影),其取景体积是一个各面均为矩形的六面体;
函数voidgluPerspective(fovy,aspect,zNear,zFar):
设置投影方式为透视投影。
第三部分是OpenGL的主要部分,使用OpenGL的库函数构造几何物体对象的数学描述,包括点线面的位置和拓扑关系、几何变换、光照处理等等。
以上三个部分是OpenGL程序的基本框架,即使移植到使用MFC的Windows程序中,也是如此。
只是由于Windows自身有一套显示方式,需要进行一些必要的改动以协调这两种不同显示方式。
2.2状态机制
OpenGL的工作方式是一种状态机制,它可以进行各种状态或模式设置,这些状态或模式在重新改变它们之前一直有效。
例如,当前颜色就是一个状态变量,在这个状态改变之前,绘制的每个象素都将使用该颜色,直到当前颜色被设置为其它颜色为止。
OpenGL中大量地使用了这种状态机制,如颜色模式、投影模式、单双显示缓存区的设置、背景色的设置、光源的位置和特性等等。
许多状态变量可以通过glEnable()、glDisable()这两个函数来设置成有效或无效状态,如是否设置光照、是否进行深度检测等;在被设置成有效状态之后,绝大部分状态变量都有一个缺省值。
通常情况下,可以用下列四个函数来获取某个状态变量的值:
glGetBooleanv()、glGetDouble()、glGetFloatv()和glGetIntegerv()。
究竟选择哪个函数应该根据所要获得的返回值的数据类型来决定。
还有些状态变量有特殊的查询函数,如glGetLight*()、glGetError()和glPolygonStipple()等。
另外,使用glPushAttrib()和glPopAttrib()函数,可以存储和恢复最近的状态变量的值。
只要有可能,都应该使用这些函数,因为它们比其它查询函数的效率更高。
3.方案论述
3.1小球运动过程
小球从某一高度处水平抛出,落地后立即弹起,弹起的最大高度为上一次高度的5/6。
经过N次以后皮球不再弹起,保持静止。
通过小球的轨迹可以实现小球通过其他静止的小球(障碍物)的画面。
整个设计包括两个方面,一是掌握小球运动的基本原理,二是圆的绘制。
动画是将静止的画面变为动态的艺术。
实现由静止到动态,主要是靠人眼的视觉残留效应。
利用人的这种视觉生理可制作出具有高度想象力和表现力的画面。
3.2简单光照模型实现原理
Phong光照明模型是由物体表面上一点P反射到视点的光强I为环境光的反射光强Ie、理想漫反射光强Id、和镜面反射光Is的总和,即
图3.2光照模型
其中R,V,N为单位矢量;Ip为点光源发出的入射光强;Ia为环境光的漫反射光强;Ka环境光的漫反射系数;Kd漫反射系数取决于表面的材料;Ks镜面反射系数;n幂次,用以模拟反射光的空间分布,表面越光滑,n越大。
在用Phong模型进行真实感图形计算时,对物体表面上的每个点P,均需计算光线的反射方向R,再由V计算。
为减少计算量,我们可以作如下假设:
a)光源在无穷远处,即光线方向L为常数;b)视点在无穷远处,即视线方向V为常数;c)用近似。
这里H为L和V的角平分向量,。
在这种简化下,由于对所有的点总共只需计算一次H的值,节省了计算时间。
结合RGB颜色模型,Phong光照明模型最终有如下的形式:
本次设计中,光源在无穷远处,光线方向为单位向量L(0.5,0.5,0.707),视点在无穷远处,视线方向V为(0, 0, 1)。
4.程序模块分析
4.1小球的生成模块
(1)定义小球的大小,起始位置
Intcx=100,cy=600;cr=20;定义小球开始运动位置、小球下降高度和体积大小;
voidMidCircleLight(intx0,inty0,intr)小球的生成方法;
voidmyDisplay()小球的显示方法;
4.2小球的运动时间模块
小球的运动时间,物理学中,我们学过忽略空气阻力,小球的下落的时间由下落的高度决定:
由h=1/2(g*t^2)得t=sqrt(2*h/g);此处用到了定时器功能。
voidTimerFunction(intvalue)定时器功能方法;
glBegin(GL_POINTS);小球填充方法。
4.3主程序运行模块
(1)glutInit,对GLUT进行初始化,这个函数必须在其它的GLUT使用之前调用一次。
其格式比较固定,一般都是glutInit(&argc,argv)就行;
(2)glutInitDisplayMode,设置显示方式,其中GLUT_RGB表示使用RGB颜色,与之对应的还有GLUT_INDEX(表示使用索引颜色)。
GLUT_SINGLE表示使用单缓冲,与之对应的还有GLUT_DOUBLE(使用双缓冲)。
更多信息,以后的实验教程会有讲解介绍;
(3)glutInitWindowPosition,设置窗口在屏幕中的位置;
(4)glutInitWindowSize,设置窗口的大小;
(5)glutCreateWindow,根据前述设置的信息创建窗口。
参数将被作为窗口的标题。
注意:
窗口被创建后,并不立即显示到屏幕上。
需要调用glutMainLoop才能看到窗口;
(6)glutDisplayFunc,设置一个函数,当需要进行画图时,这个函数就会被调用。
(7)glutMainLoop,进行一个消息循环。
在glutDisplayFunc函数中,我们设置了“当需要画图时,请调用myDisplay函数”。
于是myDisplay函数就用来画图。
观察myDisplay中的三个函数调用,发现它们都以gl开头。
这种以gl开头的函数都是OpenGL的标准函数,下面对用到的函数进行介绍:
1glClearColor(0.0,0.0,0.0,0.0):
将清空颜色设为黑色;
2glClear(GL_COLOR_BUFFER_BIT):
将窗口的背景设置为当前清空颜色;
3glRectf,画一个矩形。
参数表示了位于对角线上的两个点的横、纵坐标;
4glFlush,保证前面的OpenGL命令立即执行(而不是让在缓冲区中等待)。
4.4材质定义
材质的定义与光源的定义类似。
其函数为:
voidglMaterial{if}[v](GLenumface,GLenumpname,TYPEparam);
定义光照计算中用到的当前材质。
face可以是GL_FRONT、GL_BACK、GL_FRONT_AND_BACK,它表明当前材质应该应用到物体的哪一个面上;pname说明一个特定的材质;param是材质的具体数值,若函数为向量形式,则param是一组值的指针,反之为参数值本身。
非向量形式仅用于设置GL_SHINESS。
4.5双缓冲技术
总体意思为两个区域一个显示,一个则负责画图,然后连续切换
在计算机上的动画与实际的动画有些不同:
实际的动画都是先画好了,播放的时候直接拿出来显示就行。
计算机动画则是画一张,就拿出来一张,再画下一张,再拿出来。
如果所需要绘制的图形很简单,那么这样也没什么问题。
但一旦图形比较复杂,绘制需要的时间较长,问题就会变得突出。
我们以前在main函数里面写:
glutInitDisplayMode(GLUT_RGB|GLUT_SINGLE);
其中GLUT_SINGLE表示单缓冲,如果改成GLUT_DOUBLE就是双缓冲了。
当然还有需要更改的地方——每次绘制完成时,我们需要交换两个缓冲区,把绘制好的信息用于屏幕显示(否则无论怎么绘制,还是什么都看不到)。
如果使用GLUT工具包,也可以很轻松的完成这一工作,只要在绘制完成时简单的调用glutSwapBuffers函数就可以了。
5.总结
开始时由于显示框设置的宽度偏小,以及小球弹起高度偏高,以至于最终观察不到皮球的静止状态。
对数值进行几次修改并调试后,达到所要求的效果。
此外,皮球的平抛初速度设置的不够合理,使下落时做的抛物线运动效果不够明显;皮球的运动过程中也有一些的晃动。
由于个人能力有限,这两个问题还没得到明显改善。
时光,稍纵即逝,终于完成了这门课程作业,回想起来整个过程,感触还是挺多的。
在设计刚开始时,感到无从下手。
以前没学过C++,而仅仅学过的C语言,基础也很不扎实。
在网上翻阅相关书籍和资料后,对C++编程和OpenGL总算有了进一步理解和掌握。
从网上找到关于球运动的一些程序,经过慢慢摸索和修改,还请教了周围的同学,终于有了现在的程序。
程序编好后,依照各个函数和功能块,最终实现了小球的简单运动动画。
在这次课程作业中我遇到了许多问题,同时也发现了自己的不足之处,对以前所学过的知识理解得不够深刻,掌握得不够牢固。
比如说不懂一些软件的使用方法,对图形语言掌握得不透彻。
还有,这次课程作业,让我明白了只有自己懂,自己做,才不会在关键时刻掉链子。
别人学到的知识终究是别人的,路总是要自己走,属于自己的任务就要自己搞。
所以,我们必须要时刻强大自己,不要一味依赖别人。
这个过程虽然不是很平坦,肯定会遇到各种各样的问题,但一旦征服了它,那它就是你的东西了,当这样的厚积达到一定程度那你就能享受到薄发那刻的辉煌。
附录A:
程序清单
#include
#include
#include
#include
#defineNO_LIGHT1
#defineLIGHT2
structVector{
floatfx,fy,fz;};//矢量
structColor{
floatIr,Ig,Ib;};/*定义皮球的颜色*/
floatKaIa,Kd,n;//环境光强度
VectorH,light;
ColormLight,mColor;
GLbooleanbLight=false;
intcx=100,cy=600,cr=20;/*定义皮球开始运动时的水平位置,下落高度和体积大小*/
intcx1=50,cy1=200,cr1=15;
intwindowswidth=1200,windowshight=600;/*定义显示框的宽度和高度*/
intxstep=0,ystep=0,flag=10,up=0;
floatvh=4,g=19.8,h=cy;//小球轨迹的振幅
//初始化设定
voidInit(){floatmo;
Vectoreye;
mLight.Ir=1200,mLight.Ig=200,mLight.Ib=800;/*定义皮球的颜色*/
KaIa=100,Kd=0.7,n=10;
light.fx=0.10;light.fy=0.50;
light.fz=sqrt(1-(light.fx*light.fx)-(light.fy*light.fy));
eye.fx=0;eye.fy=0;eye.fz=1;
H.fx=light.fx+eye.fx;
H.fy=light.fy+eye.fy;
H.fz=light.fz+eye.fz;
mo=sqrt(H.fx*H.fx+H.fy*H.fy+H.fz*H.fz);
H.fx=(H.fx/mo);H.fy=(H.fy/mo);H.fz=(H.fz/mo);
H.fx=(H.fx/mo);H.fy=(H.fy/mo);H.fz=(H.fz/mo);
glClearColor(1.0,1.0,1.0,0.0);
glShadeModel(GL_SMOOTH);
}
//根据Phong模型计算光强
ColorPhong(intx0,inty0,intr,intx,inty){VectorN;
floatz,alpha,theta,Ks;
Ks=1.0-Kd;
z=sqrt((float)(r*r-(x-x0)*(x-x0)-(y-y0)*(y-y0)));
N.fx=(x-x0)*1.0/r;
N.fy=(y-y0)*1.0/r;
N.fz=z*1.0/r;
theta=N.fx*light.fx+N.fy*light.fy+N.fz*light.fz;
if(theta<0)theta=0;
alpha=H.fx*N.fx+H.fy*N.fy+H.fx*N.fz;
if(alpha<0)alpha=0;
mColor.Ir=KaIa+mLight.Ir*Kd*theta+mLight.Ir*Ks*pow(alpha,n);
mColor.Ig=KaIa+mLight.Ig*Kd*theta+mLight.Ig*Ks*pow(alpha,n);
mColor.Ib=KaIa+mLight.Ib*Kd*theta+mLight.Ib*Ks*pow(alpha,n);
returnmColor;
}
voidMidCircleLight(intx0,inty0,intr){
intx,y,deltax,deltay,d;
x=0;
y=r;
deltax=3;
deltay=5-r-r;
d=10-r;
inti=0;
glBegin(GL_POINTS);
{for(i=-y;i<=y;i++){
mColor=Phong(x0,y0,r,i+x0,x+y0);
glColor3ub(mColor.Ir,mColor.Ig,mColor.Ib);
glVertex2i(i+x0,x+y0);
glColor3ub(mColor.Ir,mColor.Ig,mColor.Ib);
glVertex2i(i+x0,-x+y0);
}
for(i=-x;i<=x;i++){
mColor=Phong(x0,y0,r,i+x0,y+y0);
glColor3ub(mColor.Ir,mColor.Ig,mColor.Ib);
glVertex2i(i+x0,y+y0);
glColor3ub(mColor.Ir,mColor.Ig,mColor.Ib);
glVertex2i(i+x0,-y+y0);
}
while(xif(d<0){
d+=deltax;
deltax+=2;
deltay+=2;
x++;
}else{
d+=deltay;
deltax+=2;
deltay+=4;
x++;
y--;
}
for(i=-x;i<=x;i++){
mColor=Phong(x0,y0,r,i+x0,y+y0);
glColor3ub(mColor.Ir,mColor.Ig,mColor.Ib);
glVertex2i(i+x0,y+y0);
glColor3ub(mColor.Ir,mColor.Ig,mColor.Ib);
glVertex2i(i+x0,-y+y0);
}
for(i=-y;i<=y;i++){
mColor=Phong(x0,y0,r,i+x0,x+y0);
glColor3ub(mColor.Ir,mColor.Ig,mColor.Ib);
glVertex2i(i+x0,x+y0);
glColor3ub(mColor.Ir,mColor.Ig,mColor.Ib);
glVertex2i(i+x0,-x+y0);}
}
}glEnd();
}
/*用此函数来显示*/
voidmyDisplay(){
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0f,1.0f,1.0f);
MidCircleLight(cx,cy,cr);
MidCircleLight(cx1,cy1,cr1);
MidCircleLight(200,100,10);
MidCircleLight(300,300,10);
MidCircleLight(400,500,10);
MidCircleLight(500,300,10);
MidCircleLight(600,100,10);
MidCircleLight(700,300,10);
MidCircleLight(800,500,10);
MidCircleLight(900,300,10);
MidCircleLight(1000,100,10);
MidCircleLight(1100,300,10);
Colorclr;
clr.Ir=180,clr.Ig=180,clr.Ib=180;
glFlush();
}
/*加载身份*/
voidReshape(intw,inth){
glViewport(0,0,(GLsizei)w,(GLsizei)h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0,(GLdouble)w,0.0,(GLdouble)h);
}
/*渲染现场*/
voidRenderScene(void){
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0f,0.0f,0.0f);
/*清空命令缓冲区并交换帧缓存*/
glutSwapBuffers();
}
/*定义计时器功能*/
voidTimerFunction(intvalue){
/*处理到达窗口边界的球形,使之反弹*/
fl