目录
纹理(Texture) 相当于着色物体的"皮肤",负责提供基础颜色,而为了方便表示纹理(可以想象下,一个3D物体的皮肤其实是可以展开成一张平面),往往使用一个二维颜色数组去表示纹理。
于是纹理平面就有了自己的坐标系(纹理空间),通常用u、v表示坐标轴。
在之前的着色(Shading)计算中,光照计算只是计算了物体受到多少光照的影响(可以粗略理解成亮度,因为有些光本身也会提供颜色),而纹理则可以给这些物体提供基础颜色。
为了使用纹理,对于每个三角形顶点vertex属性额外需要存储u、v坐标以便映射到纹理空间(由于三角形也是一个平面,因此非常方便映射到平面的纹理空间),三角形内的点则只需要根据三角重心坐标插值也能算出对应的u、v坐标。这样,三角形每个像素点就可以找到纹理中对应位置的颜色。
在某些情形下,我们可能需要将空间中的曲面(一般是指凸多面体)映射到纹理平面,即 \(f:\R ^3 \rightarrow \R ^2\) ; \((x,y,z)\rightarrow(u,v)\) ,那么就需要借助 球形贴图(Spherical Map) 或者 立方体贴图(Cube Map)。
所谓球形贴图,就是以球的形式映射贴图。
例如一个球面展开后,会得到这样一张贴图(但是球形贴图看起来会有一种扭曲现象,表现不直观):
球形贴图映射的思路:
此处的物体一般是指凸多面体网格,而渲染中的曲面(包括球面)实际上也是又若干个三角面组成,因此也算是多面体网格。
立方体贴图,通过使用构成立方体六个表面的六张贴图存储周围环境影像:
立方体贴图映射的思路:
纹理映射的一个问题是,当纹理颜色变化多且高分辨率(高频信息多),而渲染目标物体的像素量少(采样频率过低)时,很容易出现锯齿现象和摩尔纹现象。
换句话说,当屏幕一个像素点(如对应下图的斜四边形)实际对应纹理很大片的纹素区域时,只通过像素点中心采样得到的纹理颜色结果不能准确表示整片区域的纹理颜色。
使用超采样的方法可以避免走样问题,然而需要付出极大开销:
Mipmap技术则可以让纹理采样进行快速的近似正方形范围查询,它需要预先提供多层分辨率各不同(每层纹理长宽都比上层缩小一半)的纹理(用D表示它们的层级)
注:Mipmap技术的纹理额外空间开销为原分辨率纹理的1/3
这样当屏幕像素点对应纹理中较大片纹素区域时,可以选择相应高层级的纹理(低分辨率纹理),这样就能近似的对应低分辨率纹理中的一个纹素而非对应高分辨率纹理的一大片纹素区域,从而也就能近似表示这片区域的纹理颜色。
选择层级的方式则是计算屏幕像素点对应在纹理坐标中的最大微分(du、dv中取变化最大的),从而得到近似正方形的边长L,最后通过log2函数可以得出层级D,这样就可以选择合适的Mipmap层级。
为了避免着色三角形时而远时而近,导致频繁切换Mipmap层级产生突兀的变化,实际上还需要使用了层级之间的插值(根据D值),这样就可实现两个层级之间切换的平滑过渡。
Mipmap的一个缺点是,它只适合近似正方形范围查询,当一个屏幕像素点对应的纹素范围是别的形状(尤其长条形状)时,很容易导致近似正方形覆盖的区域比实际覆盖区域大得多,从而造成过度模糊现象(例如下图中远处的格子已经模糊地看不见黑色区域)
各向异性过滤的原理:在Mipmap的基础上提供横向伸缩和纵向伸缩的纹理层级(以适应横着和竖着的长条形状);但是这只能减少上述过度模糊现象的发生,因为实际渲染中还有斜向的长条形状或者其它难以近似的形状。
注:各向异性技术的纹理额外空间开销为原分辨率纹理的3倍
此外,还有一种少见的各向异性过滤方法:EWA过滤,大概原理就是任意一个不规则形状都可以拆解成不同的圆形,虽然通过多次查询的效果很好,但是性能代价非常高。
纹理通常被认为是物体的“皮肤”,因为本质上它是一个二维数组,存储的元素是颜色。但是随着纹理技术的发展,纹理衍生成了一个广泛的意义:存储某种数据的N维数组。下面各种技术便是将纹理应用到不同方面的体现。
现实世界中,有些物体非常远(例如远处的山、树林、天空),无论观察者怎么移动,这个物体的大小是几乎没有什么变化的。这些物体往往是做成场景的背景图,一般被称为 天空盒(SkyBox)。
天空盒渲染原理:
渲染该立方体时应当选择不写入深度方式(天空盒在渲染时应该为最远的深度,换句话说不应该遮挡任何其他物体)+取消背面消隐(因为在渲染立方体内部表面)。
优化:
现实世界的环境光是非常复杂的,存在大量经过多次反射后到达着色物体后再到达人眼的间接光(例如光照在窗户上,窗户再反射到杯子上,杯子再反射回人眼),这个过程中会把反射经过的物体颜色按一定权重混合在一起(因此看到的杯子混合了窗户的颜色),最后在着色物体形成近似“镜面反射”的效果(本质上就是接受了复杂环境光的结果)。
为了实现接受环境光的效果,我们可以用一个贴图来存放环境光信息,即 环境贴图(Environment Map) 或 反射贴图(Reflection Map),在给物体着色的时候不仅采样普通纹理,也采样环境贴图,按一定比例混合这两者的颜色(例如物体材质越光滑,镜面反射效果越强)。
对于360°方向均需要镜面反射现象的物体(如金属球),应采用立方体贴图方式映射;对于单一方向需要反射现象的物体(如一面镜子),可以使用普通方式映射。
如何生成立方体贴图方式的环境贴图(一个最简单的方式):
优化:
在平时的渲染中,高质量的光照(例如光线追踪, 辐射度, AO,阴影等算法)计算量无疑是庞大的,实时计算这些光照性能开销巨大,但是光照贴图给我们提供了一个预计算的方法:
在Unity中,如果我们把有网格组件的GameObject勾上static属性时,该物体会被认为是参与烘培的物体,从而为它预计算出光照贴图(也包括重新计算其它static物体的光照贴图)
好处:
代价:
环境光遮蔽(Ambient Occlusion)本质上也属于环境光的一部分计算,只不过是表示遮蔽的部分(而非光照的部分)。这种屏蔽的来源是来物体和物体(包括局部物体)相交或靠近的时候遮挡周围漫反射光线的效果,可以解决或改善场景中缝隙、褶皱与墙角、角线以及细小物体等的表现不清晰问题,综合改善暗部阴影细节,增强空间的层次感、真实感。
而通过环境光遮蔽贴图,我们可以预先计算环境光屏蔽结果,并将计算结果存放于贴图中。等着色的时候便可以通过采样环境光遮蔽贴图来得到遮蔽系数,从而增添一些暗部阴影细节。
所谓凹凸贴图,就是通过改变表面各点的法线,使本来是平的东西看起来有凹凸的效果,是一种欺骗眼睛的技术(因为物体结构并没有发生改变)。例如这个球看起来凹凸不平,实际它的几何结构就是光滑的球,只是通过凹凸贴图改变了各像素点的法线方向,从而导致光照结果不一,产生出凹凸不平的视觉效果:
高度贴图中存储的元素是高度 \(H\),用于表示局部高度偏移。对输入位置 \(p=(u,v)\) 通过一定公式就能得到其位置上的法线 \(n\)。
\(\frac{dp}{du} = c1* [H(u+1,v)-H(u,v)]\)
\(\frac{dp}{dv} = c2* [H(u,v+1)-H(u,v)]\)
\(n_{tangent}(p) = Normalize(-\frac{dp}{du},-\frac{dp}{dv},1)\)
实际上,切线空间下的法线往往还不可以直接使用在光照计算,这是因为光线、视野等方向的向量往往实在模型空间下的,需要将所有这些方向统一坐标空间才可共同参与光照计算。后面切线空间的法线贴图会给出转换切线空间和模型空间的方式。
高度贴图的一个问题是它需要经过较复杂的计算才能得出法线(开销略大),而法线贴图的做法则是直接存储表面法线的方向(相当于预先计算好法线)。
不过,在存储法线时需要将法线方向的分量[-1,1]映射到像素分量[0,1]:
\(pixel=(n+1)/2\)
同理,当对法线纹理进行采样后,也需要进行一次反映射,用于得到原先的法线方向:
\(n=pixel∗2−1\)
切线空间:对每个模型顶点,它都有一个属于自己的切线空间,其原点是顶点本身,z轴就是法线方向(normal),x轴就是顶点的切线方向(tangent),y轴就是法线和切线叉积所得,也就是副切线(bitangent)。
而另一种法线贴图则是记录切线空间下的法线(第一种记录的表面法线是在模型空间下的),换句话说,切线空间的法线本质上就是在记录"相对"的法线信息(而模型空间的法线本质上则是记录"绝对"的法线信息)
将该切线空间下的法线 \(n_{tangent}\) 转换为模型空间下的法线 \(n\) 的方法:
\(B = N \times T\) ,其中 \(N\)、\(T\) 分别为顶点上的原始的法线、切线(tangent),\(B\) 则称为副切线(bitangent)。
\(n = [T\ B\ N]\cdot n_{tangent}\)
好处:
代价:
光照计算的空间变换有两个选择:
法线贴图的一个问题是与当前的视角无关。因为实际上,从不同的角度去观察一个凹凸不平的物体上的同一位置,看到的法线应该是不一样的。
例如下图,本应该看到的是真实模型B点的法线,而实际上却因为原模型不包含凹凸信息而直接看到了点 T(actual),将该点用于查询法线贴图从而得到了真实模型A点的法线:
Parallax算法的解决方法是:
\(offset = c\cdot H(u,v)\cdot\frac{[V_x \ V_y]^T}{V_z}\)
不过在计算时,需要将视角方向 \(V\)变换成切线空间下的方向。
\(T_b = T_a+offset\)
好处:
代价:
Relief Map又叫 浮雕纹理 ,是对 Parallax 的进一步精确。如果说Parallax只是根据视角方向在切线空间下的投影和高度图作近似的偏移,那么Relief Map则是以找到正确点B点进行采样为目标,具体分为两步:
好处:
代价:
位移贴图(Displacement Map)则是真正修改模型几何的贴图,它存储了每个像素的位移量(实际上也是一种高度贴图),通过修改顶点位置,从而产生新的模型。
代价(相比于Bump Mapping):
之前介绍的光照计算中是不包含阴影的,而阴影映射(Shadow Mapping)则是常见的实现阴影计算的手段。
阴影贴图基本原理:
如图,Shadow Map记录了光源摄像机所看到的最近深度图,颜色越深,离摄像机越近:
如图,为主摄像机每个像素经过变换后比较深度的结果,其中绿色点意味着深度 \(z\) 约等于阴影贴图对应遮挡深度,非绿色点意味着深度 \(z\) 更大(即被遮挡了光照):
以上只是Shadow Mapping的基本解决方案,实际上它仍然有很多不足的地方(例如noise问题、Soft Shadow问题),业界往往采用更加高级的Shadow Mapping解决方案(例如Bias、PCF、PCSS、VSM)。
手机扫一扫
移动阅读更方便
你可能感兴趣的文章