光照模型 计算机科学与技术系
概述 使用透视投影绘制的三维物体已经具有近大远小的立体效果,经过背面剔除和z-buffer消隐后,初步生成了具有较强立体感的图形,但要模拟真实物体,还必须为其表面添加材质、映射纹理、施加光照、绘制阴影后才能产生真实感图形(photorealism computer graphics)。
Teapot光照效果 光照是增强图形真实感的重要技术。 线框图 无光照实体图 环境光和漫反射光 Gouraud插值后环境光和漫反射光 环境光、漫反射光和镜面反射光 Gouraud插值后环境光、漫反射光和镜面反射光
影响对物体视觉感受的主要因素 光源 物体表面特性 视线方向 视觉感受除物理因素外,还涉及心理因素的影响,因此在图形显示中必须综合考虑影响显示效果的多种因素。 图形学主要讨论如何从物理上考虑图形的真实感问题。
简单光照模型 光照射到物体表面,主要发生: 反射 透射(透明物体) 部分被吸收成热能 反射、透射光决定物体表面呈现的颜色
局部和全局光照模型 计算机图形学的光照模型分为局部光照模型(local illumination)和全局光照模型(Global illumination) 局部光照模型仅考虑光源直接照射到物体表面所产生的效果,能表现出光源直接投射在漫反射物体表面上所形成的连续明暗色调、镜面高光以及由于物体相互遮挡而形成的阴影。 全局光照模型除了考虑上述因素外,还考虑周围环境对物体表面的影响,能模拟镜面的映象、光的折射以及相邻表面之间的色彩辉映等精确的光照效果。
材质的属性 物体的材质是指物体表面对光的吸收、反射和透射的性能。 由于研究的是简单局部光照模型,所以只考虑材质的反射属性。 同光源一样,材质也由环境色、漫反射色和镜面反射色等分量组成,分别说明了物体对环境光、漫反射光和镜面反射光的反射率。 材质决定物体的颜色,在进行光照计算时,材质对环境光的反射率与光源的环境光分量相结合,对漫反射光的反射率与光源的漫反射光分量相结合,对镜面光的反射率与光源的镜面反射光分量相结合。
材质漫反射光反射率对物体颜色影响效果图
环境光(Ambient Light) 环境光是光源发出的光线不直接照射到物体上,而是经 多次反射和折射后到达物体。这样的光线已不具有方向 性,因此环境光照明只能为每个表面产生一个平淡的明 暗效果。 环境光光强: I = Ka · la la:光的强度; Ka:反射光的系数,与物体表面特性有关,0.0≤ka≤1.0 。 缺点:物体表面的光强度是一个恒定值,不能产生明暗的自然过渡
漫反射光(Diffuse Light) 理想漫反射:光线被物体表面反射后向各个方向以同等光强 度发散,而与视方向无关,称为理想 漫反射。该物体亦称 Lambert 反射体 当采用点光源照明时,物体表面漫反射强度 I 遵从 Lambert 余弦定律: 0.0≤θ≤π/2,0.0≤kd≤1.0 ldhgf Id 为入射光强; Kd 为漫反射系数 ,θ为入射光与物体表面法线的夹角
漫反射光 漫反射是从一点照射,向多个方向反射,均匀地散布在各 个方向,因此它与观察者的视点位置无关,但与光源的位 置和物体表面的法向量有关。 漫反射是从一点照射,向多个方向反射,均匀地散布在各 个方向,因此它与观察者的视点位置无关,但与光源的位 置和物体表面的法向量有关。 对于单位向量, 则漫反射的光照模型为: 考虑到点光源位于P点的背面时,L·N计算结果为负值,应取为零,有
镜面反射光(Specular Light) 理想表面:入射光仅在镜面反射方向有反射现象,反射角等于入射角。 观察者只能在反射方向上才能看到发射光。 非理想表面:反射光有一定的光强分布,一般取决于材质和表面光洁程度。 镜面反射光是向一定方向反射的光。在光线的照射下,光滑物体会形成一片非常亮的区域,称为高光区。
镜面反射光(Specular Light) 由于镜面反射涉及复杂的物理性质,在基本光照模型中常采用Phong Bui-Tuong 提出的实验模型处理问题。 角度关系:满足菲涅尔 (Fresnel) 反射定律 ,即: 反射角等 于入射角。 其表达式为: 0.0≤ks≤1.0,0.0≤α≤π/2
镜面反射光参数讨论 反射光强度与cosns曲线表示反射光的汇聚程度成正比 ns 为 1, 8, 64,128,256 时的cosns α 曲线 cosα cos8 α cos64 α cos128 α ldhgf cos256 α α° ns 由物体材料表面性质决定,光滑金属表面的 ns 值可大于100,而粗糙表面 ns 可小于1 。理想镜面反射的 ns 为无穷大。
镜面参数 ns 的影响效果 ns= 5 ns= 10 ns=50 ns 常规取值 5-50
镜面反射光(Specular Light) 镜面反射光颜色和入射光颜色相同,也即镜面反射光只反映光源的颜色。在白光的照射下,物体的高光区域显示白色;在红光的照射下,物体的高光区域显示红色。镜面光反射率ks是一个与物体颜色无关的参数。 镜面反射光光强不仅取决于物体表面的法线方向,而且依赖于光源和视点的相对位置。只有当视点位于比较合适的位置时,才可以观察到物体表面某些区域呈现出高光,当视点位置改变时,高光区域也会随之消失。
镜面反射光(Specular Light) Blinn于1977年对Phong的镜面反射模型做了改进,使用平分矢量H加速计算。 考虑β>90°时,H·N计算结果为负值,应取为零,有
简单光照模型 这样考虑环境光、漫反射光和镜面反射光且只有一个点光源的简单光照模型为 必须考虑点光源传播中的衰减问题,否则将丧失深度感。 从物理上讲点光源的光在空间传播时,将以 1/d2 的比率衰减,但在图形学中若用 1/d2 衰减将会造成过大或过小的光强变化。 ldhgf 考虑光强衰减的单光源简单光照模型为
多光源照明 若在场景中放置多个点光源,可以在物体表面上迭加各个光源的光照效果,一般采用线性迭加。其中要注意的是迭加后光强可能溢出显示范围,因此可设置各个光源的上限或采用归一化方法处理。 如:两个点光源照明的情景 ldhgf 光照模型为:
颜色分量的计算 大多数显示场景的图形均为彩色图形,为此,须将上述光强度方程写成光源和物体表面颜色属性的函数。由于有多种颜色描述方式,将对应不同的处理。 在常用的 RGB 描述中,场景中的颜色均用红、绿、蓝三个颜色分量的相对强度来表示,因此可将上述光强度方程扩写为分别描述 R、G 、 B分量的方程: ldhgf
物体的材质 材质是指物体表面对光的反射特性,使用光的反射率表示。 假设,有一个光源,它的RGB值是(LR, LG, LB) 物体的材质的RGB值是(MR, MG, MB) 则光源照射到物体上看到的反射光颜色为: ( MR LR, MG LG, MB LB)。 如两个光源的RGB值是(L1R, L1G, L1B)和(L2R, L2G, L2B),则看到反射光颜色为: (L1R + L2R , L1G + L2G, L1B + L2B )
光源种类 平行光 点光源 在空间具有一个位置, 它发出的光以球面形式向四周均匀的传播,此外,光强随着与光源的距离的增大而逐渐减小。如电灯泡。 平行光是最简单的,具有单一的照射方向,且光照强度不随空间位置而变化,如现实中的太阳光。 点光源 在空间具有一个位置, 它发出的光以球面形式向四周均匀的传播,此外,光强随着与光源的距离的增大而逐渐减小。如电灯泡。 聚光灯 在空间具有一个位置, 还有一个照射方向,以该方向为中心对称地向周围发散一定的角度,这样光线被限制在一个圆锥内。
在摄像机坐标系下齐次坐标表示,它位于摄像机后方。 OpenGL光照 定义每个物体的每个顶点的法线向量 创建和选择一个或多个光源,并设置它们的位置 glLightfv(GL_LIGHT0, GL_POSITION, position); //位置 glLightfv(GL_LIGHT0, GL_AMBIENT, ambient); //环境光 glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse); //漫反射 glLightfv(GL_LIGHT0, GL_SPECULAR, specular); //镜面反射 glLightfv(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 2.0); 光源的强度: GLfloat ambient[] = { 0.2, 0.2, 0.2, 1.0 }; GLfloat diffuse[] = { 1.0, 1.0, 1.0, 1.0 }; Glfloat specular[] = { 1.0, 1.0, 1.0, 1.0 }; 光源的位置: GLfloat position[] = { 0.0, 3.0, 2.0, 0.0 }; 不透明 表示光源无穷远的方向光
OpenGL光照 定义物体的材料属性-材料对光的反射率与各种光结合 glMaterialfv(GL_FRONT, GL_AMBIENT, ambient); glMaterialfv(GL_FRONT, GL_DIFFUSE, diffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, specular); glMaterialfv(GL_FRONT, GL_SHININESS, shininess); //镜面指数 glMaterialfv(GL_FRONT, GL_EMISSION, emission); //材料发散颜色 创建和选择一种光照模型,定义了全局环境光的层次和 观察点的有效位置 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient); glLightModelfv(GL_LIGHT_MODEL_LOCAL_VIEWER, local_view);
注:一旦开启光照,由glColor3f()指定的颜色将不再使用。 OpenGL光照 启用光源 glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); void display(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glColor3f(1.0, 0.0, 0.0); glutSolidSphere(1.0, 20, 20); glFlush(); } 注:一旦开启光照,由glColor3f()指定的颜色将不再使用。
void init(void) { GLfloat no_mat[] = {0.0, 0.0, 0.0, 1.0}; GLfloat mat_ambient[] = {0.247, 0.200, 0.075, 1.0}; GLfloat mat_diffuse[] = {0.752, 0.606, 0.226, 1.0}; GLfloat mat_specular[] = {0.628, 0.556, 0.366, 1.0}; GLfloat mat_shininess[] = {50.0 }; GLfloat mat_emission[] = {0.3, 0.2, 0.2, 0.0}; GLfloat light_position[] = { 1.0, 1.0, 1.0, 0.0 }; GLfloat lmodel_ambient[] = { 0.2, 0.8, 1.0, 1.0 }; //blue light glLightfv(GL_LIGHT0, GL_AMBIENT, mat_ambient); glLightfv(GL_LIGHT0, GL_DIFFUSE, mat_diffuse); glLightfv(GL_LIGHT0, GL_SPECULAR, mat_specular); glLightfv(GL_LIGHT0, GL_POSITION, light_position); glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient); 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); glMaterialfv(GL_FRONT, GL_EMISSION, no_mat); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); }
glDisable(GL_LIGHTING) glEnable(GL_LIGHTING)
漫反射 漫反射+镜面反射(0) 漫反射+镜面反射(50) 漫反射+镜面反射+材料反射
两个光源 GLfloat light0_diffuse[]= { 0.0, 0.0, 1.0, 1.0}; GLfloat light0_position[] = { 1.0, 1.0, 1.0, 0.0 }; //direction light GLfloat light1_ambient[] = { 0.2, 0.2, 0.2, 1.0 }; GLfloat light1_diffuse[] = { 1.0, 0.0, 0.0, 1.0 }; GLfloat light1_specular[] = { 1.0, 0.6, 0.6, 1.0 }; GLfloat light1_position[] = { -3.0, -3.0, 3.0, 1.0 }; //point light GLfloat spot_direction[] = { 1.0,1.0,-1.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_SPOT_CUTOFF, 30.0); glLightfv(GL_LIGHT1, GL_SPOT_DIRECTION,spot_direction); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glEnable(GL_LIGHT1);
两个光源 一个蓝色漫反射光 一个蓝色漫反射光和一个红色聚光灯
Doom3的男主角-Diffuse
Doom3的男主角-Specular
Doom3的男主角-Diffuse+Specular+Ambinet
光滑着色 应用光照模型可以完成由多边形组成的标准图形对象的表面绘制。 在绘制时一般须结合扫描算法从光照模型实现多边形面片的逐点绘制。 简单的作法是将每个多边形用单一光强来绘制-平面 复杂的算法则需逐点计算光强-平滑 ldhgf
恒定光强度的明暗处理-平面着色 为每个多边形建立一个光强度属性,该多边形面上所有点均用相同的光强值显示。 若下列假定成立,则恒定光强的明暗处理可以准确地绘制出物体: 物体是一个多面体,不含曲面。 所有照明光源离物体表面足够远。 视点离物体表面足够远。 如果条件不成立,仍可利用小多边形面片来合理地近似物体表面的光照效果。
恒定光强度的明暗处理 马赫带 平面着色 ldhgf 10等分 40等分 glShadeModel(GL_FLAT)
Gouraud 明暗处理 Gouraud 明暗处理通过在面片上将光强度值进行线性插值来计算各点光强,并完成绘制。消除在平面绘制中存在的光强不连续现象。 马赫带 ldhgf
Gouraud明暗处理 Gouraud明暗处理须进行下列计算: 确定每个多边形顶点处的平均单位法向量 对每个顶点,根据光照模型计算该点光强度 在多边形表面上,将顶点光强度进行线性插值,计算各像素点的光强 如图中顶点 V 处的法向量表示为: V N1 N2 N3 N4
Gouraud明暗处理 在具体计算中一般结合扫描线算法进行。首先求出面片各顶点的法向量方向,并利用光照模型计算该点光强。由于法向量方向不同,因此各顶点光强也可能不同。 在顶点光强基础上可以利用双线性插值确定每条扫描线上各个像素的光强。例如,下图中P点的光强可以通过双线性插值计算: 1 2 3 4 5 P 扫描线 Y X ldhgf
Gouraud明暗处理 优点:Gouraud 明暗处理计算量小,方法简单,常用于简单的漫反射照射模型的光照处理 计算中为求相邻扫描线上后续点的光强,可用增量法计算。 如图,若点 I (x, y) 的强度被插值为 I1 I2 y I X I’ 扫描线 y-1 Y 则下一扫描线 y-1 上 I’ 的光强为: ldhgf 同样的计算可以沿扫描线进行,完成面上所有像素点的光强值计算 优点:Gouraud 明暗处理计算量小,方法简单,常用于简单的漫反射照射模型的光照处理
Gouraud明暗处理 讨论: Gouraud 明暗处理的问题: 1. 保证了多边形边界两侧光强的连续性,但未保证其变化的连续性 1. 保证了多边形边界两侧光强的连续性,但未保证其变化的连续性 2. 难于表现曲折复杂的表面,例如下图曲面 ldhgf 3. 由于采用光强的插值,会强烈影响高光的形状,因此从真实效果来看不够理想。
Phong 明暗处理 与Gouraud 明暗处理相比,若不对光强度值进行线性插值来计算各点光强,而通过对法向量插值,得到各点法向量,然后再计算光强度,并完成绘制,则更为精确。 Phong 明暗处理须进行下列计算: 1. 确定每个多边形顶点处的平均单位法向量 2. 在多边形表面上,将顶点法向量进行线性插值,计算各像素点法向量 ldhgf 3. 根据光照模型沿每条扫描线计算面上各点对应的投影像素的光强值
Phong 明暗处理 对面上的各点的法向量计算,与 Gouraud 算法相仿。在得到各像素点的法向量后可利用光照模型计算光强度。 例如:图中扫描线与多边形边交点的法向量为 扫描线 对面上的各点的法向量计算,与 Gouraud 算法相仿。在得到各像素点的法向量后可利用光照模型计算光强度。
着色模式 物体的复杂光滑表面使用一系列多边形逼近的,而且多边形都是单一着色的多边形,这样物体看上去像一个一个面片拼接起来的,显得不自然。 改进显示方法: 1)细化面片 2)光滑着色-使多边形填充的颜色产生层次后连续变化 OpenGL提供两种着色方式:单一着色和光滑着色。 glShadeModel(GL_SMOOTH ); glShadeModel(GL_FLAT);
void triangle(void) { glBegin(GL_TRIANGLES); glColor3f(1.0, 0.0, 0.0); glVertex2f(2.0, 10.0); glColor3f(0.0, 0.0, 1.0); glVertex2f(15.0, 10.0); glColor3f(0.0, 1.0, 0.0); glVertex2f(2.0, 23.0); glEnd(); } void display(void) { glClear(GL_COLOR_BUFFER_BIT); glShadeModel(GL_SMOOTH); triangle(); glShadeModel(GL_FLAT); glPushMatrix(); glTranslatef(14,0,0); glPopMatrix(); glFlush(); }