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. 利用java反射将结果集封装成为对象和对象集合

    java反射机制是什么 反射机制是在运行状态中,可以知道任何一个类的属性和方法,并且调用类的属性和方法: 反射机制能够做什么 1.判断运行对象的所属类 2.构造任意一个类的对象 3.获取任意一个类的属 ...

  2. DOS命令具体解释

    net use $">\\ip\ipc$Content$nbsp;" " /user:" " 建立IPC空链接   net use $" ...

  3. docker 在运行 aspnetcore 镜像时提示 命令找不到

    不要讲路径映射到镜像中的应用根文件夹 例如默认的 /app

  4. 【2016 Summary】为过往补课、为将来夯实

    前言 看了CSDN上非常多"我的2016"年终总结,也就不能免俗地来写一波.按着时间轴捋一捋这过去一年的经过,也算是这元旦假期总一个午后的休闲时光了.(结果没想到的是午饭前開始写的 ...

  5. Android 节日短信送祝福(UI篇:3-选择短信与发送短信的Activity的实现)

    一.ChooseMsgActivity的实现 1.布局文件 <RelativeLayout xmlns:android="http://schemas.android.com/apk/ ...

  6. linux下的多线程,pthread_create函数

    pthread_create是UNIX环境创建线程函数 头文件 #include<pthread.h> 函数声明 int pthread_create(pthread_t*restrict ...

  7. SNMP 配置

    http://blog.sina.com.cn/s/blog_593bf1da0100xsvu.html

  8. Android下载文件提示文件不存在。。。 java.io.FileNotFoundException

    遇到这个错误java.io.FileNotFoundException,事实上文件是存在的,把地址复制到手机浏览器都能够直接下载的,但为嘛不能下载呢. Error in downloadBitmap ...

  9. git自己操作命令组集合

    git自己操作命令组集合 一.总结 一句话总结: 1.官方有非常详细的中文文档资料,任何组件或者插件记得看有没有文档资料,这个用起来快,配合百度. 2.git clone命令是直接把git仓库上面的代 ...

  10. _Decoder_Interface_init xxxxxx in amrFileCodec.o

    Undefined symbols for architecture arm64: "_Decoder_Interface_init", referenced from: Deco ...