Lighting:https://www.evl.uic.edu/julian/cs488/2005-11-03/index.html

光照

OpenGL中的光照(Linghting)是很重要的,为什么重要?请看下图

上图中左图是有光照的效果,右图是没有光照的效果。

有光照的好处:

  • 给人更多关于曲率和深度的视觉感受
  • 给人更明显的3D效果

隐藏面清除

在照明和着色中,深度信息和法向量变得非常重要。

旧的painter算法是这样的:

while (1) {

get_viewing_point_from_mouse_position();

glClear(GL_COLOR_BUFFER_BIT);

draw_3d_object_A();

draw_3d_object_B();

}

这样的话,一个对象可能会遮挡另一个对象

隐藏面清除通过使用Z-buffer(深度缓存)来实现

请看如下的代码示例:

glutInitDisplayMode ( GLUT_DEPTH | ... );

glEnable ( GL_DEPTH_TEST );

...

while(1) {

glClear( GLCOLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

get_viewing_point_from_mouse_position();

draw_3d_object_A();

draw_3d_object_B();

}

光照组成

  • 环境光(Ambient)

光从各个方向均匀地到达。事实上,光散射太大,我们无法确定它的方向

  • 散射光(Diffuse)

来自点光源的光线将被漫射反射(即在远离表面的所有方向上均匀地重新选择)

  • 镜面光(Specular)

从点光源发出的光线将被镜面反射(即以镜面形式反射,如从光亮的表面反射)。

  •     放射光(Emissive)

在没有入射光的情况下,表面的发射率控制着表面发出的光的数量。从一个表面发出的光不能作为照亮其他表面的光源;相反,它只影响观察者看到的颜色。

多个灯光组件结果

光照和材料的RGB

    RGB values for light and material have different meanings

For light: light colors(intensities)

(R, G, B) = (1, 1, 0) -> yellow light

For material: reflected proportions

(R, G, B) = (1, 0.5, 0) -> the material reflects all the incoming red light, half the incoming green light, and nonn of the incoming blue light.

( LR*MR, LG*MG, LB*MB )

Multiple light source: Light1 + Light2

( R1+R2, G1+G2, B1+B2 )

If the result is greater than 1.0, clamp to 1.0

光照例子

为所有对象的每个顶点定义法向量。这些法线确定对象相对于光源的方向。(在我们的示例中,法线定义为glutsolidSphere()的一部分)

  • Needs unit normal vector
  • void glEnable(GL_NORMALIZE)
  • void glEnable(GL_RESCALE_NORMAL)

Create, select, and position one or more light sources.

可以创建最多8中不同的光源(GL_LIGHT0 to GL_LIGHT7),但是光源多了会导致更多的计算复杂性。

创建并选择照明模型(Light Mode),该模型定义全局环境光的级别和视点的有效位置(用于照明计算)。

为场景中的对象定义材质属性。

#include <gl/glut.h>

#pragma comment(linker, "/subsystem:windows /ENTRY:mainCRTStartup")

/* Initialize material property, light source, lighting model,

* and depth buffer.

*/

void init(void)

{

GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 };

GLfloat mat_shininess[] = { 50.0 };

GLfloat light_position[] = { 1.0, 1.0, 1.0, 0.0 };

GLfloat light[] = { 1.0, 0.2, 0.2 };

GLfloat lmodel_ambient[] = { 0.1, 0.1, 0.1, 1.0 };

glClearColor (0.0, 0.0, 0.0, 0.0);

glShadeModel (GL_SMOOTH);

glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);

glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);

glLightfv(GL_LIGHT0, GL_POSITION, light_position);

glLightfv(GL_LIGHT0, GL_DIFFUSE, light );

glLightfv(GL_LIGHT0, GL_SPECULAR, light );

glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);

glEnable(GL_LIGHTING);

glEnable(GL_LIGHT0);

glEnable(GL_DEPTH_TEST);

}

void display(void)

{

glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glutSolidSphere (1.0, 20, 16);

glFlush ();

}

void reshape (int w, int h)

{

glViewport (0, 0, (GLsizei) w, (GLsizei) h);

glMatrixMode (GL_PROJECTION);

glLoadIdentity();

if (w <= h)

glOrtho (-1.5, 1.5, -1.5*(GLfloat)h/(GLfloat)w,

1.5*(GLfloat)h/(GLfloat)w, -10.0, 10.0);

else

glOrtho (-1.5*(GLfloat)w/(GLfloat)h,

1.5*(GLfloat)w/(GLfloat)h, -1.5, 1.5, -10.0, 10.0);

glMatrixMode(GL_MODELVIEW);

glLoadIdentity();

}

int main(int argc, char** argv)

