实验三 光照与材质处理实验
实验项目性质:设计性实验
所属课程名称:3D游戏图形学
实验计划学时:3学时
- 实验目的和要求
了解简单光照明模型的基本原理,利用VS+OpenGL实现物体的光照和材质处理。
- 实验原理
- 光照模型
当光照射到一个物体表面上时,会出现三种情形。首先,光可以通过物体表面向空间反射,产生反射光;其次,对于透明物体,光可以穿透该物体并从另一端射出,产生透射光;最后,部分光被物体表面吸收而转换成热。在上述三部分光中,仅仅是透射光和反射光能够进入人眼产生视觉效果。此外,物体本身还有可能发光。这里我们暂时不考虑透明物体,这样场景中可能存在以下几种类型的光,即环境光、散射光、镜面光和辐射光。
1)环境光(Ambient Light)
环境光有光源,但是由于被周围的环境,如地面、天空、墙壁等多次反射,变得无法确定其方向。环境光均匀地从周围环境入射至景物表面并等量地向各个方向反射出去。一般说来,房间里的环境光成分要多些,户外的相反要少得多,因为大部分光按相同的方向照射,而在户外很少有其他物体反射的光。
2)漫反射光(Diffuse Light)
漫反射光来自某个方向,它垂直于物体时比倾斜时更明亮。一旦它照射到物体上,则在各个方向上均匀地发散出去。于是,无论视点在哪里它都一样亮。来自特定位置和特定方向的任何光,都可能有散射成分。
3)镜面光(Specular Light)
镜面光也具有方向性,但被物体强烈地反射到另一个特定的方向。如一个点光源照射一个金属球时会在球面上形成一块特别亮的区域,呈现所谓“高光(Highlight)”,它是光源在金属球面上产生的镜面反射光。对于较光滑物体,其镜面反射光的高光区域小而亮;相反,粗糙表面的镜面反射光呈发散状态,其高光区域大而不亮。
4)辐射光
辐射光是最简单的一种光,它直接从物体发出并且不受任何光源影响。在OpenGL 中,任何一种光源都由三种光照成分组成:环境光、漫反射光和镜面光,当然光源本身还有可能发出辐射光。由于我们知道光是一种波,而颜色仅仅是我们可以看见的一种光波,所以每种光照成分都是由RGBA 值定义的。
- 材质属性
当我们使用光照来描述多边形,总是说它由具有某些反射属性的材质组成,而不说它具有特殊的颜色。这样我们指定物体的颜色,就必须指定物体材质对环境光、漫射光和镜面光源的反射属性。通常,我们用材质对光的红、绿、蓝三原色的反射率来近似定义材质属性。像光源一样,材质颜色也分成环境、漫反射和镜面反射成分,它们决定了材质对环境光、漫反射光和镜面反射光的反射程度。
在进行光照计算时,物体的最终颜色是由其材质属性的RGB 值 和光照属性的RGB 值共同决定的。例如,如果当前的环境光源的RGB 值为(0.5,1.0,0.5),而物体的材质的环境反射成分的RGB 值为(0.5,0.5,0.5),那么物体最终的颜色为:
(0.5×0.5,1.0×0.5,0.5×0.5)=(0.25,0.5,0.25)
即将每个环境光源的成分与材质的环境反射率相乘。这样,物体表面的颜色为三项RGB值的叠加:材质对环境光的反射率与环境光结合的RGB 值;材质对漫反射光的反射率与漫反射光结合的RGB 值;材质对镜面光的反射率与镜面反射光结合的RGB 值。注意,当叠加的RGB 中任何一个颜色分量的值大于1.0,那么就用1.0 计算。
- 实验内容
- 对实验二绘制的椅子增加光照效果,设置不同的光源,包括环境光、点光源(聚光灯)、方向光源,使椅子具有多种彩色光影。
- 除了环境光,保留一个点光源,点光源用小球来表示,使其围绕椅子旋转(椅子不要旋转),呈现在不同位置照射椅子的效果。
参考代码: spmulight
- 实验设计思路
1. 创建一个OpenGL工程,对实验二中绘制的椅子进行材质与灯光的添加,主要参考代码为spmulight, 此时是灯光光源位置不变,椅子在空间中旋转,会使得椅子具有彩色光影。
2. 与1相比是将光源使其围绕椅子旋转,使用上述代码进行修改,对display函数进行光源的移动与旋转,使光源围绕椅子得到照射椅子后的不同效果。
- 实验代码
1.
#include <GL/glut.h> #include <stdlib.h> float size = 0.25; //缩放 void myinit(void); void myReshape(int width, int height); void display(void); static GLfloat spin = 0.0; // 初始化材质特性、 光源、 光照模型和深度缓冲区 void myinit(void) { glClearColor(0.0f, 0.0f, 0.0f, 0.0f); glShadeModel(GL_SMOOTH); glEnable(GL_DEPTH_TEST); GLfloat mat_ambient[] = { 0.2, 0.2, 0.2, 1.0 }; GLfloat mat_diffuse[] = { 0.8, 0.8, 0.8, 1.0 }; GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 }; GLfloat mat_shininess[] = { 50.0 }; GLfloat light0_diffuse[] = { 1.0, 1.0, 1.0, 1.0 }; GLfloat light0_position[] = { 1.0, 1.0, 1.0, 0.0 }; GLfloat light1_ambient[] = { 0.2, 0.2, 0.2, 1.0 }; GLfloat light1_diffuse[] = { 1.0, 0.0, 0.0, 1.0 }; GLfloat light1_specular[] = { 1.0, 0.6, 0.6, 1.0 }; GLfloat light1_position[] = { -3.0, -3.0, 3.0, 1.0 }; GLfloat spot_direction[] = { 3.0, 3.0, -3.0 }; glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient); glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular); glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess); glLightfv(GL_LIGHT0, GL_DIFFUSE, light0_diffuse); glLightfv(GL_LIGHT0, GL_POSITION, light0_position); glLightfv(GL_LIGHT1, GL_AMBIENT, light1_ambient); glLightfv(GL_LIGHT1, GL_DIFFUSE, light1_diffuse); glLightfv(GL_LIGHT1, GL_SPECULAR, light1_specular); glLightfv(GL_LIGHT1, GL_POSITION, light1_position); glLightf(GL_LIGHT1, GL_SPOT_CUTOFF, 30.0); glLightfv(GL_LIGHT1, GL_SPOT_DIRECTION, spot_direction); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glEnable(GL_LIGHT1); glDepthFunc(GL_LESS); glEnable(GL_DEPTH_TEST); } void Draw_Leg() // This function draws one of the table leg { //绘制一个桌子腿 glPushMatrix(); glScalef(1.0f, 1.0f, 3.0f); glutSolidCube(1.0 * size); glPopMatrix(); } void Draw_Table() // This function draws a Table { glPushMatrix(); //将当前矩阵保存入堆栈顶(保存当前矩阵)。 glScalef(5.0f, 4.0f, 1.0f); //缩放函数 glColor3f(1.0, 0.0, 1.0); glutSolidCube(1 * size); //绘制线立方体 glPopMatrix(); //pop出来 glPushMatrix(); //将当前矩阵保存入堆栈顶(保存当前矩阵)。 glScalef(4.0f, 1.0f, 4.0f); //缩放函数 glTranslatef(0.0 * size, 1.5 * size, 0.5 * size); glColor3f(0.0, 0.0, 1.0); glutSolidCube(1 * size); //绘制线立方体 glPopMatrix(); //pop出来 glPushMatrix(); //左下角的柱子 glTranslatef(-1.5 * size, -1 * size, -1.5 * size); //尺寸是相对于中心的坐标原点,按照实验指导上的大小进行的 Draw_Leg(); glPopMatrix(); glPushMatrix(); //右下角的柱子 glTranslatef(1.5 * size, -1 * size, -1.5 * size); Draw_Leg(); glPopMatrix(); glPushMatrix(); //右上角的柱子 glTranslatef(1.5 * size, 1 * size, -1.5 * size); Draw_Leg(); glPopMatrix(); glPushMatrix(); //左上角的柱子 glTranslatef(-1.5 * size, 1 * size, -1.5 * size); Draw_Leg(); glPopMatrix(); } void display(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glPushMatrix(); glTranslated(-3.0f, -1.0f, -9.0f); glScalef(0.3, 0.3, 0.3); glDisable(GL_LIGHTING); glColor3f(0.8, 0.8, 0.8); glutSolidSphere(0.5f, 50.0f, 50.0f); glEnable(GL_LIGHTING); glPopMatrix(); glPushMatrix(); glLoadIdentity(); glTranslatef(1.0f, 0.0f, -6.0f); glRotatef(spin, 0.0, 5.0, 0.0); glColor3f(0.0f, 1.0f, 1.0f); Draw_Table(); glPopMatrix(); glEnd(); glutSwapBuffers(); //交换双缓存 glFlush(); } void myReshape(int width, int height) { glViewport(0, 0, width, height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(45.0f, (GLfloat)width / (GLfloat)height, 0.1f, 100.0f); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } void keyboard(unsigned char key, int x, int y) { switch (key) { case' x': exit(0); break; default: break; } } void spinDisplay(void) { spin = spin + 0.05; if (spin > 360.0) spin = spin - 360.0; glutPostRedisplay(); } void mouse(int button, int state, int x, int y) { switch (button) { case GLUT_LEFT_BUTTON: if (state == GLUT_DOWN) glutIdleFunc(spinDisplay); //设备空闲时调用的函数 break; case GLUT_MIDDLE_BUTTON: case GLUT_RIGHT_BUTTON: if (state == GLUT_DOWN) glutIdleFunc(NULL); break; default: break; } } // 主函数, 初始化窗口大小、 RGBA 显示模式和处理输入事件 int main(int argc, char* argv[]) { glutInit(&argc, argv); //glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB) ; glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); //使用双缓存模式 glutInitWindowSize(640, 480); glutInitWindowPosition(0, 0); glutCreateWindow("位置光源和多光源演示"); glutReshapeFunc(myReshape); glutDisplayFunc(display); myinit(); glutMouseFunc(mouse); glutKeyboardFunc(keyboard); glutMainLoop(); return 0; }
2.
#include <GL/glut.h> #include <stdlib.h> float size = 0.25; //缩放 void myinit(void); void myReshape(int width, int height); void display(void); static GLfloat spin = 0.0; static GLfloat i = 0.0; // 初始化材质特性、 光源、 光照模型和深度缓冲区 void myinit(void) { glClearColor(0.0f, 0.0f, 0.0f, 0.0f); glShadeModel(GL_SMOOTH); glEnable(GL_DEPTH_TEST); GLfloat mat_ambient[] = { 0.2, 0.2, 0.2, 1.0 }; GLfloat mat_diffuse[] = { 0.8, 0.8, 0.8, 1.0 }; GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 }; GLfloat mat_shininess[] = { 50.0 }; GLfloat light0_diffuse[] = { 1.0, 1.0, 1.0, 1.0 }; GLfloat light0_position[] = { 1.0, 1.0, 1.0, 0.0 }; GLfloat light1_ambient[] = { 0.2, 0.2, 0.2, 1.0 }; GLfloat light1_diffuse[] = { 1.0, 0.0, 0.0, 1.0 }; GLfloat light1_specular[] = { 1.0, 0.6, 0.6, 1.0 }; GLfloat light1_position[] = { -3.0, -3.0, 3.0, 1.0 }; GLfloat spot_direction[] = { -3.0, -1.0, -9.0f }; glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient); glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular); glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess); glLightfv(GL_LIGHT0, GL_DIFFUSE, light0_diffuse); glLightfv(GL_LIGHT0, GL_POSITION, light0_position); glLightfv(GL_LIGHT1, GL_AMBIENT, light1_ambient); glLightfv(GL_LIGHT1, GL_DIFFUSE, light1_diffuse); glLightfv(GL_LIGHT1, GL_SPECULAR, light1_specular); glLightfv(GL_LIGHT1, GL_POSITION, light1_position); glLightfv(GL_LIGHT1, GL_SPOT_DIRECTION, spot_direction); glLightf(GL_LIGHT1, GL_SPOT_CUTOFF, 100.0); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glEnable(GL_LIGHT1); glDepthFunc(GL_LESS); glEnable(GL_DEPTH_TEST); } void Draw_Leg() // This function draws one of the table leg { //绘制一个桌子腿 glPushMatrix(); glScalef(1.0f, 1.0f, 3.0f); glutSolidCube(1.0 * size); glPopMatrix(); } void Draw_Table() // This function draws a Table { glPushMatrix(); //将当前矩阵保存入堆栈顶(保存当前矩阵)。 glScalef(5.0f, 4.0f, 1.0f); //缩放函数 glColor3f(1.0, 0.0, 1.0); glutSolidCube(1 * size); //绘制线立方体 glPopMatrix(); //pop出来 glPushMatrix(); //将当前矩阵保存入堆栈顶(保存当前矩阵)。 glScalef(4.0f, 1.0f, 4.0f); //缩放函数 glTranslatef(0.0 * size, 1.5 * size, 0.5 * size); glColor3f(0.0, 0.0, 1.0); glutSolidCube(1 * size); //绘制线立方体 glPopMatrix(); //pop出来 glPushMatrix(); //左下角的柱子 glTranslatef(-1.5 * size, -1 * size, -1.5 * size); //尺寸是相对于中心的坐标原点,按照实验指导上的大小进行的 Draw_Leg(); glPopMatrix(); glPushMatrix(); //右下角的柱子 glTranslatef(1.5 * size, -1 * size, -1.5 * size); Draw_Leg(); glPopMatrix(); glPushMatrix(); //右上角的柱子 glTranslatef(1.5 * size, 1 * size, -1.5 * size); Draw_Leg(); glPopMatrix(); glPushMatrix(); //左上角的柱子 glTranslatef(-1.5 * size, 1 * size, -1.5 * size); Draw_Leg(); glPopMatrix(); } void display(void) { GLfloat position[] = { 1.0, 1.0, 1.0, 1.0 }; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glPushMatrix(); glTranslatef(1.0f, 0.0f, -6.0f); glRotated(-90, 1, 0, 0); glRotated(-30, 1, 0 , 0); glColor3f(0.0f, 1.0f, 1.0f); Draw_Table(); glPopMatrix(); glPushMatrix(); glLoadIdentity(); glRotatef(spin, 0.0, 0.0, 5.0); glLightfv(GL_LIGHT0, GL_POSITION, position); glTranslated(-3.0f, -1.0f, -9.0f); glScalef(0.4, 0.4, 0.4); glDisable(GL_LIGHTING); glColor3f(0.8, 0.8, 0.8); glutSolidSphere(0.5f, 50.0f, 50.0f); glEnable(GL_LIGHTING); glPopMatrix(); glEnd(); glutSwapBuffers(); //交换双缓存 glFlush(); } void myReshape(int width, int height) { glViewport(0, 0, width, height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(45.0f,(GLfloat)width / (GLfloat)height, 0.1f, 100.0f); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } void keyboard(unsigned char key,int x,int y){ switch (key) { case'x': exit(0); break; default: break; } } void spinDisplay(void) { spin = spin + 0.1; if (spin > 360.0) spin = spin - 360.0; glutPostRedisplay(); } void mouse(int button, int state, int x,int y){ switch (button) { case GLUT_LEFT_BUTTON: if (state == GLUT_DOWN) glutIdleFunc(spinDisplay); //设备空闲时调用的函数 break; case GLUT_MIDDLE_BUTTON: case GLUT_RIGHT_BUTTON : if (state == GLUT_DOWN) glutIdleFunc(NULL); break; default: break; } } //主函数, 初始化窗口大小、RGBA 显示模式和处理输入事件 int main(int argc, char* argv[]) { glutInit(&argc,argv); //glutIni tDi splayMode (GLUT. SINGLE| GLUT_ RGB); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); //使用双缓存模式 glutInitWindowSize(640,480); glutInitWindowPosition(0, 0); glutCreateWindow("光源围绕椅子"); glutReshapeFunc(myReshape); glutDisplayFunc(display); myinit(); glutMouseFunc(mouse); glutKeyboardFunc(keyboard); glutMainLoop(); return 0; }
- 实验结果及心得体会
1.
编辑编辑
2.
编辑编辑
此次实验,对三维立体图形进行灯光与材质的附加,使得物体更加具有观感,其中,最重要的是对灯光的模拟,例如环境光、镜面光等,对函数进行赋予参数,得到灯光的渲染。通过本次实验,学习了图形学中的灯光和材质的附加过程,收获颇多,对今后本课程的学习有了较大的帮助。