现实世界的光照是极其复杂的,而且会受到诸多因素的影响,这是以目前我们所拥有的处理能力无法模拟的。因此OpenGL的光照仅仅使用了简化的模型并基于对现实的估计来进行模拟,这样处理起来会更容易一些,而且看起来也差不多一样。这些光照模型都是基于我们对光的物理特性的理解。

其中一个模型被称为冯氏光照模型(Phong Lighting Model)。冯氏光照模型的主要结构由3个元素组成:环境(Ambient)、漫反射(Diffuse)和镜面(Specular)光照。这些光照元素看起来像下面这样:

光照元素

** 环境光照(Ambient Lighting) ** 即使在黑暗的情况下,世界上也仍然有一些光亮(月亮、一个来自远处的光),所以物体永远不会是完全黑暗的。我们使用环境光照来模拟这种情况,也就是无论如何永远都给物体一些颜色。 ** 漫反射光照(Diffuse Lighting) ** 模拟一个发光物对物体的方向性影响(Directional Impact)。它是冯氏光照模型最显著的组成部分。面向光源的一面比其他面会更亮。 ** 镜面光照(Specular Lighting) ** 模拟有光泽物体上面出现的亮点。镜面光照的颜色,相比于物体的颜色更倾向于光的颜色.
设置光照属性
OpenGL场景中模型颜色的产生,大致为如下的流程图所描述: ![光照元素](https://github.com/mariaclark1123/mariaclark1123.github.io/blob/master/srcimage/example1.png?raw=true) * 当不开启光照时,使用顶点颜色来产生整个表面的颜色 (ex: glColor3f(1,0,1.0,1.0)) 用glShadeModel可以设置表面内部像素颜色产生的方式: GL_FLAT/GL_SMOOTH. * 一般而言,开启光照后,在场景中至少需要有一个光源
1
(GL_LIGHT0...GL_LIGHT7)
通过glEnable(GL_LIGHT0) glDisable(GL_LIGHT0) 来开启和关闭指定的光源。 ** 全局环境光 **
1
2
GLfloat glAmbient[] = {0.6, 0,6, 0,6, 1.0};
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, gAmbient);
  • 设置光源的光分量 — 环境光/漫色光/镜面光默认情况下:
1
2
3
GL_LIGHT0...GL_LIGHT7 的GL_AMBIENT值为(0.0, 0.0, 0.0, 1.0)
GL_LIGHT0的GL_DIFFUSE和GL_SPECULAR值为(1.0, 1.0, 1.0, 1.0)
GL_LIGHT1...GL_LIGHT7 的GL_DIFFUSE和GL_SPECULAR值为(0.0, 0.0, 0.0, 0.0)。
  • 我们需要自己定义光源的光分量:
1
2
3
4
5
6
GLfloat lightAmbient[] = {1.0, 1.0, 1.0, 1.0};
GLfloat lightDiffuse[] = {1.0, 1.0, 1.0, 1.0};
GLfloat lightSpecular[] = {0.5, 0.5, 0.5, 1.0};
glLightfv(GL_LIGHT0, GL_AMBIENT, lightAmbient);
glLightfv(GL_LIGHT0, GL_DIFFUSE, lightDiffuse);
glLightfv(GL_LIGHT0, GL_SPECULAR, lightSpecular);
  • 设置光源的位置和方向
** 平行光 **
1
2
GLfloat lightPosition[] = {8.5, 5.0, -2.0, 0.0}; // w=0.0
glLightfv(GL_LIGHT0, GL_POSITION, lightPosition);
** 点光源 **
1
2
GLfloat lightPosition[] = {8.5, 5.0, -2.0, 1.0}; // w不为0
glLightfv(GL_LIGHT0, GL_POSITION, lightPosition);
** 聚光灯 ** ![](https://github.com/mariaclark1123/mariaclark1123.github.io/blob/master/srcimage/spotlight.png?raw=true)
1
2
3
4
5
GLfloat lightPosition[] = {-6.0, 1.0, 3.0, 1.0};   // w不为0
glLightfv(GL_LIGHT0, GL_POSITION, lightPosition);
GLfloat lightDirection[] = {1.0, 1.0, 0.0};
glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, lightDirection); // 聚光灯主轴方向 spot direction
glLightf(GL_LIGHT0, GL_SPOT_CUTOFF, 45.0); // cutoff角度 spot cutoff
**平行光不会随着距离d增加而衰减,但点光源和聚光灯会发生衰减** ![](https:///github.com/mariaclark1123/mariaclark1123.github.io/blob/master/srcimage/atten_eq.png?raw=true) attenuation为衰变系数,系数值越大,衰变越快。 默认情况下,c=1.0, l=0.0, q=0.0 ![](https://github.com/mariaclark1123/mariaclark1123.github.io/blob/master/srcimage/atten_pic.png?raw=true) 可以自定义衰变函数的系数:
1
2
3
glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 2.0);     // c 系数
glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 1.0); // l 系数
glLightf(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, 0.5); // q 系数

设置材质属性
环境光、散射光不受视点位置的影响。物体看起来是什么颜色,很大程度上地受到散射光的影响,环境光反射也对物体的颜色有一定的影响。 因为当光直射物体时,散射光最强;非直射时,环境光效果明显。 对于真实的世界中的物体,其散射光与环境光通常是同一个颜色。物体的镜面反射会在物体表面产生一个高亮区。观察者所看到的镜面反射依赖于视点位置 -- 沿着反射光的方向亮度最高。 ** 默认情况下: **
  • 材质的GL_AMBIENT值为(0.2, 0.2, 0.2, 1.0)
  • 材质的GL_DIFFUSE值为(0.8, 0.8, 0.8, 1.0)
  • 材质的GL_SPECULAR值为(0.0, 0.0, 0.0, 1.0)
  • 材质的GL_SHININESS值为0.0【取值范围为[0.0, 128.0],数值越大,高亮区越小,亮度越高】
  • 材质的GL_GL_EMISSION值为(0.0, 0.0, 0.0, 1.0)

简单举例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
GLfloat matAmbient[] = {0.6, 0.6, 0.6, 1.0};
GLfloat matDiffuse[] = {0.35, 0.35, 0.35, 1.0};
GLfloat matAmbDif[] = {0.5, 0.5, 0.5, 1.0};
GLfloat matSpecular[] = {0.2, 0.2, 0.2, 1.0};
GLfloat shine[] = {5.0};
GLfloat matEmission[] = {0.3, 0.1, 0.1, 1.0};
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, matAmbient);
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, matDiffuse);
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, matAmbDif); // 将背景颜色和散射颜色设置成同一颜色
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, matSpecular);
glMaterialfv(GL_FRONT, GL_SHININESS, shine);
glMaterialfv(GL_FRONT, GL_EMISSION, matEmission); // 用来模拟物体发光的效果,但这不是光源
```

<font color=#D87093>** 颜色材质模式 **</font>

使用颜色材质可以用较小的代价,快速改变场景中模型的颜色。其具体用法如下:
``` c
glEnable(GL_COLOR_MATERIAL);
glColorMaterial(GL_FRONT, GL_DIFFUSE);
glColor3f(0.2, 0.5, 0.8);
/*** 绘制一些物体 ***/
glColorMaterial(GL_FRONT, GL_SPECULAR);
glColor3f(0.9, 0.1, 0.3);
/*** 绘制另外一些物体 ***/
glDisable(GL_COLOR_MATERIAL);


参考文章

光照基础

Basic OpenGL Lighting

浅析OpenGL光照

转载于可可西的博客