OpenGL把现实世界中的光照系统近似归为三部分,分别是光源、材质和光照环境。

光源就是光的来源,是“光”这种物质的提供者; 材质是指被光源照射的物体的表面的反射、漫反射(OpenGL不考虑折射)特性;

材质反映的是光照射到物体上后物体表现出来的对光的吸收、漫反射、反射等性能;

光照环境反应环境中所有光源发出的光经过无数次反射、漫反射之后整体环境所表现出来的光照效果。指定合适的光照环境参数可以使得最后形成的画面更接近于真实场景。

一、光源

光照模型

OpenGL中的光照模型中的反射光分为三个分量,分别是环境反射光(Ambient Light)、漫反射光(Diffuse Light)和镜面反射光(Specular Light)。

  • 环境光Ambient:是由光源发出经环境多次散射而无法确定其入射方向的光,即似乎来自所有方向。其特征是入射方向和出射方向均为任意方向。
  • 漫射光Diffuse:来自特定方向,它垂直于物体时比倾斜时更明亮。一旦它照射到物体上,则在各个方向上均匀地发散出去,效果为无论视点在哪里它都一样亮,其特征是入射方向唯一、出射方向为任意方向。
  • 镜面光Specular:来自特定方向并沿另一方向反射出去,一个平行激光束在高质量的镜面上产生100%的镜面反射,其特征是入射方向和出射方向均唯一。

创建光源

OpenGL中用函数glLightfv来创建光源,函数原型是:

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

第一个参数light指定所创建的光源号,如GL_LIGHT0、GL_LIGHT1、...、GL_LIGHT7。

第二个参数pname指定光源特性,这个参数的具体信息见下表所示。

第三个参数设置相应的光源特性值。

例如下边定义了一个位置在(0,0,0),没有环境光,镜面反射光和漫反射光都为白光的光源:

GLfloat light_position[] = { 0.0, 0.0, 0.0, 0.0 };
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_POSITION, light_position);
glLightfv(GL_LIGHT0, GL_AMBIENT , light_ambient );
glLightfv(GL_LIGHT0, GL_DIFFUSE , light_diffuse );
glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);

光源的位置坐标采用齐次坐标(x, y, z, w)设置。第四个参数w为0.0时,定义相应的光源是定向光源,其所有的光线几乎是互相平行的,典型的如太阳光。光源方向由定义的坐标(x, y, z)指向(0,0,0);

w为1.0时,光源为定位光源。(x, y, z, w)指定光源在齐次坐标系下的具体位置,该位置会根据模型视点矩阵进行变换。

光源的衰减

离光源越远则光强越弱。由于定向光源是模拟的无穷远得光源,所以不会根据距离改变而衰减,所以在定向光源中是禁用衰减的; 对于定位光源有衰减。OpenGL的光衰减是通过光源的发光量乘以衰减因子来实现衰减的。

衰减系数=1/(K0+K1*D+K2*D2)

其中:  D=光源位置与顶点之间的距离

K0= GL_CONSTANT_ATTENUATION       //常数衰减因子

K1= GL_LINER_ATTENUATION               // 线性衰减因子

K2= GL_QUADRATIC_ATTENUATION    // 二次衰减因子

OpenGL中默认的衰减因子为(1,0,0),即不进行衰减。

设置好以上光源的属性之后,要使用glEnable(GL_LIGHTING)和glEnable(GL_LIGHTX)来启用光照和第X号光源。

二、 材质


OpenGL用材质对光的红、绿、蓝三原色的反射率来近似定义材料的颜色。

物体的材质跟光源一样,也分为环境、漫反射和镜面反射成分,它们决定了材料对环境光、漫反射光和镜面反射光的反射程度。其中对环境光和漫反射光的反射程度决定了物体的颜色。

比如对于一朵红色的花,它对绿色和蓝色的反射能力比较弱,对红色分量的反射能力比较强,所以呈现出来是红色。材质的镜面反射率在RGB三个分量上通常是一致的,即反射的光跟光源的颜色基本是一致的,只不过强度会减弱。镜面反射光的强度还取决于观察点的位置,当观察点正好处于入射光的反射光线上,亮斑的亮度达到最大值。

这3个材质的属性都是反应的物体对外界光线的反射情况,有些物体本身可以发射弱光,OpenGL中是通过设置材料的辐射光来实现的,可以使物体看起来像是发射出设定的辐射光一样,以达到特殊的效果。物体的辐射光使用glMaterialfv(GL_FRONT, GL_EMISSION,   earth_mat_emission)来设置。

总体来说材质定义了物体对环境光、漫反射光、镜面光的反射(吸收)能力。我们看到的物体的颜色(或亮度)是光源的颜色(或亮度)经过物体的材质反射(吸收)之后发散出来的颜色(或亮度)。

