OpenGL || opengl中的光照材质

openGL在处理光照时,把光照系统分为三部分:光源、材料、光照模型。
光源、材料和光照模式都有各自的属性,尽管属性种类繁多,但这些属性都只有少量的几个函数来设置。

  • 光源的属性:glLight*
  • 材质的属性:glMaterial*
  • 光照模式:glLightModel*


【光源的属性】&&【 材质的属性】
GL_AMBIENT、GL_DIFFUSE、GL_SPECULAR这三种属性是光源和材质所共有的。
如果某光源发出的光照射发哦某材质的表面,则最终的漫反射强度由两个GL_DIFFUSE属性共同决定的,最终的镜面反射强度由两个GL_SPECULEAR属性共同决定。
在opengl中,仅支持有限数量的光源。支持8个光源,即GL_LIGHT0到GL_LIGHT7。一些openGL实现可能支持更多数量的光源,但开启过多的光源犟龟导致程序运行速度的严重下降。
使用glEnable(GL_LIGHT0),使用glDisable函数可以关闭光源。其中GL_LIGHT0与其他光源不同,GL_DIFFUSE、GL_SPECULAR的默认值是(1.0,1.0,1.0,1.0),其他光源默认值是(0.0,0.0,0.0,1.0)

【光照模式】

  • 设置光源的种类、位置和方向(对于平行光源)
  • 为每个图元的每个顶点指定它的法向向量
  • 为各个图元指定它的材质
  • 启用光照模型

1.光源设置

a.设置环境光glLightfv(GL_LIGHT0, GL_AMBIENT, ambientLight);
b.设置漫反射光成分glLightfv(GL_LIGHT0, GL_DIFFUSE, DiffuseLight)
c.设置镜面光成分glLightfv(GL_LTIGHT0, GL_SPECULAR, SpecularLight)
光源的属性GL_SPECULAR影响镜面反射区域的颜色,一般物体的镜面反射区域的颜色为入色光线的颜色,要实现真实感,应将它设置成与GL_DIFFUSE相同
d.设置光源的位置glLightfv(GL_LIGHT0, GL_POSITION, sun_light_position)
G:_POSITION属性。表示光源的所在位置。有四个值(X, Y, Z, W)表示。

  • 方向性光源:第4个值W为0,则表示该光源位于无限远处,前三个值表示它所在的方向。通常,太阳可以近似的被认为是方向性光源
  • 位置性光源:第四个值W不为0,则X/W,Y/W, Z/W表示了光源的位置。这种光源成为位置性光源。定位光源需要对其发射的光进行衰减,可以设置各种衰减因子,环境光,散设光和镜面反射光的贡献都是衰减的,只有发射光和全局环境光不会衰减。


设置其位置与设置多边形顶点的方法相似,各种矩阵变换的函数:glTranslate*、glRotate*等在这里也有同样有效。方向性光源在计算时比为执行光源快了不少,因此在视觉效果允许下,应尽可能使用方向性光源。
举个例子,下面定义了一个位置在(1,1,1),没有环境光,并且镜面反射光和漫反射光都为白光的光源

GLfloat light_position[] = {1.0, 1.0, 1.0, 0.0};
GLfloat light_ambient[] = {0.0, 0.0, 0.0, 1.0};
GLfloat light_diffuse[] = {1.0, 1.0, 1.0, 1.0};
GLfloat light_specular[] = {1.0, 1.0, 1.0, 1.0};
glLightfv(GL_LIGHT0, GL_POSITION, light_position);
glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);
glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);

1.1 创建聚光灯(这些属性只对位置性光源有效)

glLightf(GL_LIGHT0, GL_STOP_CUTOFF, LightCutOFF)
表示将光源作为聚光灯使用。很多光源都是向四面八方射光线,但有时候一些光源则是只向某个方向发射,比如手电筒,只向一个较小的角度发射光线

  • GL_STOP_DIRECTION:属性有三个值,表示一个向量,即光源发射的方向。默认为(0.0, 0.0, -1.0),即指向z轴负方向
  • GL_SPOT_EXPONENT:属性有一个值,表示聚光的程度,为0时表示光照范围内向各个方向发射的光线强度相同,为正数时表示光照想中央集中,针对发射方向的位置受到更多的光照,其他位置受到较少的光照,数值越大,聚光效果就越明显。
  • GL_SPOT_CUTOFF:属性有一个值,表示一个角度,他是光源发射光线所覆盖角度的一半,其取值范围在0到90之间,也可以取180这个特殊值。取值为180时表示光源发射光线覆盖360度,即不使用聚光灯,向周围发射。即一个点光源。