{

glutInit(&argc, argv);

glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH);

glutInitWindowSize (500, 500);

glutInitWindowPosition (100, 100);

glutCreateWindow (argv[0]);

init ();

glutDisplayFunc(display);

glutReshapeFunc(reshape);

glutMainLoop();

return 0;

}

光照API

void glLight{if}(GLenum light, GLenum pname, TYPE param);

void glLight{if}v(GLenum light, GLenum pname, TYPE *param);

Creates the light specified by light, which can be GL_LIGHT0, GL_LIGHT1, ... , or GL_LIGHT7. The characteristic of the light being set is defined by pname, which specifies a named parameter (see Table below). param indicates the values to which the pname characteristic is set; it's a pointer to a group of values if the vector version is used, or the value itself if the nonvector version is used. The nonvector version can be used to set only single-valued light characteristics.

衰减(定义光衰减的强度)

对于现实世界中的灯光,灯光强度随着与灯光的距离的增加而降低。由于定向光无限远,因此在距离上衰减其强度是没有意义的,因此对定向光禁用衰减。但是,您可能希望减弱来自位置光的光。OpenGL通过将光源的贡献乘以衰减因子来衰减光源:

d = distance between the light's position and the vertex

kc = GL_CONSTANT_ATTENUATION

kl = GL_LINEAR_ATTENUATION

kq = GL_QUADRATIC_ATTENUATION

By default, kc = 1.0, kl = kq = 0.0.

可以为这些参数指定不同的值:

    glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 2.0);
    glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 1.0);
    glLightf(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, 0.5);

聚光灯(默认gl_spot_cutoff=180)

glLightf(GL_LIGHT0, GL_SPOT_CUTOFF, 45.0);

GLfloat spot_direction[] = { -1.0, -1.0, 0.0 };

glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, spot_direction);

可以设置多个光源

GLfloat light1_ambient[] = { 0.2, 0.2, 0.2, 1.0 };
GLfloat light1_diffuse[] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat light1_specular[] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat light1_position[] = { -2.0, 2.0, 1.0, 1.0 };
GLfloat spot_direction[] = { -1.0, -1.0, 0.0 };
glLightfv(GL_LIGHT1, GL_AMBIENT, light1_ambient);
glLightfv(GL_LIGHT1, GL_DIFFUSE, light1_diffuse);
glLightfv(GL_LIGHT1, GL_SPECULAR, light1_specular);
glLightfv(GL_LIGHT1, GL_POSITION, light1_position);
glLightf(GL_LIGHT1, GL_CONSTANT_ATTENUATION, 1.5);
glLightf(GL_LIGHT1, GL_LINEAR_ATTENUATION, 0.5);
glLightf(GL_LIGHT1, GL_QUADRATIC_ATTENUATION, 0.2);
glLightf(GL_LIGHT1, GL_SPOT_CUTOFF, 45.0);
glLightfv(GL_LIGHT1, GL_SPOT_DIRECTION, spot_direction);
glLightf(GL_LIGHT1, GL_SPOT_EXPONENT, 2.0);
glEnable(GL_LIGHT1);

光源位置(Position)

  • 定向光——光源无限远(W=0)
GLfloat light_position[] = { 1.0, 1.0, 1.0, 0.0 }; 
glLightfv(GL_LIGHT0, GL_POSITION, light_position);
位置的第四个分量是0.0,表示光是定向光。
默认情况下,GL_POSITION是(0,0,1,0),它定义了方向光。(x,y,z)是它的方向。
  • 位置光——有限距离光源(W不是0)

GLfloat light_position[] = { 5.0, 10.0, 2.0, 1.0 }; 
 glLightfv(GL_LIGHT0, GL_POSITION, light_position);

位置由模型视图矩阵转换并存储在眼睛坐标系中(即相对于眼睛)。

请注意,默认情况下(即不调用gluLookat()),相机(眼睛)位于原点,指向负Z轴。

默认情况下,位置光源向所有方向辐射。

移动光源

  • 固定光源

glViewport (0, 0, (GLsizei) w, (GLsizei) h);

glMatrixMode (GL_PROJECTION);

glLoadIdentity();

if (w <= h)

  glOrtho (-1.5, 1.5, -1.5*h/w, 1.5*h/w, -10.0, 10.0);

else

  glOrtho (-1.5*w/h, 1.5*w/h, -1.5, 1.5, -10.0, 10.0);

glMatrixMode (GL_MODELVIEW);

glLoadIdentity();

/* later in init() */

GLfloat light_position[] = { 1.0, 1.0, 1.0, 1.0 };

glLightfv(GL_LIGHT0, GL_POSITION, position);

  • 光源的独立移动

