opcv学习日志 7 光照

      OpenGL至少会支持8个光源。


 在物理学中,光线如果射入理想的光滑平面,则反射后的光线是很规则的(这样的反射称为镜面反射)。光线如果射入粗糙的、不光滑的平面,则反射后的光线是杂乱的(这样的反射称为漫反射)。现实生活中的物体在反射光线时,并不是绝对的镜面反射或漫反射,但可以看成是这两种反射的叠加。对于光源发出的光线,可以分别设置其经过镜面反射和漫反射后的光线强度。对于被光线照射的材质,也可以分别设置光线经过镜面反射和漫反射后的光线强度。这些因素综合起来,就形成了最终的光照效果。

使用glNormal*函数则可以指定法线向量

注意:使用glTranslate*函数或者glRotate*函数可以改变物体的外观,但法线向量并不会随之改变。然而,使用glScale*函数,对每一坐标轴进行不同程度的缩放,很有可能导致法线向量的不正确,虽然OpenGL提供了一些措施来修正这一问题,但由此也带来了各种开销。因此,在使用了法线向量的场合,应尽量避免使用glScale*函数。即使使用,也最好保证各坐标轴进行等比例缩放。

GL_POSITION属性。表示光源所在的位置。由四个值(X, Y, Z, W)表示。如果第四个值W为零,则表示该光源位于无限远处,前三个值表示了它所在的方向。这种光源称为方向性光源,通常,太阳可以近似的被认为是方向性光源。如果第四个值W不为零,则X/W, Y/W, Z/W表示了光源的位置。这种光源称为位置性光源。对于位置性光源,设置其位置与设置多边形顶点的方式相似,各种矩阵变换函数例如:glTranslate*、glRotate*等在这里也同样有效。方向性光源在计算时比位置性光源快了不少,因此,在视觉效果允许的情况下,应该尽可能的使用方向性光源

GL_SPOT_DIRECTION、GL_SPOT_EXPONENT、GL_SPOT_CUTOFF属性。表示将光源作为聚光灯使用(这些属性只对位置性光源有效)。很多光源都是向四面八方发射光线,但有时候一些光源则是只向某个方向发射,比如手电筒,只向一个较小的角度发射光线。GL_SPOT_DIRECTION属性有三个值,表示一个向量,即光源发射的方向。GL_SPOT_EXPONENT属性只有一个值,表示聚光的程度,为零时表示光照范围内向各方向发射的光线强度相同,为正数时表示光照向中央集中,正对发射方向的位置受到更多光照,其它位置受到较少光照。数值越大,聚光效果就越明显。GL_SPOT_CUTOFF属性也只有一个值,表示一个角度,它是光源发射光线所覆盖角度的一半(见图2),其取值范围在0到90之间,也可以取180这个特殊值。取值为180时表示光源发射光线覆盖360度,即不使用聚光灯,向全周围发射。

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


GL_LIGHT_MODEL_AMBIENT表示全局环境光线强度,由四个值组成。
     GL_LIGHT_MODEL_LOCAL_VIEWER表示是否在近处观看,若是则设置为GL_TRUE,否则(即在无限远处观看)设置为GL_FALSE。
     GL_LIGHT_MODEL_TWO_SIDE表示是否执行双面光照计算。如果设置为GL_TRUE,则OpenGL不仅将根据法线向量计算正面的光照,也会将法线向量反转并计算背面的光照。
     GL_LIGHT_MODEL_COLOR_CONTROL表示颜色计算方式。如果设置为GL_SINGLE_COLOR,表示按通常顺序操作,先计算光照,再计算纹理。如果设置为GL_SEPARATE_SPECULAR_COLOR,表示将GL_SPECULAR属性分离出来,先计算光照的其它部分,待纹理操作完成后再计算GL_SPECULAR。后者通常可以使画面效果更为逼真(当然,如果本身就没有执行任何纹理操作,这样的分离就没有任何意义)。

光照模型有四个参数(和前面描述的光照的四个独立成分不是一回事):

(1).全局环境光强(GL_LIGHT_MODEL_AMBIENT),默认值是(0.2,0.2,0.2,1.0)。

(2).观察者位置模式(GL_LIGHT_LOCAL_VIEWER)(和计算镜面反射分量相关),默认值GL_FALSE,即观察者在无穷远处。

