1、首先,光可以通过物体表面向空间反射,产生反射光;其次,对于透明物体,光可以穿透该物体并从另一端射出,产生透射光;最后,部分光被物体表面吸收而转换成热。在上述三部分光中,仅仅是透射光和反射光能够进入人眼产生视觉效果。此外,物体本身还有可能发光,比如发光的灯泡。这里我们暂时不考虑透明物体,这样场景中可能存在以下几种类型的光,即环境光、散射光、镜面光和辐射光。1)环境光(Ambient Light)环境光有光源,但是由于被周围的环境,如地面、天空、墙壁等多次反射,变得无法确定其方向。环境光均匀地从周围环境入射至景物表面并等量地向各个方向反射出去。一般说来,房间里的环境光成分要多些,户外的相反要少得多
2、,因为大部分光按相同的方向照射,而在户外很少有其他物体反射的光。2)漫射光(Diffuse Light)漫射光来自某个方向,它垂直于物体时比倾斜时更明亮。一旦它照射到物体上,则在各个方向上均匀地发散出去。于是,无论视点在哪里它都一样亮。来自特定位置和特定方向的任何光,都可能有散射成分。3)镜面光(Specular Light)镜面光也具有方向性,但被物体强烈地反射到另一个特定的方向。如一个点光源照射一个金属球时会在球面上形成一块特别亮的区域,呈现所谓“高光(Highlight)”,它是光源在金属球面上产生的镜面反射光。对于较光滑物体,其镜面反射光的高光区域小而亮;相反,粗糙表面的镜面反射光呈发
3、散状态,其高光区域大而不亮。4)辐射光辐射光是最简单的一种光,它直接从物体发出并且不受任何光源影响。在OpenGL 中,任何一种光源都由三种光照成分组成:环境光、散射光和镜面光,当然光源本身还有可能发出辐射光。由于我们知道光是一种波,而颜色仅仅是我们可以看见的一种光波,所以每种光照成分都是由RGBA 值定义的。2. 材质属性当我们使用光照来描述多边形,总是说它由具有某些反射属性的材质组成,而不说它具有特殊的颜色。这样我们指定物体的颜色,就必须指定物体材质对环境光、漫射光和镜面光源的反射属性。通常,我们用材质对光的红、绿、蓝三原色的反射率来近似定义材质属性。象光源一样,材质颜色也分成环境、漫反射
4、和镜面反射成分,它们决定了材质对环境光、漫反射光和镜面反射光的反射程度。在进行光照计算时,物体的最终颜色是由其材质属性的RGB 值 和光照属性的RGB 值共同决定的。例如,如果当前的环境光源的RGB 值为(0.5,1.0,0.5),而物体的材质的环境反射成分的RGB 值为(0.5,0.5,0.5),那么物体最终的颜色为:(0.50.5,1.00.5,0.50.5)=(0.25,0.5,0.25)即将每个环境光源的成分与材质的环境反射率相乘。这样,物体表面的颜色为三项RGB值的叠加:材质对环境光的反射率与环境光结合的RGB 值;材质对漫反射光的反射率与漫反射光结合的RGB 值;材质对镜面光的反射
5、率与镜面反射光结合的RGB 值。注意,当叠加的RGB 中任何一个颜色分量的值大于1.0,那么就用1.0 计算。三、 实验内容1. 利用OpenGL函数实现一个简单的光照模型,显示一个具有灰色光影的球。调整球的材质属性,使其呈现不同的颜色。源代码:#include GL/glut.h/ 初始化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 ; GLf
6、loat 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); glLightfv(GL_LIGHT0, GL_AMBIENT, ambient); glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse); glLightfv(GL_LIGHT0,
7、 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_LIGHT0void display(void) GLfloat position=0.0,0.0,1.5,1.0; GLfloat no_mat = 0.0, 0.0, 0.0, 1.0
8、; GLfloat mat_ambient = 0.7, 0.7, 0.7, 1.0 ; GLfloat mat_ambient_color = 0.8, 0.8, 0.2, 1.0 ; GLfloat mat_diffuse = 0.5, 0.5, 0.5, 1.0 ; GLfloat mat_specular = 1.0, 1.0, 1.0, 1.0 ; GLfloat no_shininess = 0.0 ; GLfloat low_shininess = 5.0 ; GLfloat high_shininess = 100.0 ; GLfloat mat_emission = 0.2,
9、 0.2, 0.2, 0.0; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLightfv(GL_LIGHT0,GL_POSITION,position); glPushMatrix(); glTranslatef (0.0, 0.0, 0.0); glMaterialfv(GL_FRONT, GL_AMBIENT, no_mat); /环境光 glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse); /漫反射光 glMaterialfv(GL_FRONT, GL_SPECULAR, no_
10、mat); /镜面光 glMaterialfv(GL_FRONT, GL_SHININESS, no_shininess); /反射 glMaterialfv(GL_FRONT, GL_EMISSION, mat_emission); /自发光 glutSolidSphere(1.0, 16, 16); glPopMatrix(); glFlush();void reshape(int w, int h) glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); if (w void Initial() / 启
11、用深度测试 glClearColor(0.0f, 0.0f, 0.0f, 1.0f ); /背景为白色void ChangeSize(int w, int h) if(h = 0) h = 1; / 设置视区尺寸 / 指定当前操作投影矩阵堆栈 / 重置投影矩阵 GLfloat fAspect; fAspect = (float)w/(float)h; / 计算视区的宽高比 gluPerspective(45.0, fAspect, 1.0, 500.0); / 指定透视投影的观察空间void Display(void) static float fElect1 = 0.0f; / 绕原子旋转的
12、角度 GLfloat mat_diffuse = 0.1, 0.5, 0.8, 1.0 ; GLfloat mat_emission = 0.3, 0.2, 0.2, 0.0; /清除颜色和深度缓冲区 / 指定当前操作模型视图矩阵堆栈 / 重置模型视图矩阵 glTranslatef(0.0f, 0.0f, -250.0f); /将图形沿z轴负向移动/ 绘制圆环 glTranslatef (-3.75, 3.0, 0.0); glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular); glMaterialfv(GL_FRONT, GL_SHININESS
13、, low_shininess); glMaterialfv(GL_FRONT, GL_EMISSION, no_mat); glutSolidTorus (5, 30, 50, 50); / 恢复模型视图矩阵 / 画出旋转球 / 保存当前的模型视图矩阵 glRotatef(-45.0f,0.0f, 0.0f, 1.0f); /绕z轴旋转-45 glRotatef(fElect1, 0.0f, 1.0f, 0.0f); glTranslatef(0.0f, 0.0f, 60.0f); glTranslatef (3.75, -3.0, 0.0); glMaterialfv(GL_FRONT,
14、GL_AMBIENT, mat_ambient_color); glutSolidSphere(6.0f, 15, 15);/开启 fElect1 += 10.0f; / 增加旋转步长,产生动画效果 if(fElect1 360.0f) fElect1 = 10.0f; glutSwapBuffers();void TimerFunc(int value) glutPostRedisplay(); glutTimerFunc(100, TimerFunc, 1);int main(int argc, char* argv) glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); glutCreateWindow(test2); glutReshapeFunc(ChangeSize); glutDisplayFunc(Display); glutTimerFunc(500, TimerFunc, 1); /指定定时器回调函数 Initial();运行结果:
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1