计算机图形学04 着色(shading)
计算机图形学04 着色(shading)
Shading(着色)
- 0、前置知识
- 0.1 重心坐标插值(三角形)
- 0.1.1 什么是重心坐标
- 0.1.2 重心坐标插值
- 0.2 双线性插值
- 1、shading的定义
- 2、Blinn-Phong反射模型
- 2.1 漫反射光L d L_dLd 的计算
- 2.2 高光项L s L_sLs 的计算
- 2.3 环境光L a L_aLa 的计算
- 3、着色频率(Shading Frequency)
- 3.1 逐面着色—shade each triangle(flat shading)
- 3.2 逐点着色—shade each vertex(Gouraud shading)
- 3.3 逐像素着色—shade each pixel(Phong shading)
- 4、纹理映射(Texture Mapping)
- 4.1 什么是纹理映射
- 4.2 纹理放大(Texture Magnification)
- 4.2.1 纹理图太小
- 4.2.2 纹理图太大
- 5、纹理的应用
- 5.1 环境贴图(Environment Map)
- 5.1.1 Spherical Environment Map
- 5.1.2 Cube Map
- 5.2 凹凸贴图(Bump Mapping)
- 5.3 位移贴图(Displacement Mapping)
0、前置知识
0.1 重心坐标插值(三角形)
0.1.1 什么是重心坐标
对于三角形ABC,已知其三个顶点坐标,那么对于三角形内部的任意一点,都可以由三角形三个顶点的线性组合表示,且满足以下关系,则( α , β , γ ) (α,β,γ)(α,β,γ)称为该点的中心坐标。
重心坐标的计算方法如下所示
0.1.2 重心坐标插值
有了重心坐标,即可对三角形内任意一点进行插值,假设三角形三个顶点处的值分别为V A V_AVA 、V B V_BVB 、V C V_CVC ,那么三角形内任意一点的值
V = α ∗ V A + β ∗ V B + γ ∗ V C V=αV_A+βV_B+γ*V_CV=α∗VA +β∗VB +γ∗VC
0.2 双线性插值
首先我们定义一个运算,已知v 0 v_0v0 和v 1 v_1v1 的坐标,那么,v 0 v_0v0 和v 1 v_1v1 之间任意一点的坐标可表示为
l e r p ( x , v 0 , v 1 ) = v 0 + x ( v 1 − v 0 ) lerp(x,v_0,v_1)=v_0+x(v_1 - v_0)lerp(x,v0 ,v1 )=v0 +x(v1 −v0 )
所谓双线性插值(Bilinear Interpolation),就是找到待求点周围最近的四个已知点,再对其进行两次水平方向的插值、一次垂直方向的插值(或者两次垂直方向的插值,一次水平方向的插值)。如下所示
1、shading的定义
经过光栅化过后,我们已经将图像对应到了屏幕上的每一个像素,接下来就是为每一个像素赋值的过程,这就是着色(shading)。
2、Blinn-Phong反射模型
一种经验性的着色模型,用来计算着色点处的光照值。该模型假设某着色点处的光由三部分组成,分别是高光、漫反射光、环境光,因此该点处对应的光照值也由这三种光在着色点处的光照值组成。可表示为
L = L a + L d + L s L=L_a + L_d+L_sL=La +Ld +Ls
其中L a L_aLa 表示环境光(Ambient lighting)光照强度,L d L_dLd 表示漫反射(Diffuse reflection)光光照强度,L s L_sLs 表示高光(Specular highlights)光照强度。三种光的形式大致如下所示
2.1 漫反射光L d L_dLd 的计算
首先我们对着色点处进行如下建模(l ll、n nn、v vv均以单位向量表示)
接下来,先看看什么是漫反射,所谓漫反射,就是指当光线照射到物体表面时,会向四面八方以同样的强度进行反射,这就是漫反射。也就是说,无论我们从哪个反向观察物体(无论v vv的方向如何),看到的光照都是一样的(L d L_dLd 的值与v vv无关)。
那么,L d L_dLd 的值该如何计算呢?首先,我们知道光照强度越靠近光源越大,光照强度与着色点距光源的距离有关,此强度可表示为
其次,根据Lambert’s cosine law,着色点处光照强度还与光线入射方向与着色点的法线方向有关,具体关系如下
因此,与光源相距r rr处,l ll与n nn夹角为θ θθ的着色点处的L d L_dLd 表示为
2.2 高光项L s L_sLs 的计算
建模如下,其中h hh为半程向量,为l ll和v vv夹角的角平分线方向,α αα为n nn与h hh的夹角,为了更加接近现实效果,p通常取大于1的数
2.3 环境光L a L_aLa 的计算
三项结合即为着色点处的光照强度L LL
3、着色频率(Shading Frequency)
有了Blinn-Phong反射模型,就能计算出,任意坐标处的光照强度,接下来就是对光栅化后的图像选择一个着色策略运用Blinn-Phong反射模型进行着色,不同的策略着色的频率有所差异,共有三种着色策略,分别是逐面着色、逐点着色和逐像素着色。
3.1 逐面着色—shade each triangle(flat shading)
在光栅化过程中,我们知道图像可被划分为一个个的三角形,所谓逐面着色就是以每一个三角形为单元运用Blinn-Phong反射模型进行着色,也就是说每个三角形内的颜色是一致的。此处要求的量为三角形面的法线,运用叉乘法即可(已知三角形三个顶点坐标)。
3.2 逐点着色—shade each vertex(Gouraud shading)
1、对每一个顶点求其法线进行着色,这样就得到了每个顶点处的色值。
2、对于顶点内的区域,使用插值的方法进行着色。(三角形内部可使用重心坐标插值,矩形内部可使用双线性插值)
顶点处的法线求法:与顶点相交的各个面的法线的平均
3.3 逐像素着色—shade each pixel(Phong shading)
1、求出每一个顶点的法线并其进行着色。
2、求顶点内部像素区域的法线(顶点法线插值得到),对像素进行着色。
注意:与逐点着色相区别,逐点着色是直接插值色值,逐像素着色是插值法线,再根据法线求得色值。
4、纹理映射(Texture Mapping)
4.1 什么是纹理映射
读了上面的内容,可以发现对于Blinn-Phong反射模型,我们已经知道了l ll、n nn、v vv是什么,但是并不知道k_d是什么,这就是接下来要讲的东西,纹理图。
对于一个三维物体,将其表面展开得到一幅二维图像,这个二维图像就是纹理(texture),而纹理就保存了三维物体各处的颜色值(也可为深度值等等),三维物体表面的每一处都在二维表面上得到了映射,如下地球仪所示,k d k_dkd 即为纹理图中对应坐标的值。所以纹理映射也就是求得k d k_dkd 的过程,求坐标(x,y)处k d k_dkd 值的步骤如下:
1、根据映射关系找到(x,y)在纹理图中的坐标(u,v)
2、坐标(u,v)处的值t(u,v)即为k d k_dkd
4.2 纹理放大(Texture Magnification)
4.2.1 纹理图太小
纹理图过小,意味着纹理元素太少,亦即一个纹理元素需要覆盖多个像素,也就会使得图像变得模糊,如下图左边所示,此时就可采用双线性插值对纹理图进行插值,增加纹理元素。
4.2.2 纹理图太大
纹理图过大,意味着纹理元素太多,亦即一个像素可能覆盖多个纹理元素,会产生走样现象,如下所示,近处出现锯齿,远处出现摩尔纹。
既然是走样,那么解决方法自然也可采取超采样(MSAA)解决,但是超采样计算量大,耗时长。因此,需要一种快速的算法,这就是mipmap,mipmap属于范围查询,是一种能够进行快速估计、仅对方形区域有效的范围查询方法。
Mipmap的思想是从原图生成一系列图,如下图所示,level0为原图,其后每一层为前一层长宽分别缩小一半得来(也可称为图像金字塔)。相较于原图,只需额外占用1 / 3 1/31/3的存储空间。
那么,如何使用mipmap呢,首先,对于每个像素,我们找到其再纹理图上对应的矩形区域,该区域边长L如下计算,再根据边长就可知道再哪一层mipmap上去查询该点像素的纹理值。
在上述计算方法中,D的值可能为小数,若直接采取四舍五入的方法取D值,那么最终的结果在某些地方颜色变化比较剧烈,过渡不够平缓,如下所示。
解决过渡不够平缓的问题自然是使用插值,那么该如何插值呢,需要两次双线性插值,以及一次线性插值,比如当D为1.8时,先在D=1和D=2层分别进行一次双线性插值,再将这两个双线性插值的结果进行一次线性插值,此过程叫三线性插值(Trilinear Interpolation)。
采用mipmap得到的结果如下所示,发现在远处出现了过模糊现象,原因有二:一是因为mipmap只对方形区域有效,二是因为插值的影响。
解决方法为各向异性过滤(Anisortropic Filtering),该方法可对矩形区域进行查询,而不用限制在方形区域,但是各向异性过滤也不能对斜着的长条形区域进行过滤,而EWA filtering可对任意矩形区域进行查询,如下所示
5、纹理的应用
纹理可以存储的不仅是漫反射中的k d k_dkd 的值,只要是数据,都可以用纹理进行存储,因此,纹理的应用十分广泛。
5.1 环境贴图(Environment Map)
将物体周围的环境光用纹理图存储,再将纹理图映射到物体上就可得到由环境光渲染而成的物体。如下所示,左边为环境光的纹理图,右边为使用此环境光进行渲染得到的图。
那么,存储环境光的纹理图是如何得到的呢,有两种方法,一种是球体环境光贴图(Spherical Environment Map),一种是立方体贴图(Cube Map)。
5.1.1 Spherical Environment Map
Spherical Environment Map的思想很简单,就是放一个光滑表面球体在某处,那么球面上的图像即是周围环境的图像,即环境光,再将球体表面进行展开(地球仪到地图的过程),就得到了环境光的纹理图,如下所示,但是这样得到的纹理图在上下边界处有较大的扭曲,效果不是很理想。
5.1.2 Cube Map
Cube Map就能解决Spherical Environment Map中上下部扭曲的问题是,方法是,首先,同样用一个光滑表面的球体来收集环境光,接下来,先将球体表面的信息展开映射到一个立方体的六个表面上,再将立方体的表面进行展开得到环境光的纹理图。
5.2 凹凸贴图(Bump Mapping)
当纹理图用来存储基础表面的相对高度时,就可以根据此纹理图实现凹凸贴图,无需增加三角形数目,就可实现凹凸表面的效果,大大减少了计算量。
如何根据纹理图求出该点处的法线呢,首先,我们已知基础表面的法线,那么经纹理图扰动后该点的法线可如下计算
三维情况下同理
5.3 位移贴图(Displacement Mapping)
虽然凹凸贴图可以实现凹凸的表面,但是其在边界部分效果不好,此时可用位移贴图代替,位移贴图使用的纹理图和凹凸贴图一样,但是不同之处在于,位移贴图根据纹理图存储的信息直接移动了原来顶点的位置,而凹凸贴图并没有改变顶点的位置,只是重新计算了法线,如下所示