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. 【Java笔记】配置文件java.util.Properties类的使用

    配置文件的路径:项目名/src/main/resources/mmall.properties mmall.properties的内容是键值对.例如假设写了ftp服务器的一些信息. ftp.serve ...

  2. CycleGAN 各种变变变

    转载自 简单介绍了一下GAN和DCGAN的原理.以及如何使用Tensorflow做一个简单的生成图片的demo. Ian Goodfellow对GAN一系列工作总结的ppt,确实精彩,推荐:独家 | ...

  3. ApplicationContextAware接口的作用

      1/============== 在Web应用中,Spring容器通常采用声明式方式配置产生:开发者只要在web.xml中配置一个Listener,该Listener将会负责初始化Spring容器 ...

  4. 彻底去除Win10“快速访问”

    windows10的“快速访问”功能对于我个人用处不大,作为一个爱折腾的人决定尝试彻底除去“快速访问”这个侧边栏. 注意:此操作需要确保你已经设置了[让点击Win10任务栏“文件资源管理器”图标打开“ ...

  5. 自定义垂直拖动的seekbar进度条

    系统自定义的seekbar为横向拖动的样式,需要纵向的时则需要自己定义,网上很多说了重写系统SeekBar中onDraw()的方法,但是我使用的时候不知道为什么拖动条和点偏离了,不在一条直线上,好气. ...

  6. JS设计模式学习实例之单例模式

    <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <t ...

  7. R语言大小写字母转换

    #R语言大小写字母转换 熊荣川 六盘水师范学院生物信息学实验室 xiongrongchuan@126.com http://blog.sciencenet.cn/u/Bearjazz R语言有很丰富的 ...

  8. 使用VMware将Linux装在物理硬盘上,开机即可进入Linux

    我的笔记本上是双系统Windows和Linux .经常需要在两个系统间切换,很麻烦.于是我想到如果能用VMWare虚拟机加载物理硬盘中的系统,可以在需要时,直接启动另外一个系统.     注意:我的双 ...

  9. How to deal with "Could not find component on update server. Contact VMware Support or your system administrator." in Vmware.

    手动将vmware安装目录下的vmtools镜像文件,windows.iso文件放到虚拟机的光区里. 再进入虚拟机的系统,在系统里打开光盘进行安装

  10. 【转】在android程序中使用配置文件properties

    在android程序中使用配置文件来管理一些程序的配置信息其实非常简单 在这里我们主要就是用到Properties这个类直接给函数给大家 这个都挺好理解的 读写函数分别如下: //读取配置文件 pub ...