openGL 光照处理

要绘制逼真的三维物体,必须做光照处理。没有光照的三维物体模型与二维物体没有任何差别,只有具有光照的物体才是真正的三维物体。OpenGL可以控制光照与物体的关系,产生多种不同的视觉效果。下面分几部分叙述OpenGL的光照。

1. OpenGL光照基本概念

在屏幕上最终显示的象素颜色,受到glColor命令指定的颜色影响,同时也要反映出在场景中使用光照的特性,以及物体反射和吸收光的属性。OpenGL的光是由红、绿、蓝组成的,光源的颜色由其所发出的红绿蓝颜色的数量决定,材料的属性是由在不同方向反射、入射的红绿蓝颜色的百分数表示的。OpenGL的光照方程只是一个近似的,但是计算量较小,也比较精确。OpenGL的光可来自多个光源,每光源可以单独控制开关,有的光来自某个特定的方向、位置,也有的光源分散在整个场景,如墙壁的泛光,经过来自光源的光线多次反射,无法确定其光线的方向。要绘制真实的三维物体,仅有光源是不够的,只有物体表面吸收、反射光线时,光源才起作用,而材料本身可能发光,也可能漫反射光线,或在特定方向反射光线,光照只对上述属性的材料起作用。

1). 光线由四个部分构成:发射、泛光、漫反射和镜面反射,这四个成分单独计算,然后再累加起来。

发射光(emission):来自物体,不受光源的影响。

泛光(ambient):来自环境的泛光光源,在各方向均匀散布。

漫反射光(diffuse):来自一个方向,直接照射到表面的要比仅仅扫过表面亮,一旦照射到表面上,无论在何处观察,亮度相同。

镜面反射光(specular):来自一个特定方向,以一个特定方向离开,可以把这个成分看成是材料的光洁度。镜面反射与反射物体的材料属性关系很大,光泽金属能产生很高的镜面反射,而地毯几乎没有镜面反射,在OpenGL中,这个属性是用光泽度(shininess)来表示的。

2). 材料颜色取决于反射的红绿蓝光的百分数。与光源的特性相似,材料也有泛光、扩散、反射颜色。材料的泛光与每个入射光源的泛光组分相对应,漫反射与光源的漫反射相对应,镜面反射与光源镜面反射相对应。泛光和漫反射定义材料的颜色,两者通常是相似的,镜面反射通常是白或灰。

2. 光源的定义

光源有许多特性,如颜色、位置、方向等。不同特性的光源,作用在物体上的效果是不一样的。定义一个光源的主要工作就是定义它的各种特性。下面是定义光源特性的函数glLight()的原型:

void glLight{if}[v](Glenum light,Glenum pname,TYPE param);

该函数设置光源参数

light 建立light指定的光源。light用形式为GL_LIGHTi的符号常数表示,

pname 设置光源的特性。可定义的参数在下表中给出。

param 设置pname特性的值。其各种缺省值和含义也在下表中列出。

表5-1-2

参数名

缺省值

解释

GL_AMBIENT

(0,0,0,1)

光源泛光强度的RGBA值

GL_DIFFUSE

(1,1,1,1)

光源漫反射强度的RGBA值

GL_SPECULAR

(1,1,1,1)

光源镜面反射强度的RGBA值

GL_POSITION

(0,0,1,0)

光源的位置(x,y,z,w)

GL_SPOT_DIRCTION

(0,0,-1)

聚光灯的方向(x,y,z)

GL_SPOT_EXPONENT

0

聚光灯指数

GL_SPOT_CUTOFF

180

聚光灯的截止角度

GL_CONSTANT_ATTENUATION

1

衰减因子常量

GL_LINEAR_ATTENUATION

0

线形衰减因子

GL_QUADRIC_ATTENUATION

0

二次衰减因子

下面语句是一个定义编号为GL_LIGHT0的光源的例子:

Glfloat light_ambient[] = {0.0,0.0,0.0,1.0};

Glfloat light_diffuse[] = {1.0,1.0,1.0,1.0};

Glfloat light_specular[] = {1.0,1.0,1.0,1.0};

Glfloat light_position[] = {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);

