当前位置:
文档之家› 第六讲_OpenGL编程技术-光照
第六讲_OpenGL编程技术-光照
6.6.1、光照模型 ◇ 介绍例程:ep_7_1_光照球
6.6.1、光照模型 ◇ OpenGL光组成 在OpenGL简单光照模型中的几种光分为:辐射光 (Emitted Light)、环境光(Ambient Light)、漫 射光(Diffuse Light)、镜面光(Specular Light)。 辐射光是最简单的一种光,它直接从物体发出并 且不受任何光源影响。 环境光是由光源发出经环境多次散射而无法确定 其方向的光,即似乎来自所有方向。一般说来,房间 里的环境光成分要多些,户外的相反要少得多,因为 大部分光按相同方向照射,而且在户外很少有其他物 体反射的光。当环境光照到曲面上时,它在各个方向 上均等地发散(类似于无影灯光)。
光学反射模型
通常物体表面的反射光可以认为包含三个分量:对环境光的 反射、对特定光源的漫反射和镜面反射。
(a) 漫反射
(b) 理想镜面反射
(c) 一般光滑表面的镜面反射
(d) 理想镜面反射方向 与视线方向的夹角
图6-6 光学反射模型
环境光的反射: 环境光(ambient light)来自周围环境(如墙面)散射的光,在 空间近似均匀分布,入射至物体表面后向空间各个方向均匀 反射出去。物体对环境光的反射分量表示: 其中Ia是入射的环境光亮度,Ka是环境光漫反射系数,它与物 体表面性质有关。如果简单光照模型中仅考虑环境光的反射分 量,则物体表面的亮度是一个恒定值,没有明暗的自然过渡。 散射(diffuse reflection): 散射分量表示特定光源在物体表面的反射光中那些向空间 各个方向均匀反射出去的光。兰伯特(Lambert)余弦定律指出: 当点光源照射到一个散射体时,其表面反射光亮度和光源入射 角(入射光线和表面法矢量的夹角)的余弦成正比,即 I K d I l cos( ) 0 0 Kd 1
5.2 OpenGL中的光照
OpenGL提供的函数可以方便地实现隐藏面消除、光照计 算、纹理映射。
OpenGL中隐藏面的消除采用的是Z缓冲器算法。
glEnable(GL_DEPTH_TEST )和glDisable(GL_DEPTH_TEST )
打开和禁止深度测试。 OpenGL进行光照计算时采用的是简单光照模型,只考虑 光源直接照射下物体表面的反射,不考虑光在物体间的反射 和光的透射。 glEnable(GL_LIGHTING)和glDisable(GL_LIGHTING) 打开和禁止光照计算。
Phong 光照模型
考虑环境光、散射和镜面反射,则物体表面的反射光亮度 为: n
I K a I a K d I l cos( ) K s I l cos ( )
实际上光的亮度与传播距离的平方成反比,Il为光源处的 光亮度,光线抵达物体表面以及从物体表面反射进入观察者 眼睛的过程中存在衰减的问题。漫反射分量和镜面反射分量 应该乘以一个衰减因子,以取得远的物体看起来暗些的效果。 当场景的投影变换采用透视投影时,Warnock提出线性衰减因 子1/d,而Rommey提出衰减因子1/dp可以取得比较真实的效果。 此时Phong光照模型可以进一步描述为: Il I Ka Ia p K d cos( ) K s cos n ( ) d K 其中d是物体上当前考察点到视点的距离,K是一个任意的常 量, 0 p 2 。
ra 1 g Ka a dp K ba
rl m j ( K d cos j K s cos n j ) gl j j 1 bl j
建立简单光照模型后,就可以用于消隐算法中计算像素所对 应的物体上可见点的亮度。
Gouraud明暗处理(插值颜色)
由于每个像素点都需要法向量插值和光照计算,Phong明暗处理计算 量较大,一种简化的处理方法是先利用光照模型计算出多边形顶点处亮 度,然后对亮度进行双线性插值,直接获得像素的颜色,如图6-8,P1、 P2、P3是多边形顶点,其亮度已经计算出。A点的亮度可以由P1、P2点的 亮度线性插值计算出,B点的亮度可以由P1、P3点的亮度线性插值计算出, 于是P点的亮度可以由A、B点的亮度线性插值计算出。 Phong明暗处理计算量远大于Gouraud明暗处理,但效果好。
6.6.1、光照模型
6.6.1、光照模型 ◇创建光源举例 (1)指定光源的位置:
GLfloat light_position[] = { 1.0, 1.0, 1.0, 0.0 }; glLightfv(GL_LIGHT0, GL_POSITION, light_position);
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 }; (2)指定环境光颜色、散射光、镜面反射光
计算物体上可见点光亮度时通常是将光亮度转换成为光栅图形 显示器采用的RGB三基色,这时计算需要在三个基色上分别进 行。如果存在多个光源,则将效果线性相加。此时光照模型可 以描述为 :
I Ka Ia
m
Il j
dp K j 1
( K d cos j K s cos n j )
Phong明暗处理(插值法矢)
如图6-8,P1、P2、P3是多边形顶点,其法 矢量视为共该点的所有多边形法矢量的平 均值。由P1、P2的法矢量可以线性插值计 算出A点的法矢量,由P1、P3的法矢量可 以线性插值计算出B点的法矢量,于是P 点的法矢量可以由A、B点处的法矢量线 性插值计算出,计算出P的法矢量后应用 简单光照模型可以计算出P点的光亮度。 图6-8 对P点进行双线性插值
6.6.1、光照模型 ◇ OpenGL光组成 漫射光来自一个方向,它垂直于物体时比倾 斜时更明亮。一旦它照射到物体上,则在各个方向上 均匀地发散出去。于是,无论视点在哪里它都一样亮。 来自特定位置和特定方向的任何光,都可能有散射成 分。 镜面光来自特定方向并沿另一方向反射出去,一 个平行激光束在高质量的镜面上产生100%的镜面反射。 光亮的金属和塑料具有很高非反射成分,而象粉笔和 地毯等几乎没有反射成分。
6.6.1、光照模型 ◇创建光源(Light Source) 光源有许多特性,如颜色、位置、方向等。选择 不同的特性值,则对应的光源作用在物体上的效果也 不一样,这在以后的章节中会逐步介绍的。下面详细 讲述定义光源特性的函数glLight*(): void glLight{if}[v](GLenum light , GLenum pname, TYPE param) 创建具有某种特性的光源。其中第一个参数light 指定所创建的光源号,如GL_LIGHT0、GL_LIGHT1、...、 GL_LIGHT7。第二个参数pname指定光源特性,这个参 数的辅助信息见表10-1所示。最后一个参数设置相应 的光源特性值。
5.1 光照技术
单纯判别物体表面的可见性,远远不能反映物体表面的真实感。
物体表面所呈现的颜色是由表面向视 线方向辐射进入人眼中光决定的。建 立数学模型模拟物体表面的光照明物 理现象,按照数学模型计算物体表面 向视线方向辐射进入人眼中的光亮度, 即可获得像素所对应的物体上的可见 点的颜色,这样绘制出来的图形具有 图6-5 (a) 经过光照计算的球 较强的真实感,如图6-5(a)。这些数 (b) 不经过光照计算的球 学模型就称为明暗效应模型或者光照 明模型。 当光照射到物体表面时,光可能被吸收、反射和透射,被物体吸收的部分 转化为热,只有反射、透射的光能够进入人眼产生视觉效果,它们决定了 物体所呈现的颜色。如果物体是不透明的,则透射光不存在,物体的颜色 仅由反射光决定。这种情形正是简单光照模型需要考虑的,简单光照模型 只考察光源直接照射下物体表面的反射情况。
2
I Ka I a
0 Ka 1
其中Il是来自点光源的入射光亮度。Kd是漫反射系数,与物体表 面性质有关。 是入射光线和表面法矢量的夹角(如果 >90?)。
兰伯特反射光照模型
只考虑对环境光的反射分量和对特定光源的散射分量,则物 体表面的反射光亮度为 : 0 Ka Kd 1 I Ka I a Kd Il cos( ) 0 2 适用于粗糙、无光泽的物体,如粉笔、黑板。对于擦亮的金属、 光滑的塑料等光亮物体需要计算镜面反射。 镜面反射(specular reflection): 表示特定光源在物体表面的反射光中那些遵循反射定律的 光。对于纯镜面,反射光和入射光对称地分布在表面法向的两 侧。对于一般光滑表面,表面可理解为由许多朝向不同的微小 平面构成,入射光经许多微小平面反射后形成的反射光不再是 单向的,而是分布于理想镜面反射方向的周围。通常采用余弦 函数的幂次来模拟一般光滑表面的镜面反射光的空间分布。 n I K s I l cos ( ) 0 2 Il是入射光亮度。Ks是物体表面镜面反射系数,为理想镜面反 射方向与视线方向的夹角,n为镜面反射光的会聚指数。
明暗处理
光照计算时需要用到多边形上点的法矢量,如果多边形 上点的法矢量总是取多边形的面法矢,则由于不同平面片之 间法矢量不连续,最终绘制出来的图像看起来呈多面体状。
图6-7(a) 多边形表示的物体
(b) Gouraud明暗处理
解决方法:首先多边形的顶点法矢量不再简单的取为其所在多 边形的面法矢,而是取为共该顶点的所有多边形的面法矢的平 均值;其次多边形内部点的法矢量也不再简单地取为多边形的 面法矢,而是利用多边形顶点的法矢量通过双线性插值计算出。
glLightfv(GL_LIGHT0, GL_AMBIENT , light_ambient ); glLightfv(GL_LIGHT0, GL_DIFFUSE , light_diffuse ); glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);