Lighting and Rasterization - Shading
学习目标:
1 分类不同类别的光源
2 理解图像形成过程
3 数学建模三种反射类型并了解其属性
4 了解三种渲染方法,并比较它们的优缺点
5 能够使用 OpenGL 对照明和着色进行编程。
照明和着色模型
1.计算在场景的给定点应该看到的光线的强度和颜色。
2.最终目标是 photorealism
- 照明模型 :模拟光源和环境光
- 着色模型: 模型物体和大气如何处理灯光(反射、吸收、折射等)
光源
- ambient source 环境源
模拟背景灯 · - 点光源 point source
对于附近的小光源 - 分布式源 distributed source
对于附近的大型光源。由一系列点光源的集合模拟。 - 照明方向 lighting direction
(如太阳) 对于遥远的光源
*实际看到的光源更高阶更复杂
着色
- 不透明物体 只反射和吸收光;透明物体 只折射和吸收光
半透明物体 可以折射,反射,和吸收光。 - 反射光的量 只取决于 材质。一般来说 shiny的材质可以反射更多光,dull的材质吸收更多的光。(我们暂时只讨论不透明的物体)
反射的类型:
- 环境反射(ambient reflection):是无方向的,光照是来自背景的平均信号
- 漫反射(diffuse reflection):一般发生在粗糙,暗淡,无光泽的表面。在所有方向均等地散射光
- 镜面反射(specular reflection):一般发生在光滑的表面,朝一个方向反射的光更多
- 下面一张图大家可以比较一下漫反射(diffuse)和镜面(specular)反射的区别
环境反射ambient reflection
ia为入射环境光;
ka为环境反射系数,介于0和1之间。
则我们有 :
- 环境反射 可以解释为背景中来自多个光源的漫反射的平均值。
漫反射diffuse reflection
- 考虑点光源或照明方向
- 朗伯表面(lambertian surfaces):来自表面的反射以相同的强度在所有方向上散射,与观察方向无关
- 表面接收的入射光量与表面在照明方向上的投影面积成比例
kd为漫反射系数,介于0和1 之间;
il(incident light)为入射光强度
N为表面的单位法向量
L 为光照的单位方向向量
- 那么NL就是单位投影区域(nl是cos theta 是个标量!!),如果这一点不太清楚可以看下面这张图:
- 对漫反射,我们有如下公式
镜面反射(specular )
- 考虑点光源或照明方向
- 完美的镜面反射=完美的镜子,如下图,完美的镜面反射中,光照只在R方向反射; 不完美的镜面,总会有光在R周边分散地反射出去。
N 表示L和R等分的方向(入射角=理想镜中的反射角)
R 表示单位镜面反射向量
V 表示单位观察方向向量 - 对镜面反射,我们有公式:
W(theta) 表示介于0~1的镜面反射系数
N 表示L和R等分的方向(入射角=理想镜中的反射角)
R 表示单位镜面反射向量
V 表示单位观察方向向量
ns 表示镜面反射指数,趋于∞的时候,就说明镜面几乎是完美的了! - 需要注意的是,此处我们有R =(2N·L)N–L
cos(psi)=R·V 0<=psi<=pi/2 - 不同材料的镜面反射系数
- 从下面这张图我们可以看出,我们期望的是psi角度越小越好
一般n个点光源的模型
我们表示为三种反射的综合情况
颜色模型
- 每个点光源,都是一个红绿蓝组成的向量(IlR, IlG, IlB)
关于颜色,下图中,三角形以外的都是假的颜色(实际颜色与我们看到的不一样),因为显示屏只能显示出三角形范围内的颜色
着色模型 /渲染模型(shading and rendering)
输入:将对象细分为多边形(标准图形对象)
三种常用的多边形着色方法(Shading中的插值技术)
下图从左到右分别使用的是flat shading ,gouraud shading,phong shading。不难看出 真实性提高了,但计算开销也提高了
Flat shading
计算多边形的单个强度。然后以相同的强度值显示多边形的所有点。
- 因为人类的视觉会受到“马赫带效应”的影响-强度的不连续性加剧。这会放大多边形的边缘,所以我们就能看到上图第一个小球每个部分的polygon都有着生硬的边缘
Gouraud Shading
这种着色方法的核心是 在每个多边形上线性插值强度值。
- 每个多边形的强度值与有着公共边的相邻多边形的值匹配
- 这样一来,插值便消除了平面阴影中出现的强度不连续性
- 缺点:slow,消除了镜面高光
操作步骤
- 首先要计算的是每个多边形顶点的平均单位法线,
这里的法线求法是通过包含该顶点的面的法线取平均值求得,如下图: - 将光照模型用于每个顶点以计算顶点颜色
- 在多边形表面的顶点之间线性插值,如下图,该图很重要,插值过程中我们总会用到:
- 位于多边形边缘上的点:在两个端点之间线性插值(由顶点1和2 ,插值法得出点4的颜色):
- 多边形的内部点:在扫描线上线性内插(由边缘上的点4和5,插值法得出P的颜色):
Phong shading
在Phong Shading中,在扫描线对颜色进行填充的时候,不是对颜色插值,而是对法线进行了插值。这样可以保留高光区,真实度最高,但是同时也最慢。
- 计算每个顶点的平均单位法向量
- 在多边形表面上线性插值顶点法线
- 应用照明模型计算每个表面点的像素强度,对每一个像素进行光照计算,这种情况下 计算量相当大。
- 因此为了节省计算量,我们引入:Incremental form 增量线性插值,可以之间看下图,一目了然:
下面是这部分会用到的OpenGL command
光照部分:
glEnable (GL_LIGHTING); // 打开光源
glLight* (lightName, lightProperty, propertyValue);
GLfloat light1PosType [ ] = {2.0, 0.0, 3.0, 1.0}; //一号光源位置属性
GLfloat light2PosType [ ] = {0.0, 1.0, 0.0, 0.0}; //二号光源位置属性
glLightfv (GL_LIGHT1, GL_POSITION, light1PosType); //设置1号光源的位置属性
glEnable (GL_LIGHT1);//打开光1
glLightfv (GL_LIGHT2, GL_POSITION, light2PosType);
//设置2号光源的位置属性
glEnable (GL_LIGHT2);//打开光2
// glLightfv(光源编号,光源特性,参数数据)设置光源。光源编号可取GL_LIGHT0、GL_LIGHT1、……、GL_LIGHT7共8个值。光源特性主要可取GL_AMBIENT(设置光源的环境光属性,默认值(0,0,0,1))、GL_DIFFUSE(设置光源的散射光属性,默认值(1,1,1,1))、GL_SPECULAR(设置光源的镜面反射光属性,默认值(1,1,1,1))、GL_POSITION(设置光源的位置,默认值(0,0,1,0))。参数数据格式要求为数组形式,即数学上的向量形式。
//GL_POSITION,其位置数组(x,y,z,w)定义了光源在空间中的位置。当w≠0时,它表示光源处于空间中(x,y,z)处,这时的光源称为定点光源;当w=0时,根据齐次坐标的性质,它表示光源位于无穷远处,此时光源称为定向光源,其所有光线几乎是相互平等的,如太阳。其光线方向由点(x,y,z)指向(0,0,0)。
光源颜色:
GLfloat blackColor [ ] = {0.0, 0.0, 0.0, 1.0};
GLfloat whiteColor [ ] = {1.0, 1.0, 1.0, 1.0};
glLightfv (GL_LIGHT3, GL_AMBIENT, blackColor); glLightfv (GL_LIGHT3, GL_DIFFUSE, whiteColor); glLightfv (GL_LIGHT3, GL_SPECULAR, whiteColor);
表面特性:
glMaterial* (surfFace, surfProperty, propertyValue);
diffuseCoeff [ ] = {0.2, 0.4, 0.9, 1.0};
// kdR = 0.2, kdG = 0.4, kdB = 0.9
specularCoeff [ ] = {1.0, 1.0, 1.0, 1.0};
// WR(?) = 1.0, ...
glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE,diffuseCoeff );
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specularCoeff);
glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 25.0 ); // ns = 25
//glMaterialfv(face,pname,*pname )面可以是GL_FRONT, GL_BACK,等;pname是材质,可以是GL_AMBIENT_AND_DIFFUSE,GL_SPECULAR,等,最后一个参数是系数值
表面渲染:
glShadeModel(surfRenderingMethod);
//参数可以选GL_FLAT,或者GL_SMOOTH
glNormal3* (Nx, Ny, Nz);
//计算法向量
用Gouraud 对三角形着色例程:
glEnable (GL_NORMALIZE); // convert all normal vectors to unit vector
glLightModeli (GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
// set correct V for specular calculations
glBegin (GL_TRIANGLES);
glNormal3fv (normalVector1); // normal vector at vertex1 calculated
glVertex3fv (vertex1);
glNormal3fv (normalVector2);
glVertex3fv (vertex2);
glNormal3fv (normalVector3);
glVertex3fv (vertex3);
glEnd ( );
版权声明:本文为qq_41901755原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。