glLightfv(GL_LIGHT0,GL_POSITION,light_position);

光源定义完毕后,须调用glEnable()打开该光源,否则该光源对场景中的物体不起作用。

  • 颜色

使用GL_AMBIENTGL_DIFFUSEGL_SPECULAR作为pname参数的值调用glLight()函数,指定光源中相应组成部分的颜色强度。

GL_AMBIENT用于指定环境泛光的RGBA强度。缺省情况下,GL_AMBIENT的特性值为(0.0,0.0,0.0,1.0),表示没有环境泛光。

GL_DIFFUSE用于指定漫反射的RGBA强度。缺省情况下,对于GL_LIGHT0GL_DIFFUSE的特性值为(1.0,1.0,1.0,1.0),对于其它编号为GL_LIGHT1...GL_LIGHT7的光源,该特性值为(0.0,0.0,0.0,0.0)

GL_SPECULAR用于指定镜面反射光的RGBA强度。缺省情况下,对于GL_LIGHT0,该特性的值为(1.0,1.0,1.0,1.0),对于其它光源,该特性值为(0.0,0.0,0.0,0.0)。为达到真实的光照效果,可以将GL_SPECULAR的特性值设置为与GL_DIFFUSE特性相同的值。

  • 位置

使用GL_POSITION作为参数pname的值调用glLight(),定义光源位置坐标。根据需要,可以为场景定义一个距场景无限远的光源,或者定义一个离场景较近的光源,前者称为方向光源,后者称为位置光源。对于一个无限远的方向光源,光线在到达物体时可以看成是平行的,太阳就是一个典型的方向光源。下面的语句定义的光源就是一个方向光源。

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

GlLightfv(GL_LIGHT0,GL_POSITION,light_position);

上面的例子中,由于光源位置的齐次坐标中的w分量值为0,所以该光源位于无穷远处,由(1.0,1.0,1.0)到坐标原点的射线的方向为该光源的方向。缺省情况下,光源的位置为(0.0,0.0,1.0,0.0),它定义一个指向z轴负方向的方向光源。

如果w为非0值,则光源是位置光源,(x,y,z)是该光源所在位置的坐标。

  • 衰减

光线的强度随光源距离的增加而减少。对于方向光源,随距离的增加而衰减其光线强度是没有意义的,因此对方向光源的光线不进行衰减处理。对于位置光源,OpenGL使用下面的衰减因子来衰减光线的强度。


3. 光照模式

除了定义光源外,还需为场景定义光照模式。OpenGL的光照模式由三个部分组成:全局环境光的强度,观察点的性质,对物体的前、背面的光照处理方式。

  • 全局环境光

场景中的每一个光源都可以向场景发射环境光。除此以外,还可以为场景指定无源的全局环境光。可以使用下面的语句指定这种全局环境光的强度。

Glfloat lmodel_ambient [] = {0.2,0.2,0.2,1.0};

glLightModelv(GL_LIGHT_MODEL_AMBIENT,lmodel_ambient);

缺省情况下,全局环境光的强度就是{0.2,0.2,0.2,1.0}。它的作用是产生少量的白色环境光,因此即使不为场景定义光源,仍然能看见场景中的物体。

  • 观察点性质

观察点的位置影响镜面反射产生的亮斑的计算。顶点上亮斑的亮度依赖于该处的法线、顶点到光源的方向和顶点到观察点的方向。

对于一个无穷远的观察点,它和任意顶点之间的方向保持恒定。使用一个非无穷远的观察点能产生更加逼真的效果,但由于要对每个顶点计算方向,因此会降低系统的性能。缺省时观察点为无穷远。定义观察点性质的函数是:

void glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER,Glboolean param);

当参数paramGL_TRUE时,观察点为本地观察点;取GL_FALSE时,观察点为无穷远观察点。

  • 光照面

缺省情况下,光照计算针对所有的多边形,无论是面朝前的多边形还是面朝后的多边形都受光照的影响。如果只为面朝前的多边形设置光照,则面朝后的多边形不能被正确地照亮。例如,对于一个球体,只有向前的面可见,这是因为它们是球体外面的面,而朝后的面看起来是什么样子是无关紧要的,因此不必为它进行光照计算。然而,如果将球体切开,则它的内表面也是可见的,这时就必须使内表面也能被正确地光照。下面的语句设置了双面光照。

