OpenGL学习记录3
来源:互联网 发布:海康监控网络不可达 编辑:程序博客网 时间:2024/05/19 23:27
Exercise 3:光照
要求:
1. 绘制带有光照效果的场景;
2. 场景包含3个茶壶,通过键盘1,2,3可以分别选中三个茶壶,然后用鼠标对每个茶壶进行分别的旋转;
3. 使用点光源,点光源为白色,以白色的球体表示;
4. 使用3个不同的点光源
i. 光源1的坐标设置在世界坐标系中,并围绕着三个茶壶的中心进行圆周运动;
ii. 光源2 的坐标 设置在观察坐标系,不发生变化;
iii. 光源3的坐标设置在茶壶1的物体坐标系中,当茶壶1被选中进行旋转时,光源3要跟随茶壶1 做相同的旋转;
考察目的:
1. OpenGL中光源的使用;
2. 如何在OpenGL中通过回调函数实现简单的动画(光源1需要自动围绕茶壶做圆周运动);
3. 通过设置光源的不同时机,将光源设置在不同的坐标系下;
by/scu xx
/*世界坐标系:是将每一个模型共享在一个场景中的坐标系,它通常用来描述我们期望呈现的各个模型之间的联系关系。观察坐标系:有时候我们也叫做摄影坐标系,这个有点像世界坐标系那样,只不过世界坐标系是用来描述整个场景的, 而观察坐标系的原点在观察着的眼睛或摄像机。观察坐标系的Z轴就是眼睛看到的前方,Y轴相当于眼睛的上 方,X轴位于右方。 颜色缓冲区(COLOR_BUFFER)就是帧缓冲区(FRAME_BUFFER),你需要渲染的场景最终每一个像素都要写入该缓冲区,然后由它在渲染到屏幕上显示. 深度缓冲区(DEPTH_BUFFER)与帧缓冲区对应,用于记录上面每个像素的深度值,通过深度缓冲区,我们可以进行深度测试,从而确定像素的遮挡关系,保证渲染正确. 模版缓冲(STENCIL_BUFFER)与深度缓冲大小相同,通过设置模版缓冲每个像素的值,我们可以指定在渲染的时候只渲染某些像素,从而可以达到一些特殊的效果. 环境光是一种无处不在的光。环境光源放出的光线被认为来自任何方向。因此,当你仅为场景指定环境光时,所有的物体无论法向量如何,都将表现为同样的明暗程度。 点光源放出的光线来自同一点,且方向辐射自四面八方。 平行光又称镜面光,这种光线是互相平行的。从手电筒、太阳等物体射出的光线都属于平行光。 聚光灯光线从一个锥体中射出,在被照射的物体上产生聚光的效果。使用这种光源需要指定光的射出方向以及锥体的顶角α。*/ #include <iostream>#include <gl\glew.h>#define GLUT_DISABLE_ATEXIT_HACK//若没有这一句会出现无法解析外部符号的错误,在glut.h前加上这一句就正确了#include <glut.h>#pragma comment(lib,"glew32.lib") using namespace std; bool isRotatef[4]; // 控制要旋转的茶壶或旋转视图bool isLightOpen[3]; //定义光源是否打开的bool值 float lightRotatefSpeed = 0; //第一个光源绕三个茶壶的中心旋转的速度(是一个角度)GLfloat LightPosition1[] = {0.0f, 0.0f, 0.0f, 1.0f}; //第一个点光源的位置GLfloat LightPosition2[] = {4.0f, 4.0f, 6.0f, 1.0f}; //第二个点光源的位置GLfloat LightPosition3[] = {-1.0f, 1.0f, 2.0f, 1.0f}; //第三个点光源的位置 static int mousePosX = 0,mousePosY = 0, tempX, tempY; bool isMosDownMove = false;//鼠标移动时的判断变量 struct simpleCamera{ float camera[3]; float lookat[3]; float cam[3];}; simpleCamera camera; void display();void init();void keyboard(unsignedchar key,int x, int y);void motion(int x,int z);void mouse(int button,int state,int x,int z);void reshape(int w,int h);void createLight(); void init(void){ glClearColor(0.7f,0.7f, 0.7f, 0.0f); //用当前的缓冲区清除值清除指定的缓冲区(缓冲区是指一块存储图像信息的存储空间), //GL_COLOR_BUFFER_BIT表示颜色缓冲区,GL_DEPTH_BUFFER_BIT表示深度缓冲区 glClear(GL_COLOR_BUFFER_BIT| GL_DEPTH_BUFFER_BIT); isLightOpen[0] =isLightOpen[1] = isLightOpen[2] = true; //三个光源都开启 glEnable(GL_DEPTH_TEST);//开启深度测试 //检查确定驱动程序的初始化过程中没有出现任何问题 if (GLEW_OK != glewInit()) { cout << "Fail to initialize GLEW!\n"; exit(1); } createLight();//调用createLight函数创建光源 isRotatef[3] = true; //默认移动鼠标旋转整个视图} void createLight(){ glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); GLfloatLightAmbient1[]= { 0.0f, 1.0f, 0.0f, 1.0f }; //环境光参数 GLfloatLightDiffuse1[]= { 0.0f, 1.0f, 0.0f, 1.0f }; //漫射光参数(由参数可知识最亮的漫射光) GLfloatLightSpecular1[]= { 0.0f, 1.0f, 0.0f, 1.0f }; //镜面光参数 //指定光源属性,个参数决定了它所指定的哪个光源的属性、具体的属性以及该属性的预想值 //GL_AMBIENT光的环境强度 //GL_DIFFUSE光的散射强度 //GL_SPECULAR光的镜面强度 glLightfv(GL_LIGHT0,GL_AMBIENT, LightAmbient1); glLightfv(GL_LIGHT0,GL_DIFFUSE, LightDiffuse1); glLightfv(GL_LIGHT0,GL_SPECULAR, LightSpecular1); glEnable(GL_LIGHT1); GLfloatLightAmbient2[] = {1.0f, 0.0f, 0.0f, 1.0f}; GLfloatLightDiffuse2[] = {1.0f, 0.0f, 0.0f, 1.0f}; GLfloatLightSpecular2[]= {1.0f, 0.0f, 0.0f, 1.0f}; glLightfv(GL_LIGHT1,GL_AMBIENT, LightAmbient2); glLightfv(GL_LIGHT1,GL_DIFFUSE, LightDiffuse2); glLightfv(GL_LIGHT1,GL_SPECULAR, LightSpecular2); glEnable(GL_LIGHT2); GLfloatLightAmbient3[] = {0.0f, 0.0f, 1.0f, 1.0f}; GLfloatLightDiffuse3[] = {0.0f, 0.0f, 1.0f, 1.0f}; GLfloatLightSpecular3[]= {0.0f, 0.0f, 1.0f, 1.0f }; glLightfv(GL_LIGHT2,GL_AMBIENT, LightAmbient3); glLightfv(GL_LIGHT2,GL_DIFFUSE, LightDiffuse3); glLightfv(GL_LIGHT2,GL_SPECULAR, LightSpecular3);} void display(void){ glClear(GL_COLOR_BUFFER_BIT| GL_DEPTH_BUFFER_BIT); //进行视图变换前调用下面两个函数,接下来的变换函数将影响模型变换矩阵 //***glMatrixMode():指定哪一个矩阵是当前矩阵。可选值:GL_MODELVIEW、GL_PROJECTION、GL_TEXTURE //GL_MODEVIEW,对模型视图矩阵堆栈应用随后的矩阵操作 //GL_PROJECTION,对投影矩阵应用随后的矩阵操作 //GLTEXTURE,对纹理矩阵堆栈应用随后的矩阵操作 //***glLoadIdentity():该函数的功能是重置当前指定的矩阵为单位矩阵 glMatrixMode(GL_MODELVIEW); glLoadIdentity(); //3组参数:指定了观察点的位置,定义照相机瞄准的参考点,提示哪个方向是朝上的(个为一组) //设置照相机的位置 gluLookAt(camera.camera[0],camera.camera[1], camera.camera[2], camera.lookat[0], camera.lookat[1],camera.lookat[2], 0, 1, 0); //通过平移与旋转按照预想的方式移动观察点 glTranslatef(camera.cam[0],camera.cam[1],camera.cam[2]); /*****************************************光源1*****************************************************/ //处理绕三个茶壶的中心旋转的点光源 //通过压栈操作存储一个状态,然后通过出栈操作恢复这个状态 glPushMatrix(); //以下三句表示光源在z轴的.0f范围内和x轴.0f的范围内以lightRotatefSpeed的角度变化的速度移动 glTranslatef(0.0f,0.0f, 6.0f);//将一个矩阵与当前矩阵相乘,以便将物体(或局部坐标系)平移x,y和z指定的距离 glRotatef((GLfloat)lightRotatefSpeed,0.0, 1.0, 0.0);//旋转轴经过原点,方向为(x,y,z),旋转角度为lightRotatefSpeed,方向满足右手定则 glTranslatef(6.0f,0.0f, 0.0f); glDisable(GL_LIGHTING); //使用glColor3f需要禁用光照 if (isLightOpen[0]) { glColor3f(1.0f,1.0f, 1.0f); } else { glColor3f(0.0f,0.0f, 0.0f); } //用于渲染一个球体函数原型voidglutSolidSphere(GLdouble radius , GLint slices , GLint stacks); //radius球体的半径 //slices以Z轴上线段为直径分布的圆周线的条数(将Z轴看成地球的地轴,类似于经线) //stacks围绕在Z轴周围的线的条数(类似于地球上纬线) //一般而言,后两个参数赋予较大的值,渲染花费的时间要长,效果更逼真 glutSolidSphere(0.2,100.0, 100.0); glEnable(GL_LIGHTING); //GL_POSITION表示光源位置坐标 glLightfv(GL_LIGHT0,GL_POSITION, LightPosition1); //光源绕中心旋转,设在世界坐标系 lightRotatefSpeed +=0.4f; //固定的一个速度 if (lightRotatefSpeed > 360) //角度大于则把角度设为 { lightRotatefSpeed = 0; } glPopMatrix(); /******************************************光源2************************************************/ //复制一份当前矩阵,并把这份复制添加到堆栈的顶部(记住自己的位置) glPushMatrix(); glTranslatef(LightPosition2[0],LightPosition2[1], LightPosition2[2]); glDisable(GL_LIGHTING); //使用glColor3f需要禁用光照 if (isLightOpen[1]) { glColor3f(1.0f,1.0f, 1.0f); //打开时颜色变亮 } else { glColor3f(0.0f,0.0f, 0.0f); //关闭时颜色变暗 } glutSolidSphere(0.2,100.0, 100.0); glEnable(GL_LIGHTING); glLightfv(GL_LIGHT1, GL_POSITION, LightPosition2); //光源设在观察坐标系 glPopMatrix(); //丢弃堆栈顶部的那个矩阵(回到原来的位置) if (isRotatef[3]) //判断是否需要旋转视图 { glRotatef((GLfloat)mousePosX, -1.0, 0.0, 0.0); glRotatef((GLfloat)mousePosY, 0.0, -1.0, 0.0); } /**********************茶壶1,光源3的坐标设置在茶壶的坐标系中**************************/ glPushMatrix(); glTranslatef(-4.0f,0.0f, 4.0f); if (isRotatef[0]) //判断是否旋转 { glRotatef((GLfloat)mousePosX, -1.0, 0.0, 0.0); glRotatef((GLfloat)mousePosY, 0.0, -1.0, 0.0); } glutSolidTeapot(1.0);//显示一个茶壶,参数为茶壶的大小 glTranslatef(LightPosition3[0],LightPosition3[1], LightPosition3[2]); //把局部坐标系移动到需要放点光源的地方 glDisable(GL_LIGHTING); //使用glColor3f需要禁用光照 if (isLightOpen[2]) { glColor3f(1.0f,1.0f, 1.0f); } else { glColor3f(0.0f,0.0f, 0.0f); } glutSolidSphere(0.2,100.0, 100.0); glEnable(GL_LIGHTING); glLightfv(GL_LIGHT2,GL_POSITION, LightPosition3); //光源的坐标设置在茶壶的坐标系中 glPopMatrix(); /*************************************茶壶2**************************************************/ glPushMatrix(); glTranslatef(0.0f,3.0f, 4.0f); if (isRotatef[1]) //判断是否旋转 { glRotatef((GLfloat)mousePosX, -1.0, 0.0, 0.0); glRotatef((GLfloat)mousePosY, 0.0, -1.0, 0.0); } glutSolidTeapot(1.0); glPopMatrix(); /********************************茶壶3*****************************************************/ glPushMatrix(); glTranslatef(4.0f,0.0f, 4.0f); if (isRotatef[2]) //判断是否需要旋转 { glRotatef((GLfloat)mousePosX, -1.0, 0.0, 0.0); glRotatef((GLfloat)mousePosY, 0.0, -1.0, 0.0); } glutSolidTeapot(1.0); glPopMatrix(); glutSwapBuffers();//刷新缓冲区} void reshape(int w,int h){ float aspect = (float)w/((h)?h:1);//平截头体的纵横比,也就是宽度除以高度,(h)?h:1意思是若h=0,则h=1 glViewport(0,0, w,h); //进行投影变换前调用下面两个函数,接下来的变换函数将影响投影矩阵 //在窗口改变函数reshape中先用glMatrixMode(GL_PROJECTION)定义视锥,再用glMatrixMode(GL_MODELVIEW)改为模型变换 glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(45.0f,aspect, 1.0f, 100.0f);// glViewport(0,0,w,h); glMatrixMode(GL_MODELVIEW);} void keyboard(unsignedchar key,int x, int y){ switch (key) { case 'w': camera.cam[1] +=0.1;//向上 break; case 's': camera.cam[1] -=0.1;//向下 break; case 'a': camera.cam[0] -=0.1;//向左 break; case 'd': camera.cam[0] +=0.1;//向右 break; case 'r': camera.cam[2] +=0.2;//放大视图(向外) break; case 'f': camera.cam[2] -=0.2;//缩小视图(向内) break; case 'm': lightRotatefSpeed+= 5.0f;//加快光源的速度 break; case 'n': lightRotatefSpeed-= 5.05f; break; case '1': //鼠标控制茶壶旋转 (光源会跟着旋转) isRotatef[0] = true; isRotatef[1] =isRotatef[2] = isRotatef[3] =false; break; case '2': //鼠标控制茶壶旋转 isRotatef[1] = true; isRotatef[0] =isRotatef[2] = isRotatef[3] = false; break; case '3': //鼠标控制茶壶旋转 isRotatef[2] = true; isRotatef[0] =isRotatef[1] = isRotatef[3] = false; break; case '4': //鼠标控制整个视图旋转(光源不会跟着旋转) isRotatef[3] = true; isRotatef[0] =isRotatef[1] = isRotatef[2] = false; break; case '5': //清除所做的任何旋转和缩放 camera.cam[0] =camera.cam[1] = camera.cam[2] = 0.0f; tempX = 0; tempY = 0; mousePosY = 0; mousePosX = 0; break; case 'i': //打开/关闭0号光源 isLightOpen[0] =!isLightOpen[0]; if (!isLightOpen[0]) { glDisable(GL_LIGHT0); } else { glEnable(GL_LIGHT0); } break; case 'o': //打开/关闭1号光源 isLightOpen[1] =!isLightOpen[1]; if (!isLightOpen[1]) { glDisable(GL_LIGHT1); } else { glEnable(GL_LIGHT1); } break; case 'p': //打开/关闭2号光源 isLightOpen[2] =!isLightOpen[2]; if (!isLightOpen[2]) { glDisable(GL_LIGHT2); } else { glEnable(GL_LIGHT2); } break; case 27: //退出程序 exit(0); break; }} void mouse(int button,int state,int x,int y){ switch(button) { case GLUT_LEFT_BUTTON: if (state == GLUT_DOWN) { tempX = x; tempY = y; isMosDownMove = true; //鼠标移动时需要用到的判断变量 } else { isMosDownMove = false; } break; }} void motion(int x,int y){ if(isMosDownMove) { mousePosY =(mousePosY + (x - tempX))%360; mousePosX =(mousePosX + (y - tempY))%360; tempX = x; tempY = y; } glutPostRedisplay();} void animate(void){ //刷新屏幕 glutPostRedisplay();} int main(int argc,char* argv[]){ //定义刚开始时观察点的位置 camera.camera[0] =0.0f; camera.camera[1] =0.0f; camera.camera[2] =20.0f; //平移观察点时的变量参数 camera.cam[0] =camera.cam[1] = camera.cam[2] = 0.0f; //相机瞄准的参考点的参数 camera.lookat[0] =0.0f-camera.camera[0]; camera.lookat[1] =0.0f-camera.camera[1]; camera.lookat[2] =20.0f-camera.camera[2]; glutInit(&argc,argv); //双缓冲窗口是指绘图命令实际上在离屏缓冲区执行的,然后迅速转换成窗口视图 //申请一个颜色缓冲区和一个深度缓冲区 glutInitDisplayMode(GLUT_DOUBLE| GLUT_DEPTH | GLUT_RGB); glutInitWindowSize(800,600); glutInitWindowPosition(100,100); glutCreateWindow("Teaports"); init(); glutDisplayFunc(display); glutReshapeFunc(reshape); glutKeyboardFunc(keyboard); glutMouseFunc(mouse); glutMotionFunc(motion); glutIdleFunc(animate); glutMainLoop(); return 0;}
运行结果:
0 0
- OpenGL学习记录3
- OpenGL学习问题记录
- OpenGL学习记录1
- OpenGL学习记录2
- OpenGL学习记录4
- OpenGL学习记录5
- OpenGL学习记录6
- OpenGL学习记录7
- OpenGL入门学习记录
- OpenGL学习记录(1)
- 我的OpenGL学习记录1
- OpenGL学习记录——旋转矩形
- 画个三角形-----------openGL学习记录
- OPENGL记录
- OpenGL学习3
- opengl学习笔记(3)
- openGL学习笔记3
- OpenGL学习(3)
- 创业如创作,保持热爱
- 程序员智力题
- Eclipse快捷键大全
- arm B和BL指令浅析
- MYSQL主从配置【一台主机多个实例的主从配置】
- OpenGL学习记录3
- 移动硬盘分区后丢失数据如何恢复
- 用Java写日历(万年历)程序要用到一个类文件,里面有很多
- Selenium私房菜系列5 -- 第一个Selenium RC测试案例
- iOS 多层级的immutable objects 转换成 mutable objects
- ubuntu操作系统下面给eclipse安装 adt
- hdu4339之树状数组+二分
- opendaylight+mininet实验环境搭建工作总结
- Unity3D中制作一个GUI对话框界面