实验报告书
(实验四)
姓名:
学号:
班级:
浙江理工大学
二0一二 年 十二 月
实验四 光照与材质处理
一、实验目的和要求
了解简单光照明模型的基本原理,利用VC++ OpenGL实现物体的光照和材质处理。
2、实验原理
1.光照模型
当光照射到一个物体表面上时,会出现三种情形。首先,光可以通过物体表面向空间反射,产生反射光;其次,对于透明物体,光可以穿透该物体并从另一端射出,产生透射光;最后,部分光被物体表面吸收而转换成热。在上述三部分光中,仅仅是透射光和反射光能够进入人眼产生视觉效果。此外,物体本身还有可能发光,比如发光的灯泡。这里我们暂时不考虑透明物体,这样场景中可能存在以下几种类型的光,即环境光、散射光、镜面光和辐射光。
1)环境光(Ambient Light)
环境光有光源,但是由于被周围的环境,如地面、天空、墙壁等多次反射,变得无法确定其方向。环境光均匀地从周围环境入射至景物表面并等量地向各个方向反射出去。一般说来,房间里的环境光成分要多些,户外的相反要少得多,因为大部分光按相同的方向照射,而在户外很少有其他物体反射的光。
2)漫射光(Diffuse Light)
漫射光来自某个方向,它垂直于物体时比倾斜时更明亮。一旦它照射到物体上,则在各个方向上均匀地发散出去。于是,无论视点在哪里它都一样亮。来自特定位置和特定方向的任何光,都可能有散射成分。
3)镜面光(Specular Light)
镜面光也具有方向性,但被物体强烈地反射到另一个特定的方向。如一个点光源照射一个金属球时会在球面上形成一块特别亮的区域,呈现所谓“高光(Highlight)”,它是光源在金属球面上产生的镜面反射光。对于较光滑物体,其镜面反射光的高光区域小而亮;相反,粗糙表面的镜面反射光呈发散状态,其高光区域大而不亮。
4)辐射光
辐射光是最简单的一种光,它直接从物体发出并且不受任何光源影响。在OpenGL 中,任何一种光源都由三种光照成分组成:环境光、散射光和镜面光,当然光源本身还有可能发出辐射光。由于我们知道光是一种波,而颜色仅仅是我们可以看见的一种光波,所以每种光照成分都是由RGBA 值定义的。
2.材质属性
当我们使用光照来描述多边形,总是说它由具有某些反射属性的材质组成,而不说它具有特殊的颜色。这样我们指定物体的颜色,就必须指定物体材质对环境光、漫射光和镜面光源的反射属性。通常,我们用材质对光的红、绿、蓝三原色的反射率来近似定义材质属性。象光源一样,材质颜色也分成环境、漫反射和镜面反射成分,它们决定了材质对环境光、漫反射光和镜面反射光的反射程度。
在进行光照计算时,物体的最终颜色是由其材质属性的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 计算。
3、实验内容
1.利用OpenGL函数实现一个简单的光照模型,显示一个具有灰色光影的球。调整球的材质属性,使其呈现不同的颜色。
2.绘制一个会移动的光源,要求光源用一个球来表示,使其围绕一个三维圆环旋转,呈现在不同位置照射圆环的效果。
绘制三维圆环的函数
glutSolidTorus(GLdouble innerRadius, GLdouble outerRadius,
GLint nsides, GLint rings);
glutWireTorus(GLdouble innerRadius,GLdouble outerRadius,
GLint nsides, GLint rings);
innerRadius Inner radius of the torus.
outerRadius Outer radius of the torus.
nsides Number of sides for each radial section.
rings Number of radial divisions for the torus.
例:glutSolidTorus (0.275, 0.85, 50, 50);
选做题:利用双缓存法在屏幕上显示一个不断旋转和由小到大变化的五彩立方体。
4、实验代码
1、利用OpenGL函数实现一个简单的光照模型,显示一个具有灰色光影的球。调整球的材质属性,使其呈现不同的颜色。
// 本程序演示了如何使用光照和材质
#include #include float spin=0.0; // 初始化z缓冲区,投影矩阵,光源和光照模型 void init(void) { GLfloat ambient[] = { 0.0, 0.0, 0.0, 1.0 };//环境光强度 GLfloat diffuse[] = { 1.0, 1.0, 1.0, 1.0 }; //漫射光的反射系数 GLfloat specular[] = { 1.0, 1.0, 1.0, 1.0 }; //镜面光的反射系数 GLfloat position[] = { 0.0, 3.0, 2.0, 0.0 };//光源位置 GLfloat lmodel_ambient[] = { 0.4, 0.4, 0.4, 1.0 };//全局环境光强度 GLfloat local_view[] = { 0.0 }; glClearColor(0.0, 0.1, 0.1, 0.0);//清空颜色 glEnable(GL_DEPTH_TEST);//启用深度测试 glShadeModel(GL_SMOOTH); //使用光滑着色模式 //指定GL_LIGHT0的相关属性 glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);//光源中的环境光强度 glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);//漫射光的反射系数 glLightfv(GL_LIGHT0, GL_POSITION, position); //指定光源位置 //设置全局环境光 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient); glLightModelfv(GL_LIGHT_MODEL_LOCAL_VIEWER, local_view); glEnable(GL_LIGHTING);//启用光照 glEnable(GL_LIGHT0);//启用光源GL_LIGHT0 } void display(void) { GLfloat no_mat[] = { 0.0, 0.0, 0.0, 1.0 }; //黑色材致或无材致 GLfloat mat_ambient[] = { 0.7, 0.7, 0.7, 1.0 };//物体对环境光的反射因素 GLfloat mat_ambient_color[] = { 0.1+spin*0.1, spin*0.1, 0.2, 1.0 };//颜色每一次调用时发生改变 GLfloat mat_diffuse[] = { 0.3, 0.5+spin*0.03, 0.8+spin, 1.0 };//材质对漫射光的反射系数 GLfloat mat_specular[] = { 0.3+spin, 0.3+spin, 1.0, 1.0 };//材质对镜面光的反射系数 GLfloat no_shininess[] = { 0.0 }; //镜面反射指数为 GLfloat low_shininess[] = { 5.0 }; //镜面反射指数为 GLfloat high_shininess[] = { 100.0 }; //镜面反射指数为 GLfloat mat_emission[] = {0.3, 0.2, 0.2, 0.0};//设置物体对荧光的颜色 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //更新数据 if(spin>=5){spin=0;} else spin=spin+0.5; // 绘制第一行第一列的球体,只有漫反射,没有环境光或镜面反射光 glPushMatrix(); glTranslatef (0.0, 0.0, 0.0); //设置材质 glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient_color); glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular); glMaterialfv(GL_FRONT, GL_SHININESS, high_shininess); glMaterialfv(GL_FRONT, GL_EMISSION, no_mat); glutSolidSphere(1.0, 16, 16); glPopMatrix(); glFlush();//强制刷新缓冲 } void reshape(int w, int h) { glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); if (w <= (h * 2)) glOrtho (-6.0, 6.0, -3.0*((GLfloat)h*2)/(GLfloat)w, 3.0*((GLfloat)h*2)/(GLfloat)w, -10.0, 10.0); else glOrtho (-6.0*(GLfloat)w/((GLfloat)h*2), 6.0*(GLfloat)w/((GLfloat)h*2), -3.0, 3.0, -10.0, 10.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } void keyboard(unsigned char key, int x, int y)//监听 { switch (key) { case 'c': display(); break; } } int main(int argc, char** argv) { glutInit(&argc, argv); glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH); glutInitWindowSize (600, 450); glutCreateWindow(argv[0]); init(); glutReshapeFunc(reshape); glutDisplayFunc(display); glutKeyboardFunc (keyboard); glutMainLoop(); return 0; } 2、绘制一个会移动的光源,要求光源用一个球来表示,使其围绕一个三维圆环旋转,呈现在不同位置照射圆环的效果。 #include #include static int spin = 0; // 初始化z缓冲区,投影矩阵,光源和光照模型 void Init() { glClearColor(0.0, 0.0, 6.0, 0.0);//清除颜色设为蓝色 glShadeModel(GL_SMOOTH); //使用光滑着色模式 glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glEnable(GL_DEPTH_TEST); } void Display() { GLfloat position[] = {0.0, 0.0, 1.5, 1.0};//位置设置 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);//清除当前可写的颜色缓冲和深度缓冲 glPushMatrix();//将当前矩阵堆栈推送 glTranslatef(0.0, 0.0, -5.0);//平移 glPushMatrix();//调用堆栈的顶部矩阵是推送的 将当前矩阵堆栈推送 glRotated((GLdouble)spin, 1.0, 1.0, 0.0); //旋转 glLightfv(GL_LIGHT0,GL_POSITION,position); //指定GL_LIGHT0的位置 glTranslated(0.0, 0.0, 1.5);//平移 glDisable(GL_LIGHTING);//关闭光照效果 glutWireSphere(0.1,50,50);//渲染球体(光源)半径 glEnable(GL_LIGHTING);//开启光照效果 glPopMatrix();//出栈 glutSolidTorus(0.275, 0.85, 8, 60);//绘制圆环 glPopMatrix(); glFlush(); } void Idle()//自动更新达到自动旋转 { spin=(spin+5)%360; glutPostRedisplay(); Sleep(20); } void Reshape(int w, int h) { glViewport(0,0,(GLsizei)w,(GLsizei)h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(40.0, (GLfloat)w/(GLfloat)h, 1.0, 20.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } /* void Mouse(int button,int status,int x,int y) //监听事件 { switch(button) { case GLUT_LEFT_BUTTON: if(status == GLUT_DOWN) { spin = (spin + 10) % 360; glutPostRedisplay(); } break; } default: break; } }*/ int main(int argc,char **argv) { glutInit(&argc,argv); glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH); glutInitWindowSize(500,500); //窗口大小 glutInitWindowPosition(200,200); glutCreateWindow(argv[0]); Init(); glutDisplayFunc(Display); //glutMouseFunc(Mouse); glutReshapeFunc(Reshape); glutIdleFunc(Idle); glutMainLoop(); return 0; } 五、实验结果 1、利用OpenGL函数实现一个简单的光照模型,显示一个具有灰色光影的球。调整球的材质属性,使其呈现不同的颜色。 2、绘制一个会移动的光源,要求光源用一个球来表示,使其围绕一个三维圆环旋转,呈现在不同位置照射圆环的效果。 六、实验心得下载本文