1.2 设置光线衰减系数(这些属性只对位置性光源有效)

glLightf(GL_LIGHAT0, AttenuationWay, SpotAttenuation)
参数SpotAttenuation为光线的衰减系数。 AttenuationWay可以取一下几个值:

  • GL_CONSTANT_ATTENUATION:表示光线安常数衰减(与距离无关)
  • GL_LINEAR_ATTENUATION:表示光线按距离性衰减
  • GL_QUADRATIC_ATTENUATION:表示光线按距离以二次函数衰减

这3个属性表示了光源所发出的光线的直线传播特性。现实中,光线的强度随着距离的增强而增强,openGL把这个减弱的趋势。抽象成函数:
衰减因子=1/(k1 + k2 *d + k3 * k3 * d)
其中d表示距离,光线的初始强度乘以衰减因子,就得到对应距离的光线强度。k1,k2,k3分别是 GL_CONSTANT_ATTENUATION、GL_LINEAR_ATTENUATION、GL_QUADRATIC_ATTENUATION。通过设置这三个常数,就可以控制光线在传播过程中的减弱趋势。

2 为图元指定法向量

openGL必须通过图元的法向量来确定图元的明暗程度。通过计算得到的法向量后,我们需要在绘制顶点前调用glNormal函数为顶点或图元指定法
使用glTranslate* 函数或者glRotate*函数可以改变物体的外观,但是法向向量并不会随之改变。然而,使用glScale*函数,对每一坐标轴进行了不同程度的缩放,可能导致发现向量的不正确,虽然openGL提供了一些措施来修正这一问题,但由此带来了各种开销。因此,使用了发现向量的场合,应尽量避免使用glScale*函数。使用的话也要保证各坐标系进行等比缩放
对于光源进行平移或旋转,使之相对于静止的物体移动,这可以在指定模型变换后设置光源的位置,通过修改模型的变换来改变光源的位置。

3 设置材质

openGL用材料对红、绿、蓝三原色的反射率来近似定义材料的颜色。像光源一样,材料颜色也分成环境、漫反射和镜面反射成分,它们决定了材料对环境光、漫反射光和镜面反射光的反射程度。在进行光照计算时,材料对环境光的反射率与每个进入光源的环境光结合,对漫反射的反射率与每个进入光源的漫反射光结合,对镜面光的反射率与每个进入光源的镜面反射光结合。
对环境光与漫反射光的反射程度决定可材料的颜色,并且他们很相似。对镜面反射光的反射率通常是白色或灰色(即对镜面反射光中的红、绿、蓝的反射率相同)。镜面反射高光最亮的地方变成具有光源镜面光强度的颜色。例如一个光亮的红色塑料球,求得大部分表现为红色,光亮的高光将是白色的。材质的颜色与光源的颜色有些不同。R、G、B值为材质对光的R、G、B对其最大强度的百分比。
若光源颜色的R、G、B值都是1.0,则是最强的白光;若值变为0.5,颜色仍为白色,但强度为原来的一半,用于表现为灰色;若R=G=1.0,B=0.0,则光源为黄色。
对于材质,R、G、B值为材料对光的RGB成分的反射率。比如,一种材质的R=1.0、G=0.5、B=0.0,则材质反射全部的红色成分,一般的绿色成分,不反射蓝色成分。
即:若OpenGL的光源颜色为(LR、LG、LB),材质颜色为(MR、MG、MB),那么在忽略所有其他反射效果的情况下,最终到达眼睛的光的颜色为(LRMR、LGMG、LB*MB)。指定了图元的法线之后,我们还需要为其指定相应的材质已决定物体对各种颜色的光的反射程度,这将影响物体表现为何种颜色。

【指定材质】
glMaterialfv(GL_FRONT, GL_DIFFUSE, @Diffuse);
1. GL_FRONT(正面),GL_BACK(反面),GL_FRONT_AND_BACK(正反两面)。
2. GL_AMBIENTGL_DIFFUSEGL_SPECULAR属性。这三个属性与光源的三个对应属性类似,每一属性都由四个值组成。
   【GL_AMBIENT】表示各种光线照射到该材质上,经过很多次反射后最终遗留在环境中的光线强度(颜色)。
   【GL_DIFFUSE】表示光线照射到该材质上,经过漫反射后形成的光线强度(颜色)。
   【GL_SPECULAR】表示光线照射到该材质上,经过镜面反射后形成的光线强度(颜色)。
