计算机图形学大作业——程序设计用简单光照模型显示一系列小球在不同参数情况下的镜面反射效果学号:08009223 姓名:贺国睿专业:自动化日期:2012.5.261 设计目标和要求•用简单光照模型显示一系列小球在不同参数情况下的镜面反射效果;2 算法原理介绍2.1光源分析在现实生活中的物体,要有光照存在才可以被看到。
物体通过自身发光以及反射光进入人眼,物体才能在人眼中成像。
如果没有任何的光,人眼将观察不到任何东西,一片漆黑。
在光照中首先是光源,要有光源才能产生光线,才有以后的一系列反射、折射、散射等效果。
不同的物体的表面物理属性不同,所以相同的光线照射到不同表面属性的物体表面会产生不同的效果,发生漫反射,镜面反射的比例各不相同,有的属于半透明的物体还有折射效果。
这些不同的物体表面物理属性属于材质的范畴。
除了材质以外,物体表面还有各种图案效果,这就是纹理。
光线在空中穿行的时候,还会有更多复杂的效果。
在现实中,光源的类型很多,而且有的光源不能简单的用一种模型来描述,而是具有多种不同类型光源特点。
几种基本的光源类型是:点光源、无穷远光源、方向光源和环境光。
点光源:光线从光源点向四面八方发散,发光的恒星(如太阳)、发光的灯泡一般使用该光源模型模拟,是最简单的光源。
无穷远光源:所有的光线都平行的从一个方向过来,当发光体(如太阳)离渲染的场景很远可以认为是无穷远时,一般使用该光源模型进行模拟。
方向光源:光线沿着一个方向在特定角度范围内逐渐发散开。
现实世界中的车灯,手电筒一般使用该光源模型进行模拟。
环境光源:光线从各个地方以各个角度投射到场景中所有物体表面,找不到光源的确切位置。
现实世界中不存在这样的光源,一般使用该光源模型来模拟点光源、无穷远光源、方向光源在物体表面经过许多次反射后的情况,环境光源照亮所有物体的所有面。
这四种基本的光源模型,只能近似的描述光源,不可能做到非常逼真。
在现实中,一束光线照射到物体表面发生反射后,再照射到另外的物体的表面,如此循环反复这才是环境光的真正情况。
这个过程是个无限次反射的过程,计算机无法处理无限的问题,所以采取了简单的近似处理。
而且环境光源在反射过程中,上一次反射所带的颜色会影响下次反射所照物体的颜色,并且无限的重复。
光线追踪算法是一种好得多的近似描述,但也仅仅是近似描述,只是近似效果比用环境光源模型要好。
OpenGL还提供了让物体自发光让自己可以被看见的方式。
这就是物体自发光。
物体自发光对于光源十分的重要,比如电灯泡可以看作是一个点光源,我们把点光源的位置设置到灯泡的中央,这样灯泡周围的物体将被照亮,但是灯泡的外表面由于相对光源来说是背面,将不能被照亮。
这与实际情况不符合,灯泡照亮其它物体,而自身却不亮,所以需要通过物体自发光让灯泡的外表面也发亮。
光源的一般属性包括:镜面反射光线颜色、漫反射光颜色、环境光线颜色、光源位置。
镜面反射光颜色:在物体表面将发生镜面反射的光线的颜色。
漫反射光颜色:在物体表面将发生漫反射的光线的颜色。
环境光线颜色:照亮所有物体所有表面的光线的颜色。
光源位置就是光源在场景中所在的位置。
光线的衰减:光源发出的光线的强度会随着传播距离越来越大而变弱(无穷远光源除外)。
光线强度会乘以一个衰减因子。
衰减因子=1/(K1 + K2 * d + k3 *d^2) 其中d为光源距离(无穷远光源的衰减因子为1)方向光源发出的光线会随着偏移中心方向的角度增大而减弱。
2.2 光照中的材质材质是光照效果中的重要属性。
材质描述了物体表面的光学物理属性,决定了光线在该表面光线反射的具体情况。
材质决定了物体的表面特性,决定了光线在物体表面反射的情况。
物体表面的反射分为漫反射和镜面反射。
物体反射各种类型光源的情况都可以分为:漫反射和镜面反射两种。
漫反射:光线射到物体表面以后,反射光线的方向是任意方向的。
漫反射镜面反射:光线射到物体表面以后,反射光线根据照射表面位置的法线方向,发生方向唯一确定的镜面反射。
镜面反射在OpenGL中漫反射部分的光线与镜面反射部分的光线是分开计算的,然后将分开计算的效果进行叠加。
材质的属性包括:镜面反射颜色、漫反射颜色、环境光颜色、光洁度、自发光颜色。
镜面反射颜色、漫反射色、环境光颜色:分别与光源的镜面反射光颜色、光源的漫反射颜色、光源的环境光颜色共同决定物体表面的镜面反射颜色、漫反射颜色、环境光颜色。
3种类型的结果分别计算,然后叠加共同确定反射表面像素值的颜色。
漫反射项:max{L*n,0}×DIFFUSE_light×DIFFUSE_material环境光项:AMBIENT_light×AMBIENT_material在OpenGL中可以使用下面的代码来设置材质属性:GLfloatplanet_ambient[] = { 0.01 , 0.01 , 0.01 , 1.0 };GLfloatplanet_diffuse[] = { 0.7 , 0.7 , 0.7 , 1.0 };glMaterialfv(GL_FRONT , GL_AMBIENT ,planet_ambient);glMaterialfv(GL_FRONT , GL_DIFFUSE ,planet_diffuse);2.3 函数解析//开启光照渲染glEnable(GL_LIGHTING);//设置光源属性GLfloatlight_ambient[] = { 1.0 , 1.0 , 1.0 , 0.0 };GLfloatlight_diffuse[] = { 1.0 , 1.0 , 1.0 , 1.0 };//指定光源的位置GLfloat light _position[] = { 0.0 , 0.0 , 1.0 , 1.0 };//用定义好的光源属性给指定光源GL_LIGHT0进行设置glLightfv(GL_LIGHT0 , GL_AMBIENT , light_ambient);glLightfv(GL_LIGHT0 , GL_DIFFUSE , light_diffuse);glLightfv(GL_LIGHT0 , GL_POSITION , light_position);//开启设置的光源GL_LIGHT0glEnable(GL_LIGHT0);在设置光源的位置的时候需要注意Z轴的正方向是垂直于屏幕向外,当设置Z的值为负值的时候,光源的位置位于屏幕内部;设置Z为正值的时候,光源的位置位于屏幕的外部。
如上面的代码设置的位置是屏幕正中央,垂直于屏幕表面外面1个单位的位置。
我们如果要打开全局光照,也就是在没有指定光源的时候,让场景中的物体也可以被照亮,可以使用下面的代码。
//全局光照系数GLfloatglobel_ambient[] = { 0.0 , 0.0 , 0.0 , 1.0 };//打开全局光照glLightModelfv(GL_LIGHT_MODEL_AMBIENT , globel_ambient);3 程序源代码// heguorui_08009223.cpp : 定义控制台应用程序的入口点。
//#include "stdafx.h"#include <gl/glut.h>GLfloatlight_ambient[] = {0.0f, 0.0f, 0.0f, 1.0f};//留在环境中的光照GLfloatlight_diffuse[] = {1.0f, 1.0f, 1.0f, 1.0f};GLfloatlight_specular[] = {1.0f, 1.0f, 1.0f, 1.0f};GLfloatlight_position[] = {0.0f,-10.0f, 0.0f, 0.0f};//光照位置floatlight_z = 0.0f;floatlight_y = -10.0f;voidinit(void){glClearColor(0.5,0.25,0.25,0.0);glEnable(GL_DEPTH_TEST);glShadeModel(GL_SMOOTH);glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);glLightfv(GL_LIGHT0, GL_POSITION, light_position);glEnable(GL_LIGHT0);glEnable(GL_LIGHTING);}voidmyDisplay(void){if(light_z<10) {light_z+=0.01;} else {light_z-=0.01;}light_y += 0.01;light_position[2] = light_z;light_position[1] = light_y;glLightfv(GL_LIGHT0, GL_POSITION, light_position);glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);/*glPushMatrix();glTranslatef(-3.75,3.0,0.0);glMaterialfv(GL_FRONT, GL_AMBIENT, no_mat);//表示各种光线照射到该材质上,经过很多次反射后最终遗留在环境中的光线强度(颜色)glMaterialfv(GL_FRONT, GL_DIFFUSE, earth_mat_diffuse);//表示光线照射到该材质上,经过漫反射后形成的光线强度(颜色)glMaterialfv(GL_FRONT, GL_SPECULAR, no_mat);//表示光线照射到该材质上,经过镜面反射后形成的光线强度(颜色)。
通常,GL_AMBIENT和GL_DIFFUSE都取相同的值,可以达到比较真实的效果glMaterialfv(GL_FRONT, GL_SHININESS, no_shiniess);//该属性只有一个值,称为“镜面指数”,取值范围是0到128glMaterialfv (GL_FRONT, GL_EMISSION, no_mat);//该属性由四个值组成,表示一种颜色。
OpenGL认为该材质本身就微微的向外发射光线glutSolidSphere(1.0, 64, 64);glPopMatrix();*/GLfloatno_mat[]={0.0,0.0,0.0,1.0};GLfloatmat_ambient[]={0.7,0.7,0.7,1.0};GLfloatmat_ambient_color[]={0.8,0.8,0.2,1.0};GLfloatmat_diffuse[]={0.1,0.5,0.8,1.0};GLfloatmat_specular[]={1.0,1.0,1.0,1.0};GLfloatno_shininess[]={0.0};GLfloatlow_shininess[]={5.0};GLfloathigh_shininess[]={100.0};GLfloatmat_emission[]={0.3,0.2,0.2,0.0};glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);//第一行第一列绘制的球仅有漫反射光而无环境光和镜面光glPushMatrix();glTranslatef(-3.75,3.0,0.0);glMaterialfv(GL_FRONT,GL_AMBIENT,no_mat);glMaterialfv(GL_FRONT,GL_SPECULAR,no_mat);glMaterialfv(GL_FRONT,GL_SHININESS,no_shininess);glMaterialfv(GL_FRONT,GL_EMISSION,no_mat);glutSolidSphere(1.0, 64, 64);glPopMatrix();//第一行第二列绘制的球有漫反射光和镜面光并有低高光,而无环境光glPushMatrix();glTranslatef(-1.25,3.0,0.0);glMaterialfv(GL_FRONT,GL_AMBIENT,no_mat);glMaterialfv(GL_FRONT,GL_DIFFUSE,mat_diffuse);glMaterialfv(GL_FRONT,GL_SPECULAR,mat_specular);glMaterialfv(GL_FRONT,GL_SHININESS,low_shininess);glMaterialfv(GL_FRONT,GL_EMISSION,no_mat);glutSolidSphere(1.0, 64, 64);glPopMatrix();//第一行第三列绘制的球有漫反射光和镜面光,并有很亮的高光,而无环境光glPushMatrix();glTranslatef(1.25,3.0,0.0);glMaterialfv(GL_FRONT,GL_AMBIENT,no_mat);glMaterialfv(GL_FRONT,GL_DIFFUSE,mat_diffuse);glMaterialfv(GL_FRONT,GL_SPECULAR,no_mat);glMaterialfv(GL_FRONT,GL_SHININESS,no_shininess);glMaterialfv(GL_FRONT,GL_EMISSION,mat_emission);glutSolidSphere(1.0, 64, 64);glPopMatrix();//第一行第四列绘制的球有漫反射光和辐射光,而无环境和镜面反射光glPushMatrix();glTranslatef(3.75,3.0,0.0);glMaterialfv(GL_FRONT,GL_AMBIENT,no_mat);glMaterialfv(GL_FRONT,GL_DIFFUSE,mat_diffuse);glMaterialfv(GL_FRONT,GL_SPECULAR,no_mat);glMaterialfv(GL_FRONT,GL_SHININESS,no_shininess);glMaterialfv(GL_FRONT,GL_EMISSION,mat_emission);glutSolidSphere(1.0, 64, 64);glPopMatrix();//第二行第一列绘制的球有漫反射光和环境光,而无镜面反射光glPushMatrix();glTranslatef(-3.75,0.0,0.0);glMaterialfv(GL_FRONT,GL_DIFFUSE,mat_diffuse);glMaterialfv(GL_FRONT,GL_SPECULAR,no_mat);glMaterialfv(GL_FRONT,GL_SHININESS,no_shininess);glMaterialfv(GL_FRONT,GL_EMISSION,no_mat);glutSolidSphere(1.0, 64, 64);glPopMatrix();//第二行第二列绘制的球有漫反射光,环境光和镜面光,且有低高光glPushMatrix();glTranslatef(-1.25,0.0,0.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,low_shininess);glMaterialfv(GL_FRONT,GL_EMISSION,no_mat);glutSolidSphere(1.0, 64, 64);glPopMatrix();//第二行第三列绘制的球有漫射光,环境光和镜面光,且有很亮的高光glPushMatrix();glTranslatef(1.25,0.0,0.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,high_shininess);glMaterialfv(GL_FRONT,GL_EMISSION,no_mat);glutSolidSphere(1.0, 64, 64);glPopMatrix();//第二行第四列绘制的球有漫反射光,环境光和辐射光,而无镜面光glPushMatrix();glTranslatef(3.75,0.0,0.0);glMaterialfv(GL_FRONT,GL_AMBIENT,mat_ambient);glMaterialfv(GL_FRONT,GL_DIFFUSE,mat_diffuse);glMaterialfv(GL_FRONT,GL_SPECULAR,no_mat);glMaterialfv(GL_FRONT,GL_SHININESS,no_shininess);glMaterialfv(GL_FRONT,GL_EMISSION,mat_emission);glutSolidSphere(1.0, 64, 64);glPopMatrix();//第三行第一列绘制的球有漫反射光和有颜色的环境光,而无镜面光glPushMatrix();glTranslatef(-3.75,-3.0,0.0);glMaterialfv(GL_FRONT,GL_AMBIENT,mat_ambient_color);glMaterialfv(GL_FRONT,GL_DIFFUSE,mat_diffuse);glMaterialfv(GL_FRONT,GL_SPECULAR,no_mat);glMaterialfv(GL_FRONT,GL_SHININESS,no_shininess);glMaterialfv(GL_FRONT,GL_EMISSION,no_mat);glutSolidSphere(1.0, 64, 64);glPopMatrix();//第三行第二列绘制的球有漫反射光和有颜色的环境光以及镜面光,且有低高光glPushMatrix();glTranslatef(-1.25,-3.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,low_shininess);glMaterialfv(GL_FRONT,GL_EMISSION,no_mat);glutSolidSphere(1.0, 64, 64);glPopMatrix();//第三行第三列绘制的球有漫反射光和有颜色的环境光以及镜面光,且有很亮的高光glPushMatrix();glTranslatef(1.25,-3.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, 64, 64);glPopMatrix();//第三行第四列绘制的球有漫反射光和有颜色的环境光以及辐射光,而无镜面光glPushMatrix();glTranslatef(3.75,-3.0,0.0);glMaterialfv(GL_FRONT,GL_AMBIENT,mat_ambient_color);glMaterialfv(GL_FRONT,GL_DIFFUSE,mat_diffuse);glMaterialfv(GL_FRONT,GL_SPECULAR,no_mat);glMaterialfv(GL_FRONT,GL_SHININESS,no_shininess);glMaterialfv(GL_FRONT,GL_EMISSION,mat_emission);glutSolidSphere(1.0, 64, 64);glPopMatrix();glFlush();glFlush();}voidTimerFunc(int value){glutPostRedisplay();glutTimerFunc(value, TimerFunc, 1);}voidmyReshape(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);elseglOrtho(-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 main(intargc, char* argv[]){glutInit(&argc, argv);glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE | GLUT_DEPTH);glutInitWindowPosition(0, 0);glutInitWindowSize(1000, 700);glutCreateWindow("简单光照模型显示一系列小球在不同参数情况下的镜面反射效果08009223 贺国睿");init();glutReshapeFunc(myReshape);glutDisplayFunc(&myDisplay);glutTimerFunc(250, TimerFunc, 1);glutMainLoop();}4 程序运行结果抓图第一行第一列绘制的球仅有漫反射光而无环境光和镜面光第一行第二列绘制的球有漫反射光和镜面光并有低高光,而无环境光第一行第三列绘制的球有漫反射光和镜面光,并有很亮的高光,而无环境光第一行第四列绘制的球有漫反射光和辐射光,而无环境和镜面反射光第二行第一列绘制的球有漫反射光和环境光,而无镜面反射光第二行第二列绘制的球有漫反射光,环境光和镜面光,且有低高光第二行第三列绘制的球有漫射光,环境光和镜面光,且有很亮的高光第二行第四列绘制的球有漫反射光,环境光和辐射光,而无镜面光第三行第一列绘制的球有漫反射光和有颜色的环境光,而无镜面光第三行第二列绘制的球有漫反射光和有颜色的环境光以及镜面光,且有低高光第三行第三列绘制的球有漫反射光和有颜色的环境光以及镜面光,且有很亮的高光第三行第四列绘制的球有漫反射光和有颜色的环境光以及辐射光,而无镜面光移动光源下的效果图,光源从最下方移动到最上方(定时,循环上移光源即可)5 参考文献[1] 《OpenGL编程指南》,Dave Shreiner,出版社:机械工业出版社[2] /fcl06/item/ac66f033a240a884c2cf299d , OpenGL的光照详解6 学习体会计算机图形学是一门很博大的学问。