环境光照与纹理的扩展
前面我们讲了纹理的映射以及走样处理,这一篇我们讲一下纹理贴图的其他用法。
简单来说,在现代 GPU 中,纹理已经不单单是一张贴图了,它的本质是一块高效的内存数据,加上一套硬件加速的范围查询(过滤)机制。
Memory(内存数据):它本质上是一个多维数组(1D, 2D, 3D),可以在里面存储任何你需要的数字(不仅是 RGB 颜色,还可以是坐标、法线、密度、甚至是复杂的数学查找表)。
Range Query / Filtering(范围查询/过滤):这是 GPU 硬件层的能力。当你去查某个点的数据时,硬件可以瞬间帮你做双线性插值(Bilinear)、三线性插值(Trilinear)或者各向异性过滤(Anisotropic),并且自带 Mipmap 这种加速空间范围查询、防止走样的机制。
纹理除了作为贴图外,还有很多用法,比如 Environment Lighting(环境光照)、Store Microgeometry(存储微观几何信息)、Procedural Textures(过程纹理)等。
下面我们主要介绍环境光照和几何信息中的凹凸贴图、位移贴图。
环境光照
在图形学中,环境光照(Environment Lighting)指的是物体表面接收到的、来自周围整个环境的间接光照。它不是由单一的、明确方向的点光源或平行光源照射产生的,而是周围环境中的光线经过无数次反弹、散射后,从四面八方汇聚而来的光。
对于这些光照,如果我们直接计算会非常麻烦,于是我们想到可以将周围环境的色彩和亮度数据存储在纹理中。渲染时,片元根据自身的属性去这张纹理中进行范围查询。
环境光照的纹理存储方法主要有两种,Spherical Environment Map (球面环境贴图)和Cube Map (立方体贴图)。
球面环境贴图
球面环境贴图(Spherical Environment Map)将整个环境的光照信息存储在一张二维纹理中,就像用鱼眼镜头把周围 360° 的景象拍成一张照片。渲染时,根据片元的反射向量或法线向量,计算出对应的纹理坐标,直接采样这张纹理即可获取环境光照。
这种方法的优点是实现简单,只需要一次纹理采样。
但缺点也很明显:球面映射在靠近极点(顶部和底部)的区域会产生严重的拉伸失真,导致这些方向的环境光精度不均匀。
立方体贴图
立方体贴图(Cube Map)将环境映射到立方体的六个面上(上、下、左、右、前、后),每个面都是一张正方形的二维纹理。渲染时,根据片元的反射方向,先确定射线击中了立方体的哪个面,再在该面上计算 UV 坐标进行采样。
相比球面贴图,立方体贴图的六个面各自独立、分辨率均匀,不存在极点拉伸失真的问题,因此在实际游戏和实时渲染中应用更为广泛。
球面和立方体贴图的转化
这两种贴图存储方式是可以相互转化的。给定一张球面贴图,可以通过遍历立方体六个面的每个像素,反向计算出该像素在球面上的对应 UV 坐标,将球面贴图的颜色写入立方体贴图对应面中。反之,也可以将立方体贴图展开或重新采样为球面贴图。这种转化在离线预处理阶段完成,运行时直接使用转化后的贴图即可。
凹凸贴图
如果我们想让模型表面实现凹凸效果,我们肯定能想到增加模型的顶点数量,也就是使用更加精细的模型。但是这也就意味着更多的计算量、更高的采样率。有没有什么更简单的方法呢?
答案是有的,我们可以使用凹凸纹理(Bump Texturing)处理。在 3D 图形学中,凹凸纹理处理是一项用来“欺骗眼睛”的核心技术。它的核心目的只有一个:在不增加模型顶点(Vertex)数量的前提下,通过纹理数据改变物体表面的光照反馈,让原本平坦的低模(Low-Poly)呈现出极其丰富的微观几何细节(如皮肤毛孔、砖墙缝隙、金属划痕)。
如图,对于凹凸高度,我们可以用一张黑白灰度图来表示,颜色越浅说明高度越高,反之说明高度越低。
我们知道,光照的计算最关键的是法线,确定了法线向量,我们便可以利用光照模型渲染出逼真的光照。
如图,模型原本的法线向量为
我们可以将纹理采样得到的颜色向量取模,模长代表着颜色的深浅,然后求出采样点附近模长的变化率,得到采样点处的切线向量
通过向量运算,我们可以轻松求出与切线向量垂直的向量
推广到三维空间,对于二维贴图,我们只需要分别求出
但是我们得到的法线向量
我们在推导
这个以贴图本身为基准建立的局部三维坐标系,就是”切线空间”(Tangent Space)。
如果我们直接将法线向量
为了实现切线空间到世界空间的转换,我们需要在模型的每一个三角形表面上,找到三根轴在世界空间里的真实朝向。
于是,我们引入了 TBN 矩阵,该矩阵由三条向量构成:
(Tangent - 切线):网格表面上,沿着纹理 轴延伸的那个三维世界方向向量。 (Bitangent - 副切线):网格表面上,沿着纹理 轴延伸的那个三维世界方向向量。 (Normal - 原法线):模型原本平滑表面上,垂直于三角形向外的那个三维世界法线向量(也就是图中原本的法线 )。
法线向量
比如
TBN 与向量
有了世界空间下的法线向量,我们便可以进行光照的计算了。
位移贴图
对于刚才的凹凸贴图,我们实现了光照的添加,虽然光照会让我们认为模型表面是凹凸不平的,但是存在两个问题:
模型边缘会暴露。如果你去观察模型的轮廓边缘,你会发现它依然是平滑的线,根本没有凹凸起伏。
无法产生真正的自阴影。因为表面实际上是平的,一个凸起由于高度产生的阴影,无法真正遮挡住它后面的微观表面。
因此,我们为了让模型表面点的坐标产生真实变化,引入了位移贴图(Displacement Mapping / Height Mapping)。
它的工作原理是:
顶点细分(Tessellation):GPU 会把原本平坦的低模三角形,在运行时切碎成成千上万个微小的网格顶点。
坐标修改:在顶点着色器(Vertex Shader)中,GPU 读取高度图(Height Map)的值
,然后真正去修改顶点的世界坐标:
这样,原本平坦的表面在几何上真正产生了凹凸,轮廓边缘也能正确显示出起伏,阴影计算也会基于真实变形后的几何体进行,不再有”穿帮”的问题。
位移贴图的代价是显而易见的:它需要在运行时动态生成大量顶点,对 GPU 的计算和带宽要求远高于凹凸贴图。因此在实际工程中,凹凸贴图用于表现微小细节(毛孔、划痕),位移贴图则用于需要真实几何变形的大尺度起伏(如地形、砖墙的深度缝隙)。
总结
纹理在现代 GPU 中远不止”贴图”这么简单——它是一块可高速查询的显存数据,配合硬件插值与过滤机制,可以承载各种图形学数据。
- 环境光照:将周围环境的光照信息存入纹理(球面贴图或立方体贴图),渲染时通过反射方向采样,高效模拟间接光照。
- 凹凸贴图:通过纹理记录高度信息,利用高度变化率扰动法线方向,在切线空间中计算扰动后的法线,再通过 TBN 矩阵转换到世界空间参与光照计算,以极低的性能代价”骗过”人眼。
- 位移贴图:直接修改顶点世界坐标,真正改变几何形状,解决了凹凸贴图在轮廓边缘和自阴影上的缺陷,但代价是更高的计算开销。
这次的插图来自画师 mmAir
图片地址:https://www.pixiv.net/artworks/136238938