游戏开发者OpenGL

OpenGL光源光照基础

2015-03-13  本文已影响3024人  Beatrice7

光照模型

在OpenGL光照模型中,除非一个物体自己会发光,否则它将受到3种不同类型的光的照射:环境光(ambient)、散射光(diffuse)和镜面光(specular)。

光源与材料

光源

OpenGL可以同时为我们提供8个有效的光源。也就是说,我们最多可以同时启用8个光源。它们分别是GL_LIGHT0,GL_LIGHT1,GL_LIGHT2 ……
其中,GL_LIGHT0是最特殊的一个光源,我们可以为GL_LIGHT0指定环境光成分。在默认情况下,GL_LIGHT0光源的颜色为白光,其他7个光源在默认情况下是没有颜色的,也即为黑色。

光源种类

设置光源

1.设置环境光成分

对于GL_LIGHT0,我们可以为其指定环境光成分。调用

glLightfv(GL_LIGHT0,GL_AMBIENT,@AmbientLight);

在上述函数调用中,第一个参数表示我们要对GL_LIGHT0进行设置;
第二个参数表示我们要设置的是环境光成分;
第三个参数则是一个数组,它有4个值,分别表示光源中含有红、绿、蓝三种光线的成分,一般情况下都为1;
第四个参数为透明度值,一般也为1。
完整的代码是这样的:

void SetLight
{
    int AmbientLight[4]={1,1,1,1};
    glLightfv(GL_LIGHT0,GL_AMBIENT,@AmbientLight);
    glEnable(GL_LIGHT0);       //开启GL_LIGHT0光源
    glEnable(GL_LIGHTING);     //开启光照系统
}  

2.设置漫射光成分

通过对漫射光成分的设置,我们可以产生一个点光源。方法和设置环境光成分相似,只需调用

 glLightfv(GL_LIGHT0,GL_DIFFUSE,@DiffuseLight);

其中DiffuseLight是漫射光的颜色成分。可以根据不同需要指定不同的颜色,一般情况下也为(1,1,1,1)。

3.设置镜面光成分

通过对镜面光成分的设置,我们可以产生一个平行光源。方法和设置漫射光成分相似,只需调用

glLightfv(GL_LIGHT0,GL_SPECULAR,@SpecularLight);

其中SpecularLight是镜面反射光的颜色成分。可以根据不同需要指定不同的颜色。

4.设置光源的位置

对于点光源和平行光源,我们常常需要指定光源的位置来产生需要的效果。方法仍然是调用glLightfv函数,仅仅是换换参数而已:

glLightfv(GL_LIGHT0,GL_POSITION,@LightPosition);

其中,LightPosition也是一个四维数组,四维数组的前3项依次为光源位置的X,Y,Z分量。
第四个值很特殊,一般为1或0。当LightPosition[4]=0的时候,表示光源位于距离场景无限远的地方,相当于平行光;而当LightPosition[4]=1时,光源的位置就是前三项所指定的位置,也就是成为了点光源。

材料

材料是针对场景中的物体而言的,但并不是指现实生活中构成物体的那种有质感材料,这里的材料只与物体的颜色有关(你可能会想到怎样表现类似金属、玻璃等物质质感,除了要使用光照系统并为它们指定合适的材质外,还要使用纹理贴图来表现)。OpenGL用材料对光的红、绿、蓝三原色的反射率来近似定义材料的颜色。当一束光照到物体上时,光本身有颜色(可以自己指定。通常情况下的白光是RGB三色光的混合),光照到物体上时,物体的材料会根据自身对光中的各种成分的反射参数决定反射哪种光,也就是物体所呈现出的颜色啦。所以并不是什么颜色的光照过来,物体就会呈现出什么颜色的光。

设置材料

材质的设置与光源的设置类似。其函数为:

void glMaterial{if}[v](GLenum face,GLenum pname,TYPE param);

face可以是GL_FRONT、GL_BACK、GL_FRONT_AND_BACK,它表明当前材质应该应用到物体的哪一个面上;
pname说明一个特定的材质;
param是材质的具体数值,若函数为向量形式,则param是一组值的指针,反之为参数值本身。非向量形式仅用于设置GL_SHINESS。pname参数值具体内容见下表。另外,参数GL_AMBIENT_AND_DIFFUSE表示可以用相同的RGB值设置环境光颜色和漫反射光颜色。

