最近在尝试实现'影子',顺带熟悉下 OpenGL 中 lighting 部分的知识。
在没有开启光照前,所有 vertex 的颜色是由 glColor 决定的。比如下面绘制一个三角形。
glBegin(GL_TRIANGLES);
glColor3f(1.0, 0, 0);
glVertex3f(0.0, 1.0, -2.0);
glColor3f(0, 1.0, 0);
glVertex3f(1.0, -1.0, -2.0);
glColor3f(0, 0, 1.0);
glVertex3f(-1.0, -1.0, -2.0);
glEnd();
而通过 glEnable(GL_LIGHTING) 开启光照后,则 vertex 的颜色则由 (1) 此顶点的 material 和 (2) 场景的环境光 (3) 场景中的点光源 有关。
(1) vertex 的 material 决定了此顶点不同类型光的反射程度
(2) 场景的环境光可通过 glLightModel(GL_LIGHT_MODEL_AMBIENT) 设置
(3) 而点光源通过 glLight() 设置属性,glEnable(GL_LIGHTx) 开启
无论是光源还是 vertex or 物品 本身,对光照的描述都分为四部分:ambient, diffuse, specular, emissive。光照公式就是这几个值配合几个参数组成的。为啥由这几个部分来描述光照我们就不用深究了,反正学院派的科学老头已经用无数论文证明这个公式模拟出来的光照效果不错。
我们可以通过 glShadeModel(mode) 来设定光照模型,GL_FLAT 表示 flat shading,每个 surface pixel 只使用某个 vertex 的颜色;而 GL_SMOOTH 表示 Gouraud shading,每个 vertex 通过计算得到自己独立的颜色,而 surface pixel 则通过 vertex颜色 线性插值得到;而 Phong shading 则需要自己写 shader 来实现了,Phong 是 Gouraud 的改良版,就是 surface pixel 根据 vertex 的发向量(normal) 进行插值,算出自己的 normal,并独立计算 pixel 自己的颜色。
例子:看下面的 yellow cube,首先 light0 是 (1.0, 1.0, 1.0) 的白光;下面 cube 的效果,基本上是因为 material 的因素决定的。光照不到的地方,微微泛绿色,是因为开了(0, 0.5, 0)的绿色 ambient;而大部分的黄色是因为 diffuse 为 (0.75, 0.75, 0.0) 的黄光;黄色中间的高光(highlight),是因为 (1.0, 1.0, 1.0) 的 specular 带来的效果。
代码:
// 初始化
// lights
GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 0.15 };
GLfloat mat_shininess[] = { 100.0 };
GLfloat position[] = { 0.5, 0.5, 1.0, 0.0 };
glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
glLightfv(GL_LIGHT0, GL_POSITION, position);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
// 绘制
GLfloat mat_solid[] = { 0.75, 0.75, 0.0, 1.0 };
GLfloat mat_zero[] = { 0.0, 0.0, 0.0, 1.0 };
GLfloat mat_ambient[] = { 0.0, 0.5, 0.0, 1.0 };
glMaterialfv(GL_FRONT, GL_EMISSION, mat_zero);
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_solid);
glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient);
glCallList(sphereList);
评论