通常,【GL_AMBIENT】和【GL_DIFFUSE】都取相同的值,可以达到比较真实的效果。使用【GL_AMBIENT_AND_DIFFUSE】可以同时设置【GL_AMBIENT和GL_DIFFUSE】属性。

3. GL_SHININESS属性。该属性只有一个值,成为“镜面指数”,取值范围是0到128.该值越小,表示材质越粗糙,点光源发射的光线照射到上面,也可以产生较大的两点。该值越大,标志材质越类似于镜面,光源照射到上面后,产生较小的亮点。
4. GL_EMISSION属性。该属性由四个值组成,表示一种颜色。OpenGL认为该材质本身就微微的向外发射光线,以至于眼睛感觉到它有这样的颜色,但这光线又比较微弱,以至于不会影响到其它物体的颜色。
5. GL_COLOR_INDEXES属性。该属性仅在颜色索引模式下使用,由于颜色索引模式下的光照比RGBA模式要复杂,并且使用范围较小,这里不做讨论。

//它们的数值情况如下:
GLfloat earth_mat_ambient[]  = { 0.0f, 0.0f, 0.5f, 1.0f};
GLfloat earth_mat_diffuse[]  = {0.0f, 0.0f, 0.5f, 1.0f};
GLfloat earth_mat_specular[] = {0.0f, 0.0f, 1.0f, 1.0f};
GLfloat earth_mat_emission[] = {0.0f, 0.0f, 0.0f, 1.0f};
GLfloat earth_mat_shininess  = 30.0f; //(0--128)

4 使用颜色跟踪(这将导致正面的DIFFUSE总是设置为当前颜色)

在启动光照系统之后,为图元指定颜色变得不太方便。首先我们需要创建一个数组,然后调用glMaterial函数将数组传给材质,一次决定物体的颜色。为了简便,我们可以开启颜色跟踪来简化代码,

  • 调用glEnable(GL_CORLOR_MATERIAL); 启动颜色跟踪
  • glColorMatetial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE); 决定对物体的正面还是反面,对环境光、镜面光还是漫反射光进行颜色跟踪。


第一个参数可以取 GL_FRONT、GL_BACK、GL_FRONT_AND_BACK中的任意一种,
第二个参数可以取 GL_AMBIENT、GL_DIFFUSE、GL_AMBIENT_AND_DIFFUSE、GL_SPECULAR中的任意一种。
启动颜色跟踪之后,我们就可以想以前一样使用glColor函数来指定图元的颜色了。这时,OpenGL将自动根据从glColor函数传递的颜色来决定物体材质。比如画一个红色的有立体感的球

glPushMatrix();
   glEnable(GL_COLOR_MATERIAL);
   glColorMaterial(GL_FRONT, GL_AMBIENT,GL_AMBIENT_AND_DIFFUSE);
   glColor3f(1.0, 0.0, 0.0);
   glutSolidSphere(1.0, 16, 16);
   glDisable(GL_COLOR_MATERIAL);
   glPopMatrix();

5 光照模型

光照模型分为4部分:全局环境光、近视点或者远视点、双面光照、镜面反射颜色时候和环境颜色、色散颜色分开。

  • 指定全局环境光GLfloat ambient[] = {0.2, 0.2, 0.2, 1.0};
    glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient);顶点的镜面反射亮度取决于该点的法线,顶点相对于光源的方向以及顶点相对于视点的方向。
  • 使用近视点(把无限远的观察点改为局部观察点)
    glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE); // 这就将视点放置在(0,0,0)处。
  • 启用双面光照,使物体的背面接受光照
    glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
  • 镜面颜色的计算是否从环境颜色、色散颜色分开执行纹理贴图是才有用,可使效果逼真,其原理是:把镜面光从主颜色中抽离出来,在纹理贴图后,再把镜面光加进去glLightModelfv(GL_LIGHT_MODEL_COLOR_CONTROL,GL_SEPARATE_SPECULAR_COLOR);
    恢复到默认值可以调用glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SINGLE_COLOR);
©️2020 CSDN 皮肤主题: 游动-白 设计师:上身试试 返回首页