旋转或平移灯光位置:灯光相对于静止物体移动。

static GLdouble spin;

void display(void)

{

GLfloat light_position[] = { 0.0, 0.0, 1.5, 1.0 };

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glPushMatrix();

gluLookAt (0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);

glPushMatrix();

glRotated(spin, 1.0, 0.0, 0.0);

glLightfv(GL_LIGHT0, GL_POSITION, light_position);

glPopMatrix();

glutSolidTorus (0.275, 0.85, 8, 15);

glPopMatrix();

glFlush();

}

通过模型变换(Model)来移动光源例子:

#include
<GL/glut.h> 

#pragma
comment(linker, "/subsystem:windows /ENTRY:mainCRTStartup")

static
int
spin = 0;

void
init(void)

{

  glClearColor (0.0, 0.0, 0.0, 0.0);

  glShadeModel (GL_SMOOTH);

  glEnable(GL_LIGHTING);

  glEnable(GL_LIGHT0);

  glEnable(GL_DEPTH_TEST);

}

/* Here is where the light position is reset after the modeling

* transformation (glRotated) is called. This places the

* light at a new position in world coordinates. The cube

* represents the position of the light.

*/

void
display(void)

{

GLfloat
position[] = { 0.0, 0.0, 1.5, 1.0 };

glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glPushMatrix ();

glTranslatef (0.0, 0.0, -5.0);

glPushMatrix ();

glRotated ((GLdouble) spin, 1.0, 0.0, 0.0);

glLightfv (GL_LIGHT0, GL_POSITION, position);

glTranslated (0.0, 0.0, 1.5);

glDisable (GL_LIGHTING);

glColor3f (0.0, 1.0, 1.0);

glutWireCube (0.1);                    // 模拟光源

glEnable (GL_LIGHTING);

glPopMatrix ();

glutSolidTorus (0.275, 0.85, 8, 15);

glPopMatrix ();

glFlush ();

}

void
reshape (int
w, int
h)

{

glViewport (0, 0, (GLsizei) w, (GLsizei) h);

glMatrixMode (GL_PROJECTION);

glLoadIdentity();

gluPerspective(40.0, (GLfloat) w/(GLfloat) h, 1.0, 20.0);

glMatrixMode(GL_MODELVIEW);

glLoadIdentity();

}

void
mouse(int
button, int
state, int
x, int
y)

{

switch (button) {

case
GLUT_LEFT_BUTTON:

if (state == GLUT_DOWN) {

spin = (spin + 30) % 360;

glutPostRedisplay();

}

break;

default:

break;

}

}

int
main(int
argc, char** argv)

{

glutInit(&argc, argv);

glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH);

glutInitWindowSize (500, 500);

glutInitWindowPosition (100, 100);

glutCreateWindow (argv[0]);

init ();

glutDisplayFunc(display);

glutReshapeFunc(reshape);

glutMouseFunc(mouse);

glutMainLoop();

return 0;

}


  光源随视点移动

  要创建随视点移动的灯光,需要在查看转换之前设置灯光位置。

  然后观察变换以同样的方式影响光和视点。

  记住灯光位置存储在眼睛坐标中。

光源随视点移动

GLfloat light_position[] = { 0.0, 0.0, 0.0, 1.0 };

glViewport(0, 0, (GLint) w, (GLint) h);

glMatrixMode(GL_PROJECTION);

glLoadIdentity();

gluPerspective(40.0, (GLfloat) w/(GLfloat) h, 1.0, 100.0);

glMatrixMode(GL_MODELVIEW);

glLoadIdentity();

glLightfv(GL_LIGHT0, GL_POSITION, light_position);

如果现在移动视点,灯光将随之移动,相对于眼睛保持(0,0,0)距离。

//viewpoint参数,可改变

static GLdouble ex, ey, ez, upx, upy, upz;

void display(void)

{

  glClear(GL_COLOR_BUFFER_MASK | GL_DEPTH_BUFFER_MASK);

  glPushMatrix();

  gluLookAt (ex, ey, ez, 0.0, 0.0, 0.0, upx, upy, upz);

  glutSolidTorus (0.275, 0.85, 8, 15);

  glPopMatrix();

  glFlush();

}

