OpenGL中的光照技术(翻译)
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中的光照技术(翻译)的更多相关文章
- OpenGL中实现双缓冲技术
在OpenGL中实现双缓冲技术的一种简单方法: 1.在调用glutInitDisplayMode函数时, 开启GLUT_DOUBLE,即glutInitDisplayMode(GLUT_RGB | G ...
- Opengl场景中加光照包含几个步骤
http://zuoye.baidu.com/question/44e2a82d7ad5c0e1d33ddb9a40e0bf86.html Opengl场景中加光照包含几个步骤,各个步骤实现用的函数 ...
- 【Unity技巧】Unity中的优化技术
http://blog.csdn.net/candycat1992/article/details/42127811 写在前面 这一篇是在Digital Tutors的一个系列教程的基础上总结扩展而得 ...
- Unity中的优化技术
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明.本文链接:https://blog.csdn.net/candycat1992/article/ ...
- Bullet物理引擎在OpenGL中的应用
Bullet物理引擎在OpenGL中的应用 在开发OpenGL的应用之时, 难免要遇到使用物理来模拟OpenGL中的场景内容. 由于OpenGL仅仅是一个关于图形的开发接口, 因此需要通过第三方库来实 ...
- GPRS GPRS(General Packet Radio Service)是通用分组无线服务技术的简称,它是GSM移动电话用户可用的一种移动数据业务,属于第二代移动通信中的数据传输技术
GPRS 锁定 本词条由“科普中国”百科科学词条编写与应用工作项目 审核 . GPRS(General Packet Radio Service)是通用分组无线服务技术的简称,它是GSM移动电话用户可 ...
- Android中直播视频技术探究之---基础知识大纲介绍
一.前言 最近各种视频直播app到处都是,各种霸屏,当然我们也是需要体验的,关于视频直播的软件这里就不介绍了,在不是技术的人来看,直播是一种潮流,是一种娱乐方式,但是作为一个高技术的,我们除了看看,更 ...
- OpenGL中glPushMatrix和glPopMatrix的原理
glPushMatrix.glPopMatrix操作事实上就相当于栈里的入栈和出栈. 很多人不明确的可能是入的是什么,出的又是什么. 比如你当前的坐标系原点在你电脑屏幕的左上方.如今你调用glPush ...
- OPenGL中的缓冲区对象
引自:http://blog.csdn.net/mzyang272/article/details/7655464 在许多OpenGL操作中,我们都向OpenGL发送一大块数据,例如向它传递需要处理的 ...
随机推荐
- sqoop 常用命令整理(二)
26.Validate 它用来比较源数据和目标数据的数量 它有三个接口 Validator. 它有三个接口 Validator. Property: validator Description: Dr ...
- SQL Server 2012 自动增长列,值跳跃问题(自增增加1000)
介绍 从 SQL Server 2012 版本开始, 当SQL Server 实例重启之后,表格的自动增长列的值会发生跳跃,而具体的跳跃值的大小是根据增长列的数据类型而定的.如果数据类型是 整型(in ...
- Git教程首页
Git 教程 Git 是一个分布式的版本控制和源代码管理系统,强调速度. Git 最初由Linus Torvalds设计和开发为Linux内核开发管理代码. Git是GNU通用公共许可证版本2的条款下 ...
- Redis PHP连接操作
安装 在PHP程序中使用Redis,需要确保我们有Redis的PHP驱动程序和PHP安装设置在机器上.可以查看PHP教程教你如何在机器上安装PHP.现在,让我们来看看一下如何设置Redis的PHP驱动 ...
- ASP.NET Core 2.0使用Log4net实现记录日志功能
一.安装Log4net 1.使用Nuget包进行安装 在依赖项上面右键,选择“管理NuGet程序包”,如下图所示: 在浏览界面输入log4net,然后点击安装,如下图所示: 2.使用程序包管理器控制台 ...
- 虚拟机安装以及PCL的配置(1)
安装虚拟机 (1) 下载VMware安装(自己百度一下,会有很多可供下载的) (2) 安装方式: 双击,一路点击next,不用更改安装路径(当然你也可以更改),选择安装“典型”即可 接着就有安 ...
- 记一次MyEclipse闪退的解决方法
http://www.th7.cn/Program/java/201408/262487.shtml ———————————————————————————————————————————————— ...
- 在C++中调用DLL中的函数(3)
1.dll的优点 代码复用是提高软件开发效率的重要途径.一般而言,只要某部分代码具有通用性,就可将它构造成相对独立的功能模块并在之后的项目中重复使用.比较常见的例子是各种应用程序框架,ATL.MFC等 ...
- Item is not readable svn: 条目不可读
问题:svn 查看资源历史记录失败 ,并提示"Item is not readable" 解决: 配置目录权限时如: [/]tangtx=rwyangcx=rwweishq=rw ...
- Mac下安装Pyqt
1.安装sip brew install sip 2.安装pyqt brew install pyqt