OpenGL学习11-使用光源

        环境光具有自己的用途。但是,对于绝大多数视图对现实世界进行建模的应用程序而言,必须指定一个或多个特定的光源。除了强度颜色和颜色之外,这些光源具有位置和方向。这些光源可以极大的影响场景的外光。

        OpenGL至少支持8中独立的光源,他们可以出现在场景的任何地方或者视景体之外。可以把一个光源看成位于位于无限远处,并把它的光线看成是平行的。或则,我们也可以把光源放在附近,让他的光线向四周发射。还可以指定一个聚光灯,从他发射出一道特定的光锥,并且对它的特征进行操纵。

下面是一个例子:

void RenderInit()
{
GLfloat mat_specular[] = {1.0, 1.0, 1.0, 1.0};
GLfloat mat_shininess[] = {50.0};
GLfloat white_light[] = {1.0, 1.0, 1.0, 1.0};
GLfloat lmodel_ambient[] = {0.1, 0.1, 0,1, 1.0};
glClearColor(0.0, 0.0, 0.0, 1.0);
glShadeModel(GL_SMOOTH);
glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
glLightfv(GL_LIGHT0, GL_DIFFUSE, white_light);
glLightfv(GL_LIGHT0, GL_SPECULAR, white_light);
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_DEPTH_TEST);
}
void RenderScene()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();
glRotatef(xRot, 1.0f, 0.0f, 0.0f);
glRotatef(yRot, 0.0f, 1.0f, 0.0f);
GLfloat light_position[] = {0, 0, 100, 0.0};
glLightfv(GL_LIGHT0, GL_POSITION, light_position);
glPopMatrix();
glPushMatrix();
glutSolidSphere(100, 40, 40);
glPopMatrix();
glutSwapBuffers();
}

程序运行结果,如下图:

 OpenGL学习11-使用光源_第1张图片

 

指定材料属性:

        void glMaterialv(GLenum face, GLenum pname, TYPE *param);

        参数face指物体那个面,可以取值GL_FRONT、GL_BACK、GL_FRONT_AND_BACK;pname指出要设置的哪种材质属性;param为要设置的属性值,是一个指向数组的指针(向量版本)或一个数值(非向量版本)。

pname可能取值和相对param的默认值,如下:

参数值

默认值

意义

GL_AMBIENT

(0.2,0.2,0.2,1.0)

材质的环境颜色

GL_DIFFUSE

(0.8,0.8,0.8,1.0)

材质的散射颜色

GL_AMBIENT_AND_DIFFUSE

 

材质的环境颜色和散射颜色

GL_SPECULAR

(0.0,0.0,0.0,1.0)

材质的镜面反射颜色

GL_SHININESS

0.0

镜面反射指数

GL_EMISSION

(0.0,0.0,0.1,1.0)

材质的发射光颜色

GL_COLOR_INDEXES

(0, 1, 1)

环境颜色索引、散射颜色索引和镜面反射颜色索引


指定光源属性:

        void glLightfv(GLenum light, GLenum pname, const GLfloat *params);

        参数light指定光源,OpenGL中至少支持8个光源GL_LIGHT0....GL_LIGHT7; 

pname是参数类型,常见参数及默认值:

参数值

默认值

意义

GL_AMBIENT

(0.0,0.0,0.0,1.0)

环境光强度

GL_DIFFUSE

(1.0,1.0,1.0,1.0)

散射光强度

GL_SPECULAR

(1.0,1.0,1.0,1.0)

反射光强度

GL_POSIZION

(0.0,0.0,1.0,0.0)

光源位置

光照模型:

        OpenGL的光照模型参数包括4个部分:

        (1)全局环境光强度

        (2)观察点位于场景中还是无限远处

        (3)物体正反两面是否执行不同的光照计算

        (4)镜面光颜色是否从环境和漫反射颜色中分离出来,并在纹理操作后在应用

                void APIENTRY glLightModelfv (GLenum pname, const GLfloat *params);

