一、OpenGL光源简介

OpenGL提供了多种形式的光源,如点光源平行光源聚光灯光源等。所有光源都使用 glLight*接口来设置光源属性,其中包括 glLight{if}glLight{if}v 两类。

1、示例光源

GLfloat ambient[] = {0.3f, 0.3f, 0.3f, 1.0f};  // 环境强度
GLfloat diffuse[] = {1.0f, 1.0f, 1.0f, 1.0f}; // 散射强度
GLfloat specular[] = {1.0f, 1.0f, 1.0f, 1.0f}; // 镜面强度 // 点光源, GL_POSITION属性的最后一个参数为1
GLfloat position[] = {-3.0f, -3.4f, -8.8f, 1.0f};
glLightfv(GL_LIGHT0, GL_POSITION, position);
glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
glLightfv(GL_LIGHT0, GL_SPECULAR, specular); // 平行光源, GL_POSITION属性的最后一个参数为0
GLfloat direction[] = {-3.0f, -3.4f, -8.8f, 0.0f};
glLightfv(GL_LIGHT1, GL_POSITION, direction);
glLightfv(GL_LIGHT1, GL_AMBIENT, ambient);
glLightfv(GL_LIGHT1, GL_DIFFUSE, diffuse);
glLightfv(GL_LIGHT1, GL_SPECULAR, specular); // 聚光灯光源, 需要指定位置、方向、光锥半角
GLfloat spot_direction[] = {-3.0f, -3.4f, -8.8f};
glLightfv(GL_LIGHT2, GL_POSITION, position);
glLightfv(GL_LIGHT2, GL_SPOT_DIRECTION, spot_direction);
glLightfv(GL_LIGHT2, GL_SPOT_CUTOFF, 45.0);
glLightfv(GL_LIGHT2, GL_AMBIENT, ambient);
glLightfv(GL_LIGHT2, GL_DIFFUSE, diffuse);
glLightfv(GL_LIGHT2, GL_SPECULAR, specular);

2、注意事项

  • 最大光源数:不同的硬件支持的光源数量不一样,但至少会支持8个光源。表示光源的常量有GL_LIGHT0、GL_LIGHT1、GL_LIGHT2、...、GL_LIGHT7、...等。在片段着色中可通过gl_LightSource[0]、gl_LightSource[1]、gl_LightSource[2]、...、gl_LightSource[7]、...等内建变量访问各个光源的参数;
  • 启用和关闭光源 :可通过glEnable(GL_LIGHTING)启用光照机制,然后使用glEnable(GL_LIGHTx)glDisable(GL_LIGHTx)打开或关闭相应光源(其中x代表光源序号);
  • 模型顶点必须指定法向:OpenGL光照机制是通过计算物体表面法向与入射光线的夹角来确定表面的亮度。故若传入的模型没有指定法向,则最终结果会变得一片漆黑;若法向有问题,最终结果也会莫名其妙。

二、控制光源的位置和方向

控制光源的矩阵变换和控制图元的矩阵变换相同,故最终光源表现出来的性质(如点光源位置是固定在世界坐标系某点还是跟随镜头移动,平行光源的方向在世界坐标系下是不变的还是跟随相机移动等)与提交光源位置或朝向(glLight*())和视点变换(gluLookAt())的先后顺序是息息相关的。据此我们可以定义出各式各样的常见光源,如太阳光、白炽灯、汽车前照灯等。

1、定义在世界坐标系下的光源

如果在视点变换后提交光源位置或朝向,那么光源就可以看作一个普通的几何对象,提交的坐标是在世界坐标系中度量的,对普通几何对象的各种变换同样适用于光源。可通俗的理解为视图变换矩阵作用于光源的位置或朝向参数上,此过程就如同世界坐标系下的普通物体转换至观察坐标系下。如果程序里没有视点变换,说明世界坐标系和摄像机坐标系重合,光源也可以看作一个普通的几何对象。表现出这种性质的常见光源有太阳光,家里的白炽灯等。示例代码如下:

 void myDisplay()
{
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity(); gluLookAt(0, 0, 0, 0, 0, -1, 0, 1, 0);
GLfloat sun_light_position[] = {-139.5f, -153.4f, -68.8f, 0.0f};
glLightfv(GL_LIGHT0, GL_POSITION, sun_light_position); // 光源的其他参数可在程序初始化时设置 glPushMatrix();
glTranslated(-2.5, 6.9, -184.8);
glRotated(87.4, 0, 0, 1);
drawOBJ();
glPopMatrix();
...
}

注意:光源位置或朝向的指定不能处于某个模型的模型变换代码之间(如上例中的glPushMatrix()与glPopMatrix()之间),否则光源参数会受到影响。所以最好将光源位置或朝向设置代码放在紧跟gluLookAt之后。

2、定义在相机坐标系下的光源

