图形学第七课opengl光照.docx
- 文档编号:13820403
- 上传时间:2023-06-17
- 格式:DOCX
- 页数:34
- 大小:381.41KB
图形学第七课opengl光照.docx
《图形学第七课opengl光照.docx》由会员分享,可在线阅读,更多相关《图形学第七课opengl光照.docx(34页珍藏版)》请在冰点文库上搜索。
图形学第七课opengl光照
第七章OpenGL光照
目录
10.1概念
10.2光照模型
10.3明暗处理
10.4材质
本章是比较重要的一部分,前几章只是基础,在这章里将着重讲述光照模型、明暗处理、光源设置、材质定义以及有关的计算机图形学概念等内容,介绍如何运用OpenGL函数来绘制真实感图形,充分展示三维图形世界的魅力。
如果读者以前从未接触过这方面的概念,要直接应用OpenGL函数库编写三维图形程序,是很困难的。
因此,我们将结合OpenGL的特殊性简洁明了地介绍一些有关真实感图形绘制的概念,帮助读者理解基本的OpenGL光照、材质等函数的应用方式,顺利掌握最基本的真实感图形编程方法,引导读者快速进入OpenGL三维图形世界。
10.1、真实感图形基本概念
真实感图形绘制是计算机图形学的一个重要组成部分,它综合利用数学、物理学、计算机科学和其它科学知识在计算机图形设备上生成象彩色照片那样的具有真实感的图形。
一般说来,用计算机在图形设备上生成真实感图形必须完成以下四个步骤:
一是用建模,即用一定的数学方法建立所需三维场景的几何描述,场景的几何描述直接影响图形的复杂性和图形绘制的计算耗费;二是将三维几何模型经过一定变换转为二维平面透视投影图;三是确定场景中所有可见面,运用隐藏面消隐算法将视域外或被遮挡住的不可见面消去;四是计算场景中可见面的颜色,即根据基于光学物理的光照模型计算可见面投射到观察者眼中的光亮度大小和颜色分量,并将它转换成适合图形设备的颜色值,从而确定投影画面上每一象素的颜色,最终生成图形。
由于真实感图形是通过景物表面的颜色和明暗色调来表现景物的几何形状、空间位置以及表面材料的,而一个物体表面所呈现的颜色是由表面向视线方向辐射的光能决定的。
在计算机图形学中,常采用一个既能表示光能大小又能表示其颜色组成的物理量即光亮度(luminance)或光强(intensityoflight)来描述物体表面朝某方向辐射光能的颜色。
采用这个物理量可以正确描述光在物体表面的反射、透射和吸收现象,因而可以正确计算处物体表面在空间给定方向上的光能颜色。
物体表面向空间给定方向辐射的光强可应用光照模型进行计算。
简单的光照模型通常假定物体表面是光滑的且由理想材料构成,因此只考虑光源照射在物体表面产生的反射光,所生成的图形可以模拟处不透明物体表面的明暗过渡,具有一定的真实感效果。
复杂的光照模型除了考虑上述因素外,还要考虑周围环境的光对物体表面的影响。
如光亮平滑的物体表面会将环境中其它物体映像在表面上,而通过透明物体也可看到其后的环境景象。
这类光照模型称为整体光照模型,它能模拟出镜面映像、透明等较精致的光照效果。
为了更真实的绘制图形,还要考虑物体表面的细节纹理,这通常使用一种称为“纹理映射”(texturemapping)的技术把已有的平面花纹图案映射到物体表面上,并在应用光照模型时将这些花纹的颜色考虑进去,物体表面细节的模拟使绘制的图形更接近自然景物。
以上内容中,真实感图形绘制的四大步骤前两步在前面的章节已经详细介绍过,这里不再重复,第三步OpenGL将自动完成所有消隐过程,第四步下面几节详述。
另外,部分复杂光照模型应用将在后续章节里介绍。
10.2、光照模型
10.2.1简单光照模型
当光照射到一个物体表面上时,会出现三种情形。
首先,光可以通过物体表面向空间反射,产生反射光。
其次,对于透明体,光可以穿透该物体并从另一端射出,产生透射光。
最后,部分光将被物体表面吸收而转换成热。
在上述三部分光中,仅仅是透射光和反射光能够进入人眼产生视觉效果。
这里介绍的简单光照模型只考虑被照明物体表面的反射光影响,假定物体表面光滑不透明且由理想材料构成,环境假设为由白光照明。
一般来说,反射光可以分成三个分量,即环境反射、漫反射和镜面反射。
环境反射分量假定入射光均匀地从周围环境入射至景物表面并等量地向各个方向反射出去,通常物体表面还会受到从周围环境来的反射光(如来自地面、天空、墙壁等的反射光)的照射,这些光常统称为环境光(AmbientLight);漫反射分量表示特定光源在景物表面的反射光中那些向空间各方向均匀反射出去的光,这些光常称为漫射光(DiffuseLight);镜面反射光为朝一定方向的反射光,如一个点光源照射一个金属球时会在球面上形成一块特别亮的区域,呈现所谓“高光(Highlight)”,它是光源在金属球面上产生的镜面反射光(SpecularLight)。
对于较光滑物体,其镜面反射光的高光区域小而亮;相反,粗糙表面的镜面反射光呈发散状态,其高光区域大而不亮。
下面先看一个简单的光照例程。
例10-1简单光照例程(light0.c)
#include
#include
#include
#include
#include
voidmyInit(void)
{
GLfloatlight_position[]={1.0,1.0,1.0,0.0};
glLightfv(GL_LIGHT0,GL_POSITION,light_position);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glDepthFunc(GL_LESS);
glEnable(GL_DEPTH_TEST);
}
voidmyReshape(GLsizeiw,GLsizeih)
{
glViewport(0,0,w,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();
}
voidmyDisplay(void)
{
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
auxSolidSphere(1.0);
glFlush();
}
voidmain(intargc,char**argv)
{
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB);
glutInitWindowSize(800,600);
glutInitWindowPosition(100,100);
glutCreateWindow("impleLighting");
myInit();
//glutKeyboardFunc(myKeyboard);
glutReshapeFunc(myReshape);
glutDisplayFunc(myDisplay);
glutMainLoop();
}
以上程序运行结果是显示一个具有灰色光影的球。
其中函数myinit()中包含了关键的设定光源位置、启动光照等几句,而其它程序语言几乎与以前的没有多大区别,但效果却完全不一样。
下面几个小节将详细介绍有关函数的用法。
10.2.2OpenGL光组成
在OpenGL简单光照模型中的几种光分为:
辐射光(EmittedLight)、环境光(AmbientLight)、漫射光(DiffuseLight)、镜面光(SpecularLight)。
辐射光是最简单的一种光,它直接从物体发出并且不受任何光源影响。
环境光是由光源发出经环境多次散射而无法确定其方向的光,即似乎来自所有方向。
一般说来,房间里的环境光成分要多些,户外的相反要少得多,因为大部分光按相同方向照射,而且在户外很少有其他物体反射的光。
当环境光照到曲面上时,它在各个方向上均等地发散(类似于无影灯光)。
漫射光来自一个方向,它垂直于物体时比倾斜时更明亮。
一旦它照射到物体上,则在各个方向上均匀地发散出去。
于是,无论视点在哪里它都一样亮。
来自特定位置和特定方向的任何光,都可能有散射成分。
镜面光来自特定方向并沿另一方向反射出去,一个平行激光束在高质量的镜面上产生100%的镜面反射。
光亮的金属和塑料具有很高非反射成分,而象粉笔和地毯等几乎没有反射成分。
因此,三某种意义上讲,物体的反射程度等同于其上的光强(或光亮度)。
10.2.3创建光源(LightSource)
光源有许多特性,如颜色、位置、方向等。
选择不同的特性值,则对应的光源作用在物体上的效果也不一样,这在以后的章节中会逐步介绍的。
下面详细讲述定义光源特性的函数glLight*():
voidglLight{if}[v](GLenumlight,GLenumpname,TYPEparam)
创建具有某种特性的光源。
其中第一个参数light指定所创建的光源号,如GL_LIGHT0、GL_LIGHT1、...、GL_LIGHT7。
第二个参数pname指定光源特性,这个参数的辅助信息见表10-1所示。
最后一个参数设置相应的光源特性值。
表10-1函数glLight*()参数pname说明
pname参数名
缺省值
说明
GL_AMBIENT
(0.0,0.0,0.0,1.0)
RGBA模式下环境光
GL_DIFFUSE
(1.0,1.0,1.0,1.0)
RGBA模式下漫反射光
GL_SPECULAR
(1.0,1.0,1.0,1.0)
RGBA模式下镜面光
GL_POSITION
(0.0,0.0,1.0,0.0)
光源位置齐次坐标(x,y,z,w)
GL_SPOT_DIRECTION
(0.0,0.0,-1.0)
点光源聚光方向矢量(x,y,z)
GL_SPOT_EXPONENT
0.0
点光源聚光指数
GL_SPOT_CUTOFF
180.0
点光源聚光截止角
GL_CONSTANT_ATTENUATION
1.0
常数衰减因子
GL_LINER_ATTENUATION
0.0
线性衰减因子
GL_QUADRATIC_ATTENUATION
0.0
平方衰减因子
注意:
以上列出的GL_DIFFUSE和GL_SPECULAR的缺省值只能用于GL_LIGHT0,其他几个光源的GL_DIFFUSE和GL_SPECULAR缺省值为(0.0,0.0,0.0,1.0)。
另外,表中后六个参数的应用放在下一篇中介绍。
在上面例程中,光源的创建为:
GLfloatlight_position[]={1.0,1.0,1.0,0.0};
glLightfv(GL_LIGHT0,GL_POSITION,light_position);
其中light_position是一个指针,指向定义的光源位置齐次坐标数组。
其它几个光源特性都为缺省值。
同样,我们也可用类似的方式定义光源的其他几个特性值,例如:
GLfloatlight_ambient[]={0.0,0.0,0.0,1.0};
GLfloatlight_diffuse[]={1.0,1.0,1.0,1.0};
GLfloatlight_specular[]={1.0,1.0,1.0,1.0};
glLightfv(GL_LIGHT0,GL_AMBIENT,light_ambient);
glLightfv(GL_LIGHT0,GL_DIFFUSE,light_diffuse);
glLightfv(GL_LIGHT0,GL_SPECULAR,light_specular);
10.2.4启动光照
在OpenGL中,必须明确指出光照是否有效或无效。
如果光照无效,则只是简单地将当前颜色映射到当前顶点上去,不进行法向、光源、材质等复杂计算,那么显示的图形就没有真实感,如前几章例程运行结果显示。
要使光照有效,首先得启动光照,即:
glEnable(GL_LIGHTING);
若使光照无效,则调用gDisable(GL_LIGHTING)可关闭当前光照。
然后,必须使所定义的每个光源有效,例light0.c中只用了一个光源,即:
glEnable(GL_LIGHT0);
其它光源类似,只是光源号不同而已。
10.3、明暗处理
在计算机图形学中,光滑的曲面表面常用多边形予以逼近和表示,而每个小多边形轮廓(或内部)就用单一的颜色或许多不同的颜色来勾画(或填充),这种处理方式就称为明暗处理。
在OpenGL中,用单一颜色处理的称为平面明暗处理(FlatShading),用许多不同颜色处理的称为光滑明暗处理(SmoothShading),也称为Gourand明暗处理(GourandShading)。
设置明暗处理模式的函数为:
voidglShadeModel(GLenummode);
函数参数为GL_FLAT或GL_SMOOTH,分别表示平面明暗处理和光滑明暗处理。
应用平面明暗处理模式时,多边形内每个点的法向一致,且颜色也一致;应用光滑明暗处理模式时,多边形所有点的法向是由内插生成的,具有一定的连续性,因此每个点的颜色也相应内插,故呈现不同色。
这种模式下,插值方法采用的是双线性插值法,如图10-2所示。
Gouraud明暗处理通常算法为:
先用多边形顶点的光强线性插值出当前扫描线与多边形边交点处的光强,然后再用交点的光强线插值处扫描线位于多边形内区段上每一象素处的光强值。
图中显示出一条扫描线与多边形相交,交线的端点是A点和B点,P点是扫描线上位于多边形内的任一点,多边形三个顶点的光强分别为I1、I2和I3.取A点的光强Ia为I1和I2的线性插值,B点的光强Ib为I1和I3的线性插值,P点的光强Ip则为Ia和Ib的线性插值。
采用Gouraud明暗处理不但可以使用多边形表示的曲面光强连续,而且计算量很小。
这种算法还可以以增量的形式改进,且能用硬件直接实现算法,从而广泛用于计算机实时图形生成。
请看下面光滑明暗处理的例程:
例10-2明暗处理例程(Shading.c)
#include
#include
#include
#include
#include
voidmyInit(void)
{
glShadeModel(GL_SMOOTH);
}
voidobject(void)
{
glBegin(GL_POLYGON);
glColor3f(1.0,0.0,0.0);
glVertex2f(4.0,4.0);
glColor3f(1.0,1.0,1.0);
glVertex2f(12.0,4.0);
glColor3f(0.0,0.0,1.0);
glVertex2f(12.0,12.0);
glColor3f(0.0,1.0,0.0);
glVertex2f(4.0,12.0);
glEnd();
}
voidmyReshape(GLsizeiw,GLsizeih)
{
glViewport(0,0,w,h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if(w<=h)
gluOrtho2D(0.0,16.0,0.0,16.0*(GLfloat)h/(GLfloat)w);
else
gluOrtho2D(0.0,16.0*(GLfloat)w/(GLfloat)h,0.0,16.0);
glMatrixMode(GL_MODELVIEW);
}
voidmyDisplay(void)
{
glClear(GL_COLOR_BUFFER_BIT);
object();
glFlush();
}
voidmain(intargc,char**argv)
{
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB);
glutInitWindowSize(800,600);
glutInitWindowPosition(100,100);
glutCreateWindow("SmoothShading");
myInit();
//glutKeyboardFunc(myKeyboard);
glutReshapeFunc(myReshape);
glutDisplayFunc(myDisplay);
glutMainLoop();
}
以上程序运行结果是在屏幕上显示一个色彩连续变化的三角形。
这个程序是用的RGBA显示模式,若改用颜色表模式,则颜色内插实际上是颜色表的内插,因此呈现的颜色可能不连续。
网友不妨自己试试。
另外,若在light0.c程序中加上一句定义GL_FLAT明暗处理模式,则又会出现怎样的情形呢?
读者可以仔细比较一下。
10.4、材质
10.4.1材质颜色
OpenGL用材料对光的红、绿、蓝三原色的反射率来近似定义材料的颜色。
象光源一样,材料颜色也分成环境、漫反射和镜面反射成分,它们决定了材料对环境光、漫反射光和镜面反射光的反射程度。
在进行光照计算时,材料对环境光的反射率与每个进入光源的环境光结合,对漫反射光的反射率与每个进入光源的漫反射光结合,对镜面光的反射率与每个进入光源的镜面反射光结合。
对环境光与漫反射光的反射程度决定了材料的颜色,并且它们很相似。
对镜面反射光的反射率通常是白色或灰色(即对镜面反射光中红、绿、蓝的反射率相同)。
镜面反射高光最亮的地方将变成具有光源镜面光强度的颜色。
例如一个光亮的红色塑料球,球的大部分表现为红色,光亮的高光将是白色的。
10.4.2材质定义
材质的定义与光源的定义类似。
其函数为:
voidglMaterial{if}[v](GLenumface,GLenumpname,TYPEparam);
定义光照计算中用到的当前材质。
face可以是GL_FRONT、GL_BACK、GL_FRONT_AND_BACK,它表明当前材质应该应用到物体的哪一个面上;pname说明一个特定的材质;param是材质的具体数值,若函数为向量形式,则param是一组值的指针,反之为参数值本身。
非向量形式仅用于设置GL_SHINESS。
pname参数值具体内容见表10-1。
另外,参数GL_AMBIENT_AND_DIFFUSE表示可以用相同的RGB值设置环境光颜色和漫反射光颜色。
表10-2函数glMaterial*()参数pname的缺省值
参数名
缺省值
说明
GL_AMBIENT
(0.2,0.2,0.2,1.0)
材料的环境光颜色
GL_DIFFUSE
(0.8,0.8,0.8,1.0)
材料的漫反射光颜色
GL_AMBIENT_AND_DIFFUSE
材料的环境光和漫反射光颜色
GL_SPECULAR
(0.0,0.0,0.0,1.0)
材料的镜面反射光颜色
GL_SHINESS
0.0
镜面指数(光亮度)
GL_EMISSION
(0.0,0.0,0.0,1.0)
材料的辐射光颜色
GL_COLOR_INDEXES
(0,1,1)
材料的环境光、漫反射光和镜面光颜色
例10-3材质定义例程(light1.c)
#include
#include
#include
#include
#include
voidmyInit(void)
{
/*设置材质的各种光的颜色成分反射比率*/
GLfloatmat_ambient[]={0.8,0.8,0.8,1.0};
GLfloatmat_diffuse[]={0.8,0.0,0.8,1.0};/*紫色*/
GLfloatmat_specular[]={1.0,0.0,1.0,1.0};/*亮紫色*/
GLfloatmat_shininess[]={50.0};
GLfloatlight_position[]={1.0,1.0,1.0,0.0};
glMaterialfv(GL_FRONT,GL_AMBIENT,mat_ambient);
glMaterialfv(GL_FRONT,GL_DIFFUSE,mat_diffuse);
glMaterialfv(GL_FRONT,GL_SPECULAR,mat_specular);
glMaterialfv(GL_FRONT,GL_SHININESS,mat_shininess);
glLightfv(GL_LIGHT0,GL_POSITION,light_position);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glDepthFunc(GL_LESS);
glEnable(GL_DEPTH_TEST);
}
voidmyReshape(GLsizeiw,GLsizeih)
{
glViewport(0,0,w,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();
}
voidmyDisplay(void)
{
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
auxSolidSphere(1.0);
glFlush()
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 图形学 第七 opengl 光照