一、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. 最大流算法---Edmond-Karp

    这个算法是基于FF方法,就是通过不断求残余网络的增广路来增广流量,直到找不到增广路为止.注意:每次找到增广路以后都要更新原网络.EK算法通过BFS寻找源S到汇T的一条最短路径,因此时间复杂度是O(VE ...

  2. HDU-4972 A simple dynamic programming problem

    http://acm.hdu.edu.cn/showproblem.php?pid=4972 ++和+1还是有区别的,不可大意. A simple dynamic programming proble ...

  3. 【转】unity3d 如何得到当前物体播放的动画

    原文:http://blog.csdn.net/smilelance/article/details/22285125 public static string GetCurrentPlayingAn ...

  4. socket编程五种模型

    客户端:创建套接字,连接服务器,然后不停的发送和接收数据. 比较容易想到的一种服务器模型就是采用一个主线程,负责监听客户端的连接请求,当接收到某个客户端的连接请求后,创建一个专门用于和该客户端通信的套 ...

  5. HDU 1520 Anniversary party [树形DP]

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1520 题目大意:给出n个带权点,他们的关系可以构成一棵树,问从中选出若干个不相邻的点可能得到的最大值为 ...

  6. 细谈Java

    重载:相同函数名,不同参数. 重写(覆写):父类和子类之间的,子类重写了父类的方法. java的多态:重载+覆写 1.      Main方法: 是public的,也是static,也是void的,参 ...

  7. ASP.NET与SOAP协议使用记录

    近期初次接手一个公司的管理系统开发任务,因为公司需要有Android,IOS客户端,又要求有PC端的网页客户端....对服务请求的要求自然也就落在了统一接口访问上了.... 使用ASP.NET的WEB ...

  8. c#委托和事件(上)

    C# 中的委托和事件 引言 委托 和 事件在 .Net Framework中的应用非常广泛,然而,较好地理解委托和事件对很多接触C#时间不长的人来说并不容易.它们就像是一道槛儿,过了这个槛的人,觉得真 ...

  9. 在Windows上安装私有GitHub的开源替代-GitLab

    在我之前的一篇博客中介绍过GitLab: 开源免费的git管理工具,今天说一下怎么在windows安装GitLab. BitNami可以很容易的帮助你安装开源应用,和Helicon Zoo类似,我之前 ...

  10. linux操作系统cron详解

    Linux操作系统定时任务系统 Cron 入门 cron是一个linux下的定时执行工具,可以在无需人工干预的情况下运行作业.由于Cron 是Linux的内置服务,但它不自动起来,可以用以下的方法启动 ...