![](http://image-for-blog.qiniudn.com/屏幕快照 2015-03-13 下午12.15.49.png)
完整代码如下:

void SetMaterialAndLight
{
   GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 };
   GLfloat mat_shininess[] = { 50.0 };

   GLfloat light_position[] = { 1.0, 1.0, 1.0, 0.0 };  //最后一个参数为0表示该光源是directional的
 //GLfloat light_position[] = { 1.0, 1.0, 1.0, 1.0 };  //最后一个参数非0表示该光源是positional的

   GLfloat light_ambient[] = { 0.0, 1.0, 0.0, 1.0 };
   GLfloat light_diffuse[] = { 0.0, 1.0, 0.0, 1.0 };
   GLfloat light_specular[] = { 0.0, 1.0, 0.0, 1.0 };

   glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
   glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);

   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);       //开启GL_LIGHT0光源
   glEnable(GL_LIGHTING);     //开启光照系统
}  

颜色追踪

在没有学习光照之前,我们是通过glColor()函数来指定物体颜色的,前面已经说过,这时候我们能看到我们所设置的物体颜色是因为有全局环境光的原因。当开启光照功能后,如果用上述的设置材料属性的方法进行设置,则原来设置的颜色与被光照到后物体呈现的颜色毫无关系,即原来的 glColor*()命令失去原有的作用。
但还有一种方法设置材料属性的方法,称为颜色追踪,即用颜色指定代替材料属性指定。使用颜色追踪,可以告诉OpenGL仅仅通过调用glColor来设置材料属性。为了启用颜色追踪,需要以GL_COLOR_MATERIAL为参数调用glEnable。接着,glColorMaterial函数根据glColor所设置的值来指定材料参数。

glEnable(GL_COLOR_MATERIAL);
glColorMaterial(GL_FRONT,GL_AMBIENT_AND_DIFFUSE);

如果调用了 glEnable(GL_COLOR_MATERIAL),那么就会使光照模型中的几种光根据glColor*()中的指定确定颜色;
void glColorMaterial(GLenum face, GLenum mode);
– face的取值GL_FRONT, GL_BACK与GL_FRONT_AND_BACK(默认值)
– mode的取值为GL_EMISSION, GL_AMBIENT, GL_DIFFUSE, GL_SPECULAR与 GL_AMBIENT_AND_DIFFUSE(默认值)
例如:

glEnable(GL_COLOR_MATERIAL); 
glColorMaterial(GL_FRONT, GL_DIFFUSE); /* now glColor* changes diffuse reflection */ 
glColor3f(0.2, 0.5, 0.8);

/* draw some objects here */ 

glColorMaterial(GL_FRONT, GL_SPECULAR); /* now glColor* changes specular reflection */
glColor3f(0.9, 0.0, 0.2);

/* draw other objects here */ 
glDisable(GL_COLOR_MATERIAL); 

另外,不需要使用glColorMaterial()时,确保禁用。

材质RGB值和光源RGB值的关系

材质的颜色与光源的颜色有些不同。对于光源,R、G、B值等于R、G、B对其最大强度的百分比。若光源颜色的R、G、B值都是1.0,则是最强的白光;若值变为0.5,颜色仍为白色,但强度为原来的一半,于是表现为灰色;若R=G=1.0,B=0.0,则光源为黄色。对于材质,R、G、B值为材质对光的R、G、B成分的反射率。比如,一种材质的R=1.0,G=0.5,B=0.0,则材质反射全部的红色成分,一半的绿色成分,不反射蓝色成分。也就是说,若OpenGL的光源颜色为(LR,LG,LB),材质颜色为(MR,MG,MB),那么,在忽略所有其他反射效果的情况下,最终到达眼睛的光的颜色为(LR*MR,LG*MG,LB*MB)。同样,如果有两束光,相应的值分别为(R1,G1,B1)和(R2,G2,B2),则OpenGL将各个颜色成分相加,得到(R1+R2,G1+G2,B1+B2),若任一成分的和值大于1(超出了设备所能显示的亮度)则约简到1.0。

OpenGL 光照模效果的原理

OpenGL的光照模型是用来模拟现实生活中的光照的。它根据顶点的法线向量光源的位置决定顶点的明暗程度,根据顶点的材质光源中三原色的成分来决定物体将表现出怎样的颜色

使用OpenGL的光照模型的步骤:

  1. 为每个图元的每个顶点指定它的法线向量
  2. 为各个图元指定它的材料

步骤1和步骤3上面已经说过了,下面解释一下步骤2。
众所周知,光线是根据物体表面法向来确定其反射方向的,所以想要对开启光照效果就要对物体表面的每个图元指定法向。如果场景中的物体是多边形网格模型,则需要自己计算每个网格的法向量然后再调用glNormal*()为每个网格指定法线向量。当然,如果你用的是类似glutSolidTorus()或者glutSolidSphere()这种GLUT工具包中的函数则不用自己指定图元的法向量。

几个例子

我在github上传了几个例子可以方便理解->我是栗子

上一篇下一篇

猜你喜欢

热点阅读