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
原创粉丝点击