(3).单面光照or双面光照(GL_LIGHT_MODEL_TWO_SIDE),默认值GL_FALSE,单面光照。

(4).是否分离镜面颜色(GL_LIGHT_MODEL_COLOR_CONTROL)(和纹理映射效果相结合),默认值为GL_SINGLE_COLOR。

光照使用函数glLightModel*()指定光照模型的四个参数。


eg:

#include <gl/glut.h>

#define WIDTH 400
#define HEIGHT 400

static GLfloat angle = 0.0f;

void myDisplay(void)
{
     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

     // 创建透视效果视图
     glMatrixMode(GL_PROJECTION);
     glLoadIdentity();
     gluPerspective(90.0f, 1.0f, 1.0f, 20.0f);
     glMatrixMode(GL_MODELVIEW);
     glLoadIdentity();
     gluLookAt(0.0, 5.0, -10.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);

     // 定义太阳光源,它是一种白色的光源
     {
     GLfloat sun_light_position[] = {0.0f, 0.0f, 0.0f, 1.0f};
     GLfloat sun_light_ambient[]   = {0.0f, 0.0f, 0.0f, 1.0f};
     GLfloat sun_light_diffuse[]   = {1.0f, 1.0f, 1.0f, 1.0f};
     GLfloat sun_light_specular[] = {1.0f, 1.0f, 1.0f, 1.0f};

     glLightfv(GL_LIGHT0, GL_POSITION, sun_light_position);
     glLightfv(GL_LIGHT0, GL_AMBIENT,   sun_light_ambient);
     glLightfv(GL_LIGHT0, GL_DIFFUSE,   sun_light_diffuse);
     glLightfv(GL_LIGHT0, GL_SPECULAR, sun_light_specular);

     glEnable(GL_LIGHT0);
     glEnable(GL_LIGHTING);
     glEnable(GL_DEPTH_TEST);
     }

     // 定义太阳的材质并绘制太阳
     {
         GLfloat sun_mat_ambient[]   = {0.0f, 0.0f, 0.0f, 1.0f};
         GLfloat sun_mat_diffuse[]   = {0.0f, 0.0f, 0.0f, 1.0f};
         GLfloat sun_mat_specular[] = {0.0f, 0.0f, 0.0f, 1.0f};
         GLfloat sun_mat_emission[] = {0.5f, 0.0f, 0.0f, 1.0f};
         GLfloat sun_mat_shininess   = 0.0f;

         glMaterialfv(GL_FRONT, GL_AMBIENT,    sun_mat_ambient);
         glMaterialfv(GL_FRONT, GL_DIFFUSE,    sun_mat_diffuse);
         glMaterialfv(GL_FRONT, GL_SPECULAR,   sun_mat_specular);
         glMaterialfv(GL_FRONT, GL_EMISSION,   sun_mat_emission);
         glMaterialf (GL_FRONT, GL_SHININESS, sun_mat_shininess);

         glutSolidSphere(2.0, 40, 32);
     }

     // 定义地球的材质并绘制地球
     {
         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;

         glMaterialfv(GL_FRONT, GL_AMBIENT,    earth_mat_ambient);
         glMaterialfv(GL_FRONT, GL_DIFFUSE,    earth_mat_diffuse);
         glMaterialfv(GL_FRONT, GL_SPECULAR,   earth_mat_specular);
         glMaterialfv(GL_FRONT, GL_EMISSION,   earth_mat_emission);
         glMaterialf (GL_FRONT, GL_SHININESS, earth_mat_shininess);

         glRotatef(angle, 0.0f, -1.0f, 0.0f);
         glTranslatef(5.0f, 0.0f, 0.0f);
         glutSolidSphere(2.0, 40, 32);
     }

     glutSwapBuffers();
}
void myIdle(void)
{
     angle += 1.0f;
     if( angle >= 360.0f )
         angle = 0.0f;
     myDisplay();
}

int main(int argc, char* argv[])
{
     glutInit(&argc, argv);
     glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
     glutInitWindowPosition(200, 200);
     glutInitWindowSize(WIDTH, HEIGHT);
     glutCreateWindow("OpenGL光照演示");
     glutDisplayFunc(&myDisplay);
     glutIdleFunc(&myIdle);
     glutMainLoop();
     return 0;
}


你可能感兴趣的:(opcv学习日志 7 光照)