参数及默认值:

参数值

默认值

意义

GL_LIGHT_MODEL_AMBIENT

(0.2,0.2,0.2,1.0)

整个场景中的环境光强度

GL_LIGHT_MODEL_LOCAL_VIEWER

0.0/GL_FALSE

场景中观察点,默认无限远处

GL_LIGHT_MODEL_TWO_SIDED

0.0/GL_FALSE

单独对多边形两面进行明暗处理

GL_LIGHT_MODEL_COLOR_CONTROL

GL_SINGLE_COLOR(默认)、GL_SEPATATE_SPECULAR_COLOR

镜面光是否与慢反射和环境光分开计算

        环境光依赖于每个光源的颜色,因此需要对每个光源指定环境光强度;OpenGL中也可以定义一个对测试非常有用的全局环境光:

                GLfloat lmodel_ambient[] = {0.1, 0.1, 0,1, 1.0};

                glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);


启用光源:

        明暗处理的计算由下述命令启用:

                glEnable(GL_LIGHTING);

        当光照被激活后,glColor()命令将被忽略

        必须单独激活每一个光源:

                glEnable(GL_LIGHT0);


法线向量:

        物体的法线向量定义了它的表面在空间中的朝向,即,定义了表面相对于光源的方向。因为OpenGL是使用法线向量来确定一个物体表面的某个顶点所接受的光照。

        指定法线向量:

                void glNormal3f(GLfloat nx, GLfloat ny, GLfloat nz);

                void glNormal3fv(const GLfloat *v);

        在OpenGL实现中,所有的表面法线最终必须转换为单位法线。单位法线的长度为1的法线向量。可以让OpenGL自动把一条法线向量转换为单位法线:

                glEnable(GL_NORMALIZE);

        但是,这种方法在效率上有所牺牲。我们最好自己预先计算单位法线,而不是依赖OpenGL自动执行。

        应该注意,调用glScale转换函数是还会对法线的长度进行缩放。如果使用glScale和光照可能会在OpenGL中看到不希望看到的结果。这时候就需要使用新的方法,使用GL_RESCALE_NORMALS替代GL_NORMALIZE:

                glEnable(GL_RESCALE_NORMALS);

        在Glut提供的绘制函数中法线向量在函数中已经设置好了,如glutSolidSphere。如果需要自己实现物体的绘制,就需要自己设置法线向量了,下面说明一种法线的计算方法:

        如下图,显示3个点,P1,P2,P3,可以定义两个向量:从P1到P2的向量V1,从P1到P3的向量V2。从数学的角度,三维空间两个向量定义一个平面。可以得到该平面的法相向量为V3=V1 X V2。

 OpenGL学习11-使用光源_第2张图片

        假设V1 = (a1, b1, c1),V2 = (a2, b2, c2)

        得到V3 = (b1xc2-c1xb2, a1xc2-c1xa2, a1xb2-b1xa2)

计算法线向量方法的代码如下:

typedef float M3DVector3f[3];
void m3dFindNormal(M3DVector3f normal, const M3DVector3f p1, const M3DVector3f p2, const M3DVector3f p3)
{
M3DVector3f v1, v2;
v1[0] = p3[0] - p2[0];
v1[1] = p3[1] - p2[1];
v1[2] = p3[2] - p2[2];
v2[0] = p1[0] - p2[0];
v2[1] = p1[1] - p2[1];
v2[2] = p1[2] - p2[2];
m3dCrossProduct(normal, v1, v2);
}
void m3dCrossProduct(M3DVector3f normal, const M3DVector3f v1, const M3DVector3f v2)
{
normal[0] = v1[1]*v2[2] - v1[2]*v2[1];
normal[1] = v1[0]*v2[2] - v1[2]*v2[0];
normal[2] = v1[0]*v2[1] - v1[1]*v2[0];
}

你可能感兴趣的:(OpenGL学习)