OpenGL快速入门示例-OpenGL光照和材质

OpenGL光照和材质


        当光照射到一个物体表面上时,会出现三种情形。首先,光可以通过物体表面向空间反射,产生反射光。其次,对于透明体,光可以穿透该物体并从另一端射出,产生透射光。最后,部分光将被物体表面吸收而转换成热。在上述三部分光中,仅仅是透射光和反射光能够进入人眼产生视觉效果。这里介绍的简单光照模型只考虑被照明物体表面的反射光影响,假定物体表面光滑不透明且由理想材料构成,环境假设为由白光照明。
  一般来说,反射光可以分成三个分量,即环境反射、漫反射和镜面反射。环境反射分量假定入射光均匀地从周围环境入射至景物表面并等量地向各个方向反射出去,通常物体表面还会受到从周围环境来的反射光(如来自地面、天空、墙壁等的反射光)的照射,这些光常统称为环境光(Ambient Light);漫反射分量表示特定光源在景物表面的反射光中那些向空间各方向均匀反射出去的光,这些光常称为漫射光(Diffuse Light);镜面反射光为朝一定方向的反射光,如一个点光源照射一个金属球时会在球面上形成一块特别亮的区域,呈现所谓“高光(Highlight)”,它是光源在金属球面上产生的镜面反射光(Specular Light)。对于较光滑物体,其镜面反射光的高光区域小而亮;相反,粗糙表面的镜面反射光呈发散状态,其高光区域大而不亮。

光组成


        在OpenGL简单光照模型中的几种光分为:辐射光(Emitted Light)、环境光(Ambient Light)、漫射光(Diffuse Light)、镜面光(Specular Light)。
  

  • 辐射光是最简单的一种光,它直接从物体发出并且不受任何光源影响。
  • 环境光是由光源发出经环境多次散射而无法确定其方向的光,即似乎来自所有方向。一般说来,房间里的环境光成分要多些,户外的相反要少得多,因为大部分光按相同方向照射,而且在户外很少有其他物体反射的光。当环境光照到曲面上时,它在各个方向上均等地发散(类似于无影灯光)。
  • 漫射光来自一个方向,它垂直于物体时比倾斜时更明亮。一旦它照射到物体上,则在各个方向上均匀地发散出去。于是,无论视点在哪里它都一样亮。来自特定位置和特定方向的任何光,都可能有散射成分。
  • 镜面光来自特定方向并沿另一方向反射出去,一个平行激光束在高质量的镜面上产生100%的镜面反射。光亮的金属和塑料具有很高非反射成分,而象粉笔和地毯等几乎没有反射成分。因此,三某种意义上讲,物体的反射程度等同于其上的光强(或光亮度)。

创建光源


        光源有许多特性,如颜色、位置、方向等。选择不同的特性值,则对应的光源作用在物体上的效果也不一样,这在以后的章节中会逐步介绍的。下面详细讲述定义光源特性的函数glLight*():

void glLight{if}[v](GLenum light , GLenum pname, TYPE param)

        创建具有某种特性的光源。其中第一个参数light指定所创建的光源号,如GL_LIGHT0、GL_LIGHT1、...、GL_LIGHT7。第二个参数pname指定光源特性,这个参数的辅助信息见表1-3所示。最后一个参数设置相应的光源特性值。

pname 参数名 默认值 说明
GL_AMBIENT (0.0, 0.0, 0.0, 1.0) RGBA模式下环境光
GL_DIFFUSE (1.0, 1.0, 1.0, 1.0) RGBA模式下漫反射光
GL_SPECULAR (1.0,1.0,1.0,1.0) RGBA模式下镜面光
GL_POSITION (0.0,0.0,1.0,0.0) 光源位置齐次坐标(x,y,z,w)
GL_SPOT_DIRECTION (0.0,0.0,-1.0) 点光源聚光方向矢量(x,y,z)
GL_SPOT_EXPONENT 0.0 点光源聚光指数
GL_SPOT_CUTOFF 180.0 点光源聚光截止角
GL_CONSTANT_ATTENUATION 1.0 常数衰减因子
GL_LINER_ATTENUATION 0.0 线性衰减因子
GL_QUADRATIC_ATTENUATION 0.0 平方衰减因子

        以上列出的GL_DIFFUSE和GL_SPECULAR的缺省值只能用于GL_LIGHT0,其他几个光源的GL_DIFFUSE和GL_SPECULAR缺省值为(0.0,0.0,0.0,1.0)。另外,表中后六个参数的应用放在下一篇中介绍。在上面例程中,光源的创建为:

GLfloat light_position[] = { 1.0, 1.0, 1.0, 0.0 };
glLightfv(GL_LIGHT0, GL_POSITION, light_position);

        其中light_position是一个指针,指向定义的光源位置齐次坐标数组。其它几个光源特性都为缺省值。同样,我们也可用类似的方式定义光源的其他几个特性值。例如:

 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_AMBIENT , light_ambient );
 glLightfv(GL_LIGHT0, GL_DIFFUSE , light_diffuse );
 glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);

启动光照


        在OpenGL中,必须明确指出光照是否有效或无效。如果光照无效,则只是简单地将当前颜色映射到当前顶点上去,不进行法向、光源、材质等复杂计算,那么显示的图形就没有真实感,如前几章例程运行结果显示。要使光照有效,首先得启动光照,启动光照需要用到如下函数。

glEnable(GL_LIGHTING);

        若使光照无效,则调用gDisable(GL_LIGHTING)可关闭当前光照。然后,必须使所定义的每个光源有效,如果只用了一个光源。

gDisable(GL_LIGHT0);

        其它光源类似,只是光源号不同而已。

材质颜色


        OpenGL用材料对光的红、绿、蓝三原色的反射率来近似定义材料的颜色。像光源一样,材料颜色也分成环境、漫反射和镜面反射成分,它们决定了材料对环境光、漫反射光和镜面反射光的反射程度。在进行光照计算时,材料对环境光的反射率与每个进入光源的环境光结合,对漫反射光的反射率与每个进入光源的漫反射光结合,对镜面光的反射率与每个进入光源的镜面反射光结合。对环境光与漫反射光的反射程度决定了材料的颜色,并且它们很相似。对镜面反射光的反射率通常是白色或灰色(即对镜面反射光中红、绿、蓝的反射率相同)。镜面反射高光最亮的地方将变成具有光源镜面光强度的颜色。例如一个光亮的红色塑料球,球的大部分表现为红色,光亮的高光将是白色的。材质的定义与光源的定义类似:

void glMaterial{if}[v](GLenum face,GLenum pname,TYPE param);

        定义光照计算中用到的当前材质。face可以是GL_FRONT、GL_BACK、GL_FRONT_AND_BACK,它表明当前材质应该应用到物体的哪一个面上;pname说明一个特定的材质;param是材质的具体数值,若函数为向量形式,则param是一组值的指针,反之为参数值本身。非向量形式仅用于设置GL_SHINESS。另外,参数GL_AMBIENT_AND_DIFFUSE表示可以用相同的RGB值设置环境光颜色和漫反射光颜色。

参数名 默认值 说明
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_SHINESS 0.0 镜面指数(光亮度)
GL_EMISSION (0.0, 0.0, 0.0, 1.0) 材料的辐射光颜色
GL_COLOR_INDEXES (0, 1, 1) 材料的环境光、漫反射光和镜面光颜色

材质RGB值 与 光源RGB


        材质的颜色与光源的颜色有些不同。对于光源,R、G、B值等于R、G、B对其最大强度的百分比。若光源颜色的R、G、B值都是1.0,则是最强的白光;若值变为0.5,颜色仍为白色,但强度为原来的一半,于是表现为灰色;若R=G=1.0,B=0.0,则光源为黄色。对于材质,R、G、B值为材质对光的R、G、B成分的反射率。比如,一种材质的R=1.0、G=0.5、B=0.0,则材质反射全部的红色成分,一半的绿色成分,不反射蓝色成分。也就是说,若OpenGL的光源颜色为(LR、LG、LB),材质颜色为(MR、MG、MB),那么,在忽略所有其他反射效果的情况下,最终到达眼睛的光的颜色为(LRMR、LGMG、LB*MB)。
        同样,如果有两束光,相应的值分别为(R1、G1、B1)和(R2、G2、B2),则OpenGL将各个颜色成分相加,得到(R1+R2、G1+G2、B1+B2),若任一成分的和值大于1(超出了设备所能显示的亮度)则约简到1.0。

示例


        下面的示例将演示光照和材质在OpenGL上的应用。