glLightModeli(GL_LIGHT_MODEL_TWO_SIDE,GL_TRUE);

这时,OpenGL为面朝后的多边形求表面法线的逆。这就意味着多边形的两个面的表面法线均朝向观察者。作为结果,多边形的两个面均被正确地照亮。

要关闭双面光照,在前面的调用中加入GL_FALSE参数。

4. 材质属性

大多数的材质属性与光源的属性类似。设置材质属性的函数是:

void glMaterial{if}(Glenum face ,Glenum pname ,TYPE param);

void glMaterial{if}v(Glenum face,Glenum pname,TYPE* param);

函数为物体指定当前材质的某一属性。参数face可以是GL_FRONTGL_BACKGL_FRONT_AND_BACK,指定当前材质作用于物体的哪一个方面。被设置的材质的属性由pname标识,对应于该属性的值由param给出。下表列出了pname的取值、缺省值和所代表的意义。

5-1-3

参数名

缺省值

解释

GL_AMBIENT

(0.2,0.2,0.2,1.0)

材料泛射强度的RGBA

GL_DIFFUSE

(0.8,0.8,0.8,1.0)

材料漫反射强度的RGBA

GL_AMBIENT_DIFFUSE

(0.8,0.8,0.8,1.0)

材料的泛光,漫反射强度的RGBA

GL_SPECULAR

(0.0,0.0,0.0,1.0)

材料镜面反射强度的RGBA

GL_SHININESS

0.0

材料镜面反射指数

GL_EMISSION

(0.0,0.0,0.0,1.0)

材料发射光的颜色

GL_COLOR_INDEX

(0,1,0)

材料镜面反射光的色彩指数

 

  • 漫反射和泛射

材质的GL_DIFFUSEGL_AMBIENT属性定义了物体对漫反射光和泛射光的反射率。漫反射的反射率对物体的颜色起着最重要的作用,它受入射的漫反射光颜色以及入射光与法线的夹角的影响,而不受观察点位置的影响。

泛射光的反射率影响物体的整体颜色,因为直射到物体上的漫反射光最亮,而没有被直射的物体的环境反射光最明显。一个物体的泛射光反射率受全局环境光和来自光源的环境光的双重影响。与漫反射一样,泛射光的反射率不受视点位置的影响。

在现实世界中,漫反射和泛射光反射率通常是相同的,因此OpenGL提供一种简便的方法为它们赋相同的值。

Glfloat mat_amb_diff [] = {0.1,0.5,0.8,1.0};

glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE,mat_amb_diff);

上面的语句将当前材质的漫反射和泛射光反射率设置为(0.1,0.5,0.8,1.0)

  • 镜面反射

表面较为光洁的物体由于反射光线而会产生亮斑。例如,在阳光下看一个表面光洁的金属球,球体表面的某些部分会产生强烈的亮斑,当移动金属球时,亮斑也会随之移动,当移动至某些位置时,亮斑变得看不见了。

OpenGL中,这种亮斑称为镜面反射光。设置物体对光的镜面反射特性可以限定亮斑的颜色、大小和亮度。控制亮斑颜色的方法是用GL_SPECULAR作为pname参数的值调用glMaterial*()函数。控制亮斑大小和亮度的方法是以GL_SHININESS作为pname参数的值调用glMaterial*()函数,这时参数param的取值范围为0.0128.0,这个值越大,亮斑的尺寸越小且亮度越高。

镜面反射光的强度还取决于视点的位置。当视点处于直接反射的角度时,亮斑的亮度到达最大值。

  • 发射光

前面讨论的两类材质属性都是被动地反射外界的光线,但某些物体(如灯泡)本身能够发射出光线。对于这类物体需要定义其光线发射特性。用GL_EMISSION作为pname参数的值调用glMaterial*(),函数指定一种RGBA颜色,使得物体看起来像发出某种颜色的光。


  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值