OpenGL中的光照技术(翻译)的更多相关文章

  1. OpenGL中实现双缓冲技术

    在OpenGL中实现双缓冲技术的一种简单方法: 1.在调用glutInitDisplayMode函数时, 开启GLUT_DOUBLE,即glutInitDisplayMode(GLUT_RGB | G ...

  2. Opengl场景中加光照包含几个步骤

    http://zuoye.baidu.com/question/44e2a82d7ad5c0e1d33ddb9a40e0bf86.html  Opengl场景中加光照包含几个步骤,各个步骤实现用的函数 ...

  3. 【Unity技巧】Unity中的优化技术

    http://blog.csdn.net/candycat1992/article/details/42127811 写在前面 这一篇是在Digital Tutors的一个系列教程的基础上总结扩展而得 ...

  4. Unity中的优化技术

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明.本文链接:https://blog.csdn.net/candycat1992/article/ ...

  5. Bullet物理引擎在OpenGL中的应用

    Bullet物理引擎在OpenGL中的应用 在开发OpenGL的应用之时, 难免要遇到使用物理来模拟OpenGL中的场景内容. 由于OpenGL仅仅是一个关于图形的开发接口, 因此需要通过第三方库来实 ...

  6. GPRS GPRS(General Packet Radio Service)是通用分组无线服务技术的简称,它是GSM移动电话用户可用的一种移动数据业务,属于第二代移动通信中的数据传输技术

    GPRS 锁定 本词条由“科普中国”百科科学词条编写与应用工作项目 审核 . GPRS(General Packet Radio Service)是通用分组无线服务技术的简称,它是GSM移动电话用户可 ...

  7. Android中直播视频技术探究之---基础知识大纲介绍

    一.前言 最近各种视频直播app到处都是,各种霸屏,当然我们也是需要体验的,关于视频直播的软件这里就不介绍了,在不是技术的人来看,直播是一种潮流,是一种娱乐方式,但是作为一个高技术的,我们除了看看,更 ...

  8. OpenGL中glPushMatrix和glPopMatrix的原理

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

  9. OPenGL中的缓冲区对象

    引自:http://blog.csdn.net/mzyang272/article/details/7655464 在许多OpenGL操作中,我们都向OpenGL发送一大块数据,例如向它传递需要处理的 ...

随机推荐

  1. Mapreduce 进阶

    场景描述 订单需要封装成为一个bean 传入reduce,然后实现排序取出top1,或者分组求和 首先要实现排序就要实现comparable接口 要实现分组top1,那么"相同的bean&q ...

  2. android sqlite应用优化(资料整理)

    1.  优化插入速度 a.不要绑定空列    在我的程序,至少有50%的列是空值.碰到空值列,就不调用ih.bind()方法对它进行绑定,就我的程序而言,当列值为null或者空的字符串是, 有将近30 ...

  3. 【Unity笔记】提示框ToolTips大小自适应,及其闪烁的问题

    需求:制作了一个提示框,当鼠标移入背包格子内,显示提示框,且提示框位置跟随鼠标移动.当鼠标移出背包格子,隐藏提示框. 制作提示框ToolTips 因为提示框的大小要求随着显示的文本内容长度而自动大小适 ...

  4. [root]既然sudo 可以暂时获取root权限,那么为何还需要root这个用户呢

    既然sudo 可以暂时获取root权限,那么为何还需要root这个用户呢 sudo 非root用户可以临时行使root权限,也就是非root用户可以操作该系统下的任何文件,仍然存在安全风险,怎么解释? ...

  5. PostgreSQL Table Partitioning<转>

    原创文章,转载请务必将下面这段话置于文章开头处(保留超链接).本文转发自Jason’s Blog,原文链接 http://www.jasongj.com/2015/12/13/SQL3_partiti ...

  6. Struts2、Spring、Hibernate 高效开发的最佳实践(转载)

    Struts2.Spring.Hibernate 高效开发的最佳实践 Struts2.Spring.Hibernate(SSH)是最常用的 Java EE Web 组件层的开发技术搭配,网络中和许多 ...

  7. HBase的compact分析

    HBase是基于LSM树存储模型的分布式NoSQL数据库.LSM树对比普遍的B+树来说,能够获得较高随机写性能的同时,也能保持可靠的随机读性能(可参考这里).在进行读请求的时候,LSM树要把多个子树( ...

  8. Ubuntu 安装软件方法

    Ubuntu软件安装有几种方式,常用的是deb包的安装方式,deb是debian系列的Linux包管理方式,Ubuntu软件安装属于debian的派生,也默认支持这种软件安装方式,当下载到一个deb格 ...

  9. Android图片二进制与Bitmap、Drawable之间的转换

    Android图片二进制与Bitmap.Drawable之间的转换 Java代码  public byte[] getBitmapByte(Bitmap bitmap){      ByteArray ...

  10. Ogre 编辑器二(用Ogre的地形组件加载天龙八部地形)

    主界面如上文设计完成后,场景刚开始添加了是Ogre例子里的,发现场景里实物太少,于是想到直接把天龙的场景拿下来,天龙网上有源码,参考了下,把天龙的地形用Ogre的地形组件完成了下,如下是效果图: 因为 ...