#include <GLUT/GLUT.h>
#include <OpenGL/OpenGL.h>
 
 
// 初始化参数
void init() {
    GLfloat ambient[] = { 0.0, 0.0, 0.0, 1.0 };
    GLfloat diffuse[] = { 1.0, 1.0, 1.0, 1.0 };
//    GLfloat specular[] = { 1.0, 1.0, 1.0, 1.0 };
    GLfloat position[] = { 0.0, 0, -1.0, 0.0 };
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LESS);
    glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
    glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
//    glLightfv(GL_LIGHT0, GL_SPECULAR, specular);
    glLightfv(GL_LIGHT0, GL_POSITION, position);
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    glClearColor(0.0, 0.1, 0.1, 0.0) ;
}
 
 
// 绘图回调函数
void display() {
    GLfloat no_mat[] = { 0.0, 0.0, 0.0, 1.0 };
    GLfloat mat_ambient[] = { 0.7, 0.7, 0.7, 1.0 };
    GLfloat mat_ambient_color[] = { 0.8, 0.8, 0.2, 1.0 };
    GLfloat mat_diffuse[] = { 0.1, 0.5, 0.8, 1.0 };
    GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 };
    GLfloat no_shininess[] = { 0.0 };
    GLfloat low_shininess[] = { 5.0 };
    GLfloat high_shininess[] = { 100.0 };
    GLfloat mat_emission[] = {0.3, 0.2, 0.2, 0.0};
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
     
 
    /* 第一行第一列绘制的球仅有漫反射光而无环境光和镜面光。*/
    glPushMatrix();
    glTranslatef (-3.75, 3.0, 0.0);
    glMaterialfv(GL_FRONT, GL_AMBIENT, no_mat);
    glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
    glMaterialfv(GL_FRONT, GL_SPECULAR, no_mat);
    glMaterialfv(GL_FRONT, GL_SHININESS, no_shininess);
    glMaterialfv(GL_FRONT, GL_EMISSION, no_mat);
    glutSolidSphere(1.0, 20, 20);
    glPopMatrix();
 
     
 
    /* 第一行第二列绘制的球有漫反射光和镜面光,并有低高光,而无环境光 。*/
    glPushMatrix();
    glTranslatef (-1.25, 3.0, 0.0);
    glMaterialfv(GL_FRONT, GL_AMBIENT, no_mat);
    glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
    glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
    glMaterialfv(GL_FRONT, GL_SHININESS, low_shininess);
    glMaterialfv(GL_FRONT, GL_EMISSION, no_mat);
    glutSolidSphere(1.0, 20, 20);
 
    glPopMatrix();
 
     
 
    /* 第一行第三列绘制的球有漫反射光和镜面光,并有很亮的高光,而无环境光 。*/
    glPushMatrix();
    glTranslatef (1.25, 3.0, 0.0);
    glMaterialfv(GL_FRONT, GL_AMBIENT, no_mat);
    glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
    glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
    glMaterialfv(GL_FRONT, GL_SHININESS, high_shininess);
    glMaterialfv(GL_FRONT, GL_EMISSION, no_mat);
    glutSolidSphere(1.0, 20, 20);
    glPopMatrix();
     
 
    /* 第一行第四列绘制的球有漫反射光和辐射光,而无环境和镜面反射光。*/
    glPushMatrix();
    glTranslatef (3.75, 3.0, 0.0);
    glMaterialfv(GL_FRONT, GL_AMBIENT, no_mat);
    glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
    glMaterialfv(GL_FRONT, GL_SPECULAR, no_mat);
    glMaterialfv(GL_FRONT, GL_SHININESS, no_shininess);
    glMaterialfv(GL_FRONT, GL_EMISSION, mat_emission);
    glutSolidSphere(1.0, 20, 20);
    glPopMatrix();
     
 
    /* 第二行第一列绘制的球有漫反射光和环境光,而镜面反射光。*/
    glPushMatrix();
    glTranslatef (-3.75, 0.0, 0.0);
    glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient);
    glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
    glMaterialfv(GL_FRONT, GL_SPECULAR, no_mat);
    glMaterialfv(GL_FRONT, GL_SHININESS, no_shininess);
    glMaterialfv(GL_FRONT, GL_EMISSION, no_mat);
    glutSolidSphere(1.0, 20, 20);
    glPopMatrix();
     
 
    /* 第二行第二列绘制的球有漫反射光、环境光和镜面光,且有低高光。*/
    glPushMatrix();
    glTranslatef (-1.25, 0.0, 0.0);
    glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient);
    glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
    glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
    glMaterialfv(GL_FRONT, GL_SHININESS, low_shininess);
    glMaterialfv(GL_FRONT, GL_EMISSION, no_mat);
    glutSolidSphere(1.0, 20, 20);
    glPopMatrix();
 
 
    /* 第二行第三列绘制的球有漫反射光、环境光和镜面光,且有很亮的高光。*/
    glPushMatrix();
    glTranslatef (1.25, 0.0, 0.0);
    glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient);
    glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
    glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
    glMaterialfv(GL_FRONT, GL_SHININESS, high_shininess);
    glMaterialfv(GL_FRONT, GL_EMISSION, no_mat);
    glutSolidSphere(1.0, 20, 20);
    glPopMatrix();
  
 
    /* 第二行第四列绘制的球有漫反射光、环境光和辐射光,而无镜面光。*/
    glPushMatrix();
    glTranslatef (3.75, 0.0, 0.0);
    glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient);
    glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
    glMaterialfv(GL_FRONT, GL_SPECULAR, no_mat);
    glMaterialfv(GL_FRONT, GL_SHININESS, no_shininess);
    glMaterialfv(GL_FRONT, GL_EMISSION, mat_emission);
    glutSolidSphere(1.0, 20, 20);
    glPopMatrix();
 
 
    /* 第三行第一列绘制的球有漫反射光和有颜色的环境光,而无镜面光。*/
    glPushMatrix();
    glTranslatef (-3.75, -3.0, 0.0);
    glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient_color);
    glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
    glMaterialfv(GL_FRONT, GL_SPECULAR, no_mat);
    glMaterialfv(GL_FRONT, GL_SHININESS, no_shininess);
    glMaterialfv(GL_FRONT, GL_EMISSION, no_mat);
    glutSolidSphere(1.0, 20, 20);
    glPopMatrix();
     
 
    /* 第三行第二列绘制的球有漫反射光和有颜色的环境光以及镜面光,且有低高光。*/
    glPushMatrix();
    glTranslatef (-1.25, -3.0, 0.0);
    glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient_color);
    glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
    glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
    glMaterialfv(GL_FRONT, GL_SHININESS, low_shininess);
    glMaterialfv(GL_FRONT, GL_EMISSION, no_mat);
    glutSolidSphere(1.0, 20, 20);
    glPopMatrix();
     
 
    /* 第三行第三列绘制的球有漫反射光和有颜色的环境光以及镜面光,且有很亮的高光。*/
    glPushMatrix();
    glTranslatef (1.25, -3.0, 0.0);
    glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient_color);
    glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
    glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
    glMaterialfv(GL_FRONT, GL_SHININESS, high_shininess);
    glMaterialfv(GL_FRONT, GL_EMISSION, no_mat);
    glutSolidSphere(1.0, 20, 20);
    glPopMatrix();
 
 
    /* 第三行第四列绘制的球有漫反射光和有颜色的环境光以及辐射光,而无镜面光。*/
    glPushMatrix();
    glTranslatef (3.75, -3.0, 0.0);
    glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient_color);
    glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
    glMaterialfv(GL_FRONT, GL_SPECULAR, no_mat);
    glMaterialfv(GL_FRONT, GL_SHININESS, no_shininess);
    glMaterialfv(GL_FRONT, GL_EMISSION, mat_emission);
    glutSolidSphere(1.0, 20, 20);
    glPopMatrix();
    // 执行绘图命令
    glFlush();
}
 
 
// 窗口大小变化回调函数
void reshape(int w, int h) {
    glViewport(0, 0, w, h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(60.0, (GLfloat)w/(GLfloat)h, 0.1, 100000.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    gluLookAt(0, 0, 10, 0, 0, -1, 0, 1, 0);
}
 
 
int main(int argc, const char * argv[]) {
    // 初始化显示模式
    glutInit(&argc, const_cast<char **>(argv));
    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA);

 
    // 初始化窗口
    glutInitWindowSize(500, 500);
    glutInitWindowPosition(100, 100);
    glutCreateWindow(argv[0]);

 
    init();
    glutReshapeFunc(reshape);
    glutDisplayFunc(display);
 
    // 开始主循环绘制
    glutMainLoop();
    return 0;
}

运行效果如下图:
      在这里插入图片描述

发布了54 篇原创文章 · 获赞 80 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_41685265/article/details/104367130