定义材质的函数使用glMaterialfv,函数原型是:

void  glMaterialfv (GLenum face, GLenum pname, const GLfloat *params);

第一个参数face可以是GL_FRONT、GL_BACK、GL_FRONT_AND_BACK,它表明当前材质应该应用到物体的哪一个面上;

第二个参数pname指定正在设定的材质特性,这个参数的辅助信息下表所示:

第三个params参数设置相应的材质的特性值。

三、 光照环境

光照环境是指该环境中的光线不是来自于特定的光源,它是一个全局环境光,即那些在环境中经过了充分散射的光,这个光在环境中物体的各个表面上均匀泛射,环境中所有的物体都会受到该环境光的影响。

使用函数flLightModelfv来设定环境光,如下定义了一个微微发出蓝光的环境光,在这种情况下,即使环境中没有光源存在,也可以看到场景中的物体:

GLfloat mat_ambient[]   = {0.0f, 0.0f, 0.2f, 1.0f};
glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient);

总结一下在OpenGL中加入光照的步骤为:

  • 1. 设置光源参数: 需要多次调用带有不同参数的glLightfv函数,设置环境光(Ambient Light)、漫射光(Diffuse Light)、镜面光(Specular Light)和光照位置(Position)等。
  • 2. 开启光照,使用glEnable(GL_LIGHTING)和glEnable(GL_LIGHTXX)来开启光照和XX号光源,前者相当于光       源的总开关,后者是对应的开启相应号数的光源。 第3步是法线的设置,本文不涉及。

下图是对光照应用的例子,红色球代表太阳,材质的辐射光为红光,绿色球代表地球,绕太阳公转,材质的辐射光为蓝光,镜面反射光为红色(蓝色地球上的红色区域):

另一种演示效果,设置太阳的辐射演示为白色,地球的镜面反射为白色,漫反射为红色:

完整代码如下,可以设置不同的材质属性,查看不同的效果:

#include <gl/glut.h>
#include <Windows.h> static GLfloat angle = 0.0f;
void myDisplay(void)
{
glClearColor(0.3,0.7,0.5,0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //清理颜色和深度缓存 // 创建透视效果视图
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(80.0f, 1.0f, 1.0f, 20.0f); glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0.0, 12.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}; //RGBA模式的环境光,为0
GLfloat sun_light_diffuse[] = {1.0f, 1.0f, 1.0f, 1.0f}; //RGBA模式的漫反射光,全白光
GLfloat sun_light_specular[] = {1.0f, 1.0f, 1.0f, 1.0f}; //RGBA模式下的镜面光 ,全白光
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}; //定义材质的环境光颜色,为0
GLfloat sun_mat_diffuse[] = {0.0f, 0.0f, 0.0f, 1.0f}; //定义材质的漫反射光颜色,为0
GLfloat sun_mat_specular[] = {0.0f, 0.0f, 0.0f, 1.0f}; //定义材质的镜面反射光颜色,为0
GLfloat sun_mat_emission[] = {0.8f, 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(3.0, 40, 32);
} // 定义地球的材质并绘制地球
{
GLfloat earth_mat_ambient[] = {0.0f, 0.0f, 1.0f, 1.0f}; //定义材质的环境光颜色,骗蓝色
GLfloat earth_mat_diffuse[] = {0.0f, 0.0f, 0.5f, 1.0f}; //定义材质的漫反射光颜色,偏蓝色
GLfloat earth_mat_specular[] = {1.0f, 0.0f, 0.0f, 1.0f}; //定义材质的镜面反射光颜色,红色
GLfloat earth_mat_emission[] = {0.0f, 0.0f, 0.0f, 1.0f}; //定义材质的辐射光颜色,为0
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(7.0f, 0.0f, 0.0f);
glutSolidSphere(3.0, 40, 32);
}
Sleep(10);
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(400, 400);
glutCreateWindow("OpenGL光照演示");
glutDisplayFunc(&myDisplay);
glutIdleFunc(&myIdle);
glutMainLoop();
return 0;
}