如果在视点变换前提交光源位置,视点和光源将捆绑在一起,即二者相对位置不变,一起运动。此时,可以理解为提交的光源位置是在相机坐标系中度量的(位置参数的默认值是(0.0, 0.0, 1.0, 0.0), 就是在摄像机坐标系中度量的)。亦可通俗的理解为视图变换矩阵未作用于光源的位置或朝向参数上。光源的位置朝向参数在观察坐标系的值会保持不变。表现出这种性质的常见光源有汽车前照灯(以驾驶员的视角观察视角)或矿工头上的矿灯。示例代码如下:

 void myDisplay()
{
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity(); GLfloat sun_light_position[] = {-139.5f, -153.4f, -68.8f, 0.0f};
glLightfv(GL_LIGHT0, GL_POSITION, sun_light_position); // 光源的其他参数可在程序初始化时设置
gluLookAt(0, 0, 0, 0, 0, -1, 0, 1, 0); glPushMatrix();
glTranslated(-2.5, 6.9, -184.8);
glRotated(87.4, 0, 0, 1);
drawOBJ();
glPopMatrix();
...
}

OpenGL光源位置的更多相关文章

  1. openGL光源概念

    1. 光照模型      环境光——经过多次反射而来的光称为环境光,无法确定其最初的方向,但当特定的光源关闭后,它们将消失. 全局环境光——每个光源都能对场景提供环境光.此外,还有一个环境光,它不来自 ...

  2. OpenGL中glPushMatrix和glPopMatrix的原理

    glPushMatrix.glPopMatrix操作事实上就相当于栈里的入栈和出栈. 很多人不明确的可能是入的是什么,出的又是什么. 比如你当前的坐标系原点在你电脑屏幕的左上方.如今你调用glPush ...

  3. 使用glPushMatrix和glPopMatrix的原因

    转自 百度百科   glPushMatrix 函数将当前矩阵堆栈推送,通过一个,复制当前矩阵. 这就是后 glPushMatrix 的调用堆栈的顶部矩阵是它下面的相同的.   1. 原理讲解 终于明白 ...

  4. OpenGL光照3:光源

    本文是个人学习记录,学习建议看教程 https://learnopengl-cn.github.io/ 非常感谢原作者JoeyDeVries和多为中文翻译者提供的优质教程 的内容为插入注释,可以先跳过 ...

  5. Opengl使用模型视图变换移动光源

    光源绕一个物体旋转,按下鼠标左键时,光源位置旋转. #include <GL/glut.h> static int spin = 0;static GLdouble x_1 = 0.0;s ...

  6. opengl 笔记(2)

    /*- * Opengl Demo Test * * Fredric : 2016-7-10 */ #include <GLUT/GLUT.h> #include <stdlib.h ...

  7. CSharpGL(39)GLSL光照示例:鼠标拖动太阳(光源)观察平行光的漫反射和镜面反射效果

    CSharpGL(39)GLSL光照示例:鼠标拖动太阳(光源)观察平行光的漫反射和镜面反射效果 开始 一图抵千言.首先来看鼠标拖动太阳(光源)的情形. 然后是鼠标拖拽旋转模型的情形. 然后我们移动摄像 ...

  8. OpenGL阴影,Shadow Volumes(附源程序,使用 VCGlib )

    实验平台:Win7,VS2010 先上结果截图:    本文是我前一篇博客:OpenGL阴影,Shadow Mapping(附源程序)的下篇,描述两个最常用的阴影技术中的第二个,Shadow Volu ...

  9. OpenGL阴影,Shadow Mapping(附源程序)

    实验平台:Win7,VS2010 先上结果截图(文章最后下载程序,解压后直接运行BIN文件夹下的EXE程序): 本文描述图形学的两个最常用的阴影技术之一,Shadow Mapping方法(另一种是Sh ...

随机推荐

  1. 使用Struts2开发Java Web应用程序(目录)

    连接地址 http://blog.csdn.net/struts2/article/details/1721752

  2. HDU-4952 Number Transformation

    http://acm.hdu.edu.cn/showproblem.php?pid=4952 Number Transformation Time Limit: 2000/1000 MS (Java/ ...

  3. VS2010 MFC GDI+ 实现PNG透明图片显示

    网上找了一些资料学习了一下PNG图的显示,这里总结一下. 参考:http://blog.csdn.net/czyt1988/article/details/7965066 一.VS2010配置GDI+ ...

  4. C++之友元函数

    1.为什么要引入友元函数:在实现类之间数据共享时,减少系统开销,提高效率 具体来说:为了使其他类的成员函数直接访问该类的私有变量 即:允许外面的类或函数去访问类的私有变量和保护变量,从而使两个类共享同 ...

  5. poj 1328 Radar Installation【贪心区间选点】

    Radar Installation Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 20000/10000K (Java/Other) ...

  6. 389. Find the Difference

    一开始没看见shuffle...觉得同时遍历不就完事了.. 和那个所有数字出现2,有一个出现3次还是什么的一样,CHAR可以完美和INT相互切换. public class Solution { pu ...

  7. BufferedInputStream详解

    BufferedInputStream是一个带有缓冲区域的InputStream,它的继承体系如下:  InputStream  |__FilterInputStream          |__Bu ...

  8. BA/PM Competency Module

    No Competency Description BA Weight% PM Weight% 1 Business Analysis:BA   Track Maps   process flows, ...

  9. 屏蔽全部统计代码(51.la cnzz 百度统计 谷歌分析师adsense、屏蔽淘宝客广告代码)的方法

    支持百度统计 .51.la统计.cnzz统计.51yes统计.谷歌分析师.阿里妈妈淘宝客广告.chinaz弹窗.假设有很多其它的须要屏蔽的,欢迎联系 default7#zbphp.com 改动etc的 ...

  10. HDU 2069 Coin Change

    Coin Change Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total S ...