计算机图形学期末实验报告.docx
《计算机图形学期末实验报告.docx》由会员分享,可在线阅读,更多相关《计算机图形学期末实验报告.docx(11页珍藏版)》请在冰豆网上搜索。
![计算机图形学期末实验报告.docx](https://file1.bdocx.com/fileroot1/2022-12/31/6e2e9c28-fd85-4de7-8feb-d9733827fff2/6e2e9c28-fd85-4de7-8feb-d9733827fff21.gif)
计算机图形学期末实验报告
附件1:
封面格式
得分:
计算机图形学期末考试答卷
姓名:
学号:
一、目标及任务
目标:
1、熟悉OpenGL编程
2、学会平面网格的绘制
3、掌握Opengl的光照和动画实现
任务一:
1、绘制如上图的一个绿色平面网格。
网格x的世界坐标取值范围为[-16,16],
y的世界坐标取值范围为[-16,16]。
z取值始终为0。
2、该题所绘制的平面网格,用于
模拟地面,需将其整合到后面提高题中的场景中。
任务二:
1.构造三个球体对象,要求启用光照,对象的色彩可以自行发挥想象。
2.三个球体对象,最大的球体A,中间大球体B,最小的球体C。
球体A静止不动,
球体B绕球体A旋转,球体C绕球体B旋转,同时也绕球体A旋转(球体C有点类似月球,
它绕地球旋转,同时也绕太阳旋转)。
二、开发环境
操作系统版本:
win7
集成开发环境:
visuaC++6.0
三、总的技术思路、技术流程框架图及源代码
任务一:
主要用到的函数:
1、voidgluLookAt(GLdoubleeyex,GLdoubleeyey,GLdoubleeyez,GLdoublecenterx,GLdoublecentery,GLdoublecenterz,GLdoubleupx,GLdoubleupy,GLdoubleupz);
该函数定义一个视图矩阵,并与当前矩阵相乘。
第一组eyex,eyey,eyez相机在世界坐标的位置
第二组centerx,centery,centerz相机镜头对准的物体在世界坐标的位置
第三组upx,upy,upz相机向上的方向在世界坐标中的方向
2、voidglLineStipple(GLintfactor,GLushortpattern);
参数pattern:
是由1或0组成的16位序列,从这个模式的低位开始,一个一个像素地进行处理,如果模型中对应的位是1,就绘制这个像素,否则不绘制。
factor:
为重复因子,它与1和0的连续子序列相乘,如果模式中出现3个1,并且factor是2,那么他们就扩展为6个连续的1.
3、glOrtho就是一个正射投影函数。
它创建一个平行视景体。
实际上这个函数的操作是创建一个正射投影矩阵,并且用这个矩阵乘以当前矩阵。
其中近裁剪平面是一个矩形,矩形左下角点三维空间坐标是(left,bottom,-near),右上角点是(right,top,-near);远裁剪平面也是一个矩形,左下角点空间坐标是(left,bottom,-far),右上角点是(right,top,-far)。
所有的near和far值同时为正或同时为负。
如果没有其他变换,正射投影的方向平行于Z轴,且视点朝向Z负轴。
这意味着物体在视点前面时far和near都为负值,物体在视点后面时far和near都为正值。
主要用到的技术:
1、正射投影
正射投影,又叫平行投影。
这种投影的视景体是一个矩形的平行管道,也就是一个长方体,如图所示。
正射投影的最大一个特点是无论物体距离相机多远,投影后的物体大小尺寸不变。
这种投影通常用在建筑蓝图绘制和计算机辅助设计等方面,这些行业要求投影后的物体尺寸及相互间的角度不变,以便施工或制造时物体比例大小正确。
2、模型视图变换
由于模型和视图的变换都通过矩阵运算来实现,在进行变换前,应先设置当前操作的矩阵为“模型视图矩阵”。
设置的方法是以GL_MODELVIEW为参数调用glMatrixMode函数。
在代码中,视图变换必须出现在模型变换之前,但可以在绘图之前的任何时候执行投影变换和视口变换。
display()程序中绘图函数潜在的重复性强调了:
在指定的视图变换之前,应该使glLoadIdentity()函数把当前矩阵设置为单位矩阵。
在载入单位矩阵之后,使用gluLookAt()函数指定视图变换。
如果程序没有调用gluLookAt(),那么照相机会设定为一个默认的位置和方向。
在默认的情况下,照相机位于原点,指向Z轴负方向,朝上向量为(0,1,0)。
一般而言,display()函数包括:
视图变换+模型变换+绘制图形的函数(如glutWireCube())。
display()会在窗口被移动或者原来先遮住这个窗口的东西被一开时,被重复调用,并经过适当变换,保证绘制的图形是按照希望的方式进行绘制。
在调用glFrustum()设置投影变换之前,在reshape()函数中有一些准备工作:
视口变换+投影变换+模型视图变换。
由于投影变换,视口变换共同决定了场景是如何映射到计算机的屏幕上的,而且它们都与屏幕的宽度,高度密切相关,因此应该放在reshape()中。
reshape()会在窗口初次创建,移动或改变时被调用。
OpenGL中矩阵坐标之间的关系:
物理坐标*模型视图矩阵*投影矩阵*透视除法*规范化设备坐标——〉窗口坐标
源代码:
#include
voidmyDisplay(){
glClear(GL_COLOR_BUFFER_BIT);//刷新背景
glMatrixMode(GL_MODELVIEW);//对模型视景矩阵操作
glLoadIdentity();//加载单位矩阵
gluLookAt(1.0,1.0,1.0,0.0,0.0,0.0,0.0,0.0,5.0);//定义视图矩阵设置照相机位置
for(inti=-16;i<16;i++){
for(intj=-16;j<16;j++)
{
glBegin(GL_LINE_LOOP);//绘制线段
glVertex3f(i,j,0);
glVertex3f(i,j+1,0);
glVertex3f(i+1,j+1,0);
glVertex3f(i+1,j,0);
glEnd();
}
}
glFlush();
}
voidinit(){
glColor3f(1.0,0.0,1.0);//网格颜色
glLineStipple(3,0xcccc);//定义点画模式
glMatrixMode(GL_PROJECTION);//投影矩阵
glLoadIdentity();//加载单位矩阵
glOrtho(-24,24,-24,24,-24,24);//设置修改空间范围
}
voidmain(intargc,char**argv){
glutInit(&argc,argv);
glutInitWindowPosition(0,0);//初始位置
glutInitWindowSize(800,800);
glutCreateWindow("lines");
glutDisplayFunc(myDisplay);
glEnable(GL_LINE_STIPPLE);//启用直线点画功能
init();
glutMainLoop();//循环绘图
}
运行效果图:
任务二:
主要技术:
1、动画的实现:
动画的实现是通过不断修改旋转变换的角度来实现的。
并且利用双缓冲技术,在存储器(很有可能是显存)中开辟两块区域,一块作为发送到显示器的数据,一块作为绘画的区域,在适当的时候交换它们,只要在绘制完成时简单的调用glutSwapBuffers函数把绘制好的信息用于屏幕显示就可以了。
在每次调用显示回调函数之前改变角度参数的值,使天体看起来像在旋转。
其中,angle1为地球绕太阳旋转的角度,angle2为月亮绕地球旋转的角度,月亮绕地球旋转速度是地球绕太阳旋转速度的12倍,设置angle1每次增加20.0f度,angle2每次增加2.0f度。
2、深度测试:
深度测试决定了是否绘制较远的象素点(或较近的象素点),通常选用较近的,而较远优先能实现透视的效果。
深度测试只需要调用函数:
glEnable(GL_DEPTH_TEST);就可以打开深度测试功能。
另外,在创建窗口时指定其具有深度缓冲区,深度缓存的位数是衡量深度缓存精度的参数。
深度缓存位数越高,则精确度越高,在每次渲染场景时,消除深度缓冲区即可。
3、光照:
简单的光照效果的,我们通过光照的层次,很容易的认为它是一个三维的物体
眼睛之所以看见各种物体,是因为光线直接或间接的从它们那里到达了眼睛。
人类对于光线强弱的变化的反应,比对于颜色变化的反应来得灵敏。
因此对于人类而言,光线很大程度上表现了物体的立体感。
OpenGL在处理光照时采用这样一种近似:
把光照系统分为三部分,分别是光源、材质和光照环境。
光源就是光的来源,可以是前面所说的太阳或者电灯等。
材质是指接受光照的各种物体的表面,由于物体如何反射光线只由物体表面决定(OpenGL中没有考虑光的折射),材质特点就决定了物体反射光线的特点。
光照环境是指一些额外的参数,它们将影响最终的光照画面,比如一些光线经过多次反射后,已经无法分清它究竟是由哪个光源发出,这时,指定一个“环境亮度”参数,可以使最后形成的画面更接近于真实情况。
对于光源发出的光线,可以分别设置其经过镜面反射和漫反射后的光线强度。
对于被光线照射的材质,也可以分别设置光线经过镜面反射和漫反射后的光线强度。
这些因素综合起来,就形成了最终的光照效果。
根据光的反射定律,由光的入射方向和入射点的法线就可以得到光的出射方向。
因此,对于指定的物体,在指定了光源后,即可计算出光的反射方向,进而计算出光照效果的画面。
本作业中使用了2个光源,一个在太阳中心light0,照亮地球和月亮;另一个光源light1只照亮太阳,在画太阳之前打开,画完之后使用函数glDisable(GL_LIGHT1);关闭light1。
4、表面材质:
材质与光源相似,也需要设置众多的属性。
不同的是,光源是通过glLight*函数来设置的,而材质则是通过glMaterial*函数来设置的。
glMaterial*函数有三个参数。
第一个参数表示指定哪一面的属性。
可以是GL_FRONT、GL_BACK或者GL_FRONT_AND_BACK。
分别表示设置“正面”“背面”的材质,或者两面同时设置。
第二、第三个参数与glLight*函数的第二、三个参数作用类似。
本作业中只用到了材质的发射光颜色,太阳、地球、月亮分别为红色、蓝色和黄色,如设置太阳glMaterialfv(GL_FRONT_AND_BACK,GL_EMISSION,sun_emission);
技术流程图:
源代码:
#include
#include
voidInitial()
{
GLfloatlight0_diffuse[]={1.0f,0.5f,0.0f,1.0f};//light0中漫反射光分量
GLfloatlight0_position[]={10.0f,20.0f,-150.0f,1.0f};//light0的坐标位置
GLfloatlight0_direction[]={0.0f,0.0f,-1.0f};//light0的聚光灯方向角
glLightfv(GL_LIGHT0,GL_DIFFUSE,light0_diffuse);//light0在太阳中心
glLightfv(GL_LIGHT0,GL_POSITION,light0_position);
glLightfv(GL_LIGHT0,GL_SPOT_DIRECTION,light0_direction);
glEnable(GL_DEPTH_TEST);//启用深度测试
glEnable(GL_LIGHTING);//启用光源
glEnable(GL_LIGHT0);//使用0号光照
glEnable(GL_COLOR_MATERIAL);//启用颜色材质模式
glFrontFace(GL_CCW);//指定逆时针绕法表示多边形正面
}
voidChangeSize(intw,inth)
{
if(h==0)h=1;
glViewport(0,0,w,h);//设置视区尺寸
glMatrixMode(GL_PROJECTION);//指定当前操作投影矩阵堆栈
glLoadIdentity();//重置投影矩阵
gluPerspective(35.0,(float)w/(float)h,1.0,500.0);//指定透视投影的观察空间
glMatrixMode(GL_MODELVIEW);//投影矩阵
glLoadIdentity();//加载单位矩阵
}
voidDisplay(void)
{
staticfloatangle1=0.0f,angle2=0.0f;
//angle1地球绕太阳旋转的角度,angle2月亮绕地球旋转的角度
GLfloatsun_emission[]={0.6f,0.0f,0.0f,1.0f};//太阳颜色
GLfloatearth_emission[]={0.0f,0.0f,0.8f,1.0f};//地球颜色
GLfloatmoon_emission[]={0.98f,0.625f,0.12f,1.0f};//月亮颜色
GLfloatlight1_diffuse[]={0.5f,0.8f,0.0f,1.0f};//光源light1中漫反射光分量
GLfloatlight1_position[]={50.0f,100.0f,100.0f,1.0f};//光源light1的坐标位置
GLfloatlight1_direction[]={0.0f,0.0f,-1.0f};//光源light1的聚光灯方向角
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);//清除颜色和深度缓冲区
glMatrixMode(GL_MODELVIEW);//指定当前操作模型视图矩阵堆栈
glLoadIdentity();//重置模型视图矩阵
glTranslatef(0.0f,0.0f,-150.0f);//将图形沿z轴负向移动150.0f
//绘制太阳
glEnable(GL_LIGHT1);
glLightfv(GL_LIGHT1,GL_DIFFUSE,light1_diffuse);
glLightfv(GL_LIGHT1,GL_POSITION,light1_position);
glLightfv(GL_LIGHT1,GL_SPOT_DIRECTION,light1_direction);
glMaterialfv(GL_FRONT_AND_BACK,GL_EMISSION,sun_emission);
glutSolidSphere(12.0f,30,30);//绘制太阳
glDisable(GL_LIGHT1);
//绘制地球
glPushMatrix();//保存当前的矩阵视图模型
glRotatef(angle1,0.0f,10.0f,1.0f);//旋转一定角度
glTranslatef(40.0f,0.0f,0.0f);//绕x轴正向移动40.0f
glMaterialfv(GL_FRONT_AND_BACK,GL_EMISSION,earth_emission);
glutSolidSphere(6.0f,20,20);//绘制地球
//绘制月亮
glRotatef(angle2,0.0f,1.0f,0.0f);
glTranslatef(15.0f,0.0f,0.0f);//绕x轴方向移动15.0f
glMaterialfv(GL_FRONT_AND_BACK,GL_EMISSION,moon_emission);
glutSolidSphere(3.0f,20,20);//绘制月亮
glPopMatrix();//恢复矩阵视图模型
angle1+=2.0f;//增加旋转步长,产生动画效果
if(angle1==360.0f)
angle1=0.0f;
angle2+=20.0f;
if(angle2==360.0f)
angle2=0.0f;
glutSwapBuffers();//双缓冲下使用该函数交换两个缓冲区的内容
}
voidTimerFunc(intx)
{
glutPostRedisplay();//重绘图像
glutTimerFunc(100,TimerFunc,1);//定时
}
intmain(intargc,char*argv[])
{
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB|GLUT_DEPTH);
//设置图形显示模式为双缓冲,深度缓冲,建立RGB模式窗口
glutInitWindowSize(640,480);
glutInitWindowPosition(400,200);
glutCreateWindow("太阳地球月亮");
glutReshapeFunc(ChangeSize);
glutDisplayFunc(Display);
glutTimerFunc(500,TimerFunc,1);
Initial();
glutMainLoop();
return0;
}
运行效果图:
四、心得
在本学期的计算机图形学学习中,不仅让我学习到了很多图形学知识,期末的作业更培养了我如何去把握一件事情,如何去做一件事情,又如何完成一件事情。
学习计算机图形学不能停留在学习它的程序语言,而是利用学到的知识编写C语言程序来验证自己的想法,深入理解图形生成的原理,解决实际问题。
而且计算机图形学是依附在C语言编程基础之上的,我们对图形生成算法的理解要通过C程序才能体现出来。
通过本学期对计算机图形学这门课的学习,使我们巩固了一些关于C语言的知识,理解了我们计算机图形学的理论知识,这对我们将来到社会工作将会有莫大的帮助。
同时它让我知道计算机图形的强大和瑰丽之处,虽然我们学的都是基本的生成算法,但是通过老师展示的几个计算机图形学高级程序,我们才了解到计算机图形学可以做出非常华丽的视觉效果,而且只要你努力,任何东西都不会太难。
最后,还是很庆幸能学到计算机图形学这样的一门课程,在学习本课程的同时,已经涉及了很多的学科,让我们更有能力成为全方位、多特色的新世纪人才。
使我们的编程能力、思维能力都获得了提高。