OpenGL(七) 光照模型及设置的更多相关文章

  1. OpenGL ES 光照模型之——漫反射光(RenderMonkey测试,地球日出效果)

    概述及目录(版权所有,请勿转载 http://www.cnblogs.com/feng-sc) 本文在上一篇(OpenGL ES 光照模型之——环境光照(RenderMonkey测试))环境光基础上, ...

  2. SharpGL学习笔记(九) OpenGL的光照模型, 术语解释

    在3D场景中,每个像素最终显示出来的颜色都是经过大量计算而得到的,其中一些计算是依赖于场景中的光照以及场景中物体对光线的反射和吸收情况. 例如,对于一个红色的物体, 在白色光(白光是红光,绿光和蓝光等 ...

  3. OpenGL ES 光照模型之——环境光照(RenderMonkey测试)

    概述及目录(版权所有,请勿转载 www.cnblogs.com/feng-sc/) 本文总结如何在RenderMonkey下做简单的OpenGL ES环境光光照模型测试. 主要包括如下内容: 1.使用 ...

  4. 关于OpenGL游戏全屏模式的设置

    使用DirectX的API的话可以给游戏窗口设置指定的显示器和全屏独占模式,但是如果使用OpenGL的API就比较遗憾不能直接设置. 以下内容基于Windows系统. 如果使用OpenGL渲染,第一步 ...

  5. Linux 系统常用命令汇总(七) 安全设置

     安全设置 分类 命令 选项 注解 安全策略 selinux setenforce number(0,1) 设置selinux状态,0关闭,1开启 getenforce 显示当前selinux状态,e ...

  6. OpenGL的glViewPort窗口设置函数实现分屏

    之前实现过全景图片查看(OpenGL的几何变换3之内观察全景图),那么我们需要进行分屏该如何实现呢?如下图: 没错就是以前提过的glViewPort函数,废话不多说了,我直接上代码: //从这里开始进 ...

  7. Java开发桌面程序学习(七)——ImageView设置图片以及jar包读取fxml文件

    ImageView设置图片 JavaFx的ImageView,设置图片不能直接通过属性设置,只能通过代码来设置 ImageView设置图片 首先,我们让fxml对应的那个controller的java ...

  8. OpenGL光照设置

    一.设置光源 (1)光源的种类 环境光 环境光是一种无处不在的光.环境光源放出的光线被认为来自任何方向.因此,当你仅为场景指定环境光时,所有的物体无论法向量如何,都将表现为同样的明暗程度. 点光源 由 ...

  9. OpenGL(三) RGBA颜色设置

    OpenGL支持两种颜色模式:一种是RGBA,一种是颜色索引模式. 像素点附加颜色信息之后,就必须为每一个像素点额外分配一个内存空间保存该点的颜色信息,对于RGBA颜色模式,保存的数据直接代表了颜色, ...

随机推荐

  1. iOS Universal Static Framework 手动转 XCode Cocoa Framework

    不须要又一次创建Project,手动改动project设置. 第一步:在Project文件里,改动type,去掉static 1. 搜索wrapper.framework.static,去掉stati ...

  2. Node.js日志框架选型比較:Bunyan

    前一篇Node.js日志框架选型比較:Winston Bunyan Bunyan(by Trent Mick)是另外一个值得考虑的日志框架,以稍微不同的方式处理结构化,机器可读性被重点对待. 其结果是 ...

  3. 【Redis源代码剖析】 - Redis内置数据结构之压缩字典zipmap

    原创作品,转载请标明:http://blog.csdn.net/Xiejingfa/article/details/51111230 今天为大家带来Redis中zipmap数据结构的分析,该结构定义在 ...

  4. VMware Workstation 12 安装mac os x 10.11

    本人近期在学习iOS开发,由于初学,购买设备有点太昂贵了点.和我有意向想法的朋友能够看看在这篇文章.在虚拟机里装MAC os系统. 第一步:准备 VMware Workstation 12版本号 ma ...

  5. Qt 连接MySQL数据库(很多相关文章)

    今天想试试Qt如何连接数据库的. 谁知怎么写完了提示driver not loaded我就郁闷了. 我自己是 VS2010 + Qt4.8.4 + MySQL5.1 的环境 网上查到是 C:\Qt\4 ...

  6. 【hdu 3537】Daizhenyang's Coin

    Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submission(s) ...

  7. Myeclipse - Web项目转换技巧--处理Java项目、SVN非Web项目问题

    喜欢从业的专注,七分学习的态度. 概述 对于Java调试,使用Eclipse习惯性的使用Junit调试,使用Myeclipse习惯性的将项目转成Web项目在Tomcat或Weblogic中调试,在My ...

  8. [redis] redis配置文件redis.conf的详细说明

    # Redis 配置文件 # 当配置中需要配置内存大小时,可以使用 1k, 5GB, 4M 等类似的格式,其转换方式如下(不区分大小写) # # 1k => bytes # 1kb => ...

  9. 解决eclipse 保存卡顿的问题

    开发十年,就只剩下这套Java开发体系了 >>>   eclipse 如果启动慢,还可以接收. 可是如果是 保存的时候卡顿, 有时候会 卡顿 3秒-5 秒的,感觉到写代码特别的不顺畅 ...

  10. 【34.40%】【codeforces 711D】Directed Roads

    time limit per test2 seconds memory limit per test256 megabytes inputstandard input outputstandard o ...