计算机图形学12:纹理映射

计算机图形学12:纹理映射

1. 为什么需要纹理映射?

到目前为止,我们渲染的物体表面属性(如颜色)要么是单一的,要么是在顶点之间平滑插值的。这就像是用纯色颜料或渐变色给模型上色,很难表现复杂的细节。

纹理 (Texture),从广义上讲,是指物体表面属性的任何空间变化。这包括但不限于:

颜色的变化(如砖墙、木纹)

光泽度的变化(如部分磨损的金属)

透明度的变化(如彩色玻璃窗)

法线方向的变化(模拟凹凸不平的表面)

纹理映射 (Texture Mapping),就是将这些预先定义好的表面属性变化(通常是一张二维图片),“贴”到三维模型的表面上。这就像是给一个白色的墙壁模型贴上壁纸,或者给一个光滑的瓶子模型贴上标签。

核心优势:以计算换取几何。 我们用相对廉价的、在渲染时查询一张图片的成本,来替代创建数百万个微小多边形来模拟表面细节的巨大几何成本。

2. 纹理映射的基本流程

纹理映射的本质是一个映射 (Mapping) 过程,它在两个空间之间建立了一座桥梁:

纹理空间 (Texture Space): 一个通常是二维的、标准化的坐标系,用来定义纹理本身。这个空间中的图像我们称为纹理图 (Texture Map),其中的每个数据点称为纹素 (Texel)。纹理空间的坐标通常用 (u, v) 表示,范围通常是 [0, 1]。

对象空间 (Object Space): 我们三维模型所在的坐标系,坐标为 (x, y, z)。

映射过程分为两步:

分配纹理坐标: 对于模型的每个顶点,我们必须手动或通过算法为其指定一组纹理坐标 (u, v)。这个过程也称为 UV展开 (UV Unwrapping)。它定义了模型表面的哪一个点,对应于纹理图上的哪一个点。

渲染时插值: 在光栅化阶段,多边形内部每个像素的纹理坐标 (u, v),由其所属三角形顶点的UV坐标通过重心坐标插值得到。GPU用这个插值后的UV坐标,到纹理图中去查询 (lookup) 对应的纹素颜色,并用这个颜色来为像素着色。

3. 纹理映射的应用:不仅仅是贴图

“纹理”不仅仅是颜色图。我们可以用纹理来控制和“伪造”几乎任何表面属性,极大地丰富视觉效果。

颜色映射 (Color Mapping): 这是最常见的应用,用纹理的颜色来决定物体表面的漫反射颜色 ($k_d$)。

凹凸贴图 (Bump Mapping): 用一张灰度图来扰动表面法线。纹理中较亮的部分表示“凸起”,较暗的部分表示“凹陷”。在进行光照计算时,使用这个被扰动过的法线,而不是原始的几何法线。这可以在一个完全平坦的几何表面上,制造出极其逼真的凹凸不平的假象。注意,它只改变了光照效果,并没有真正改变模型的几何形状。

法线贴图 (Normal Mapping): 凹凸贴图的升级版。纹理中直接存储了预计算好的、完整的法线向量(XYZ分量编码到RGB通道中)。它比凹凸贴图能表现更复杂的表面细节,是现代游戏中塑造角色和场景细节的核心技术。

置换贴图 (Displacement Mapping): 这是唯一一种真正改变模型几何的贴图技术。它使用灰度图的高度信息,在渲染时(通常在顶点着色器或专门的细分阶段)将模型的顶点沿法线方向进行实际的位移。它能产生真实的凹凸轮廓和阴影,但计算成本最高。

环境映射 (Environment Mapping): 用一张纹理来模拟镜面反射。纹理图是周围环境的全景图(通常是立方体贴图或球形贴图)。对于模型上的每个点,我们计算出视线在该点的反射方向,然后用这个反射方向向量去查询环境贴图,得到反射的颜色。这可以高效地在光滑物体上伪造出反射周围环境的效果。

光照贴图 (Light Mapping): 将复杂的光照和阴影效果(通常是计算成本高昂的全局光照)预先烘焙 (bake) 到一张纹理上。渲染时,只需将这张光照贴图与物体的基础颜色贴图相乘即可。这是一种用空间换取时间的技术,能够在静态场景中实现高质量的全局光照效果。

4. 纹理映射的挑战:走样与滤波

纹理映射本质上也是一种采样过程,因此同样会遇到走样 (Aliasing) 问题。

放大 (Magnification): 当一个纹素被映射到屏幕上的多个像素时(比如相机离物体很近),会出现块状马赛克。

缩小 (Minification): 当多个纹素被挤压到一个像素区域内时(比如相机离物体很远),会导致闪烁、摩尔纹等现象。

为了解决这些问题,我们需要纹理滤波 (Texture Filtering) 技术。

最近邻滤波 (Nearest-Neighbor Filtering): 最简单的方法。直接选择离采样点最近的那个纹素的颜色。效果粗糙,会产生明显的马赛克,但速度最快。

双线性滤波 (Bilinear Filtering): 取离采样点最近的4个纹素,根据采样点与它们的距离进行加权平均,得到最终颜色。效果平滑,能很好地解决放大时的马赛克问题。

Mipmapping (多级渐远纹理): 解决缩小问题的关键技术。

预处理: 在加载纹理时,预先生成一系列从原始分辨率开始,每级分辨率减半的低分辨率纹理版本,构成一个Mipmap链。

渲染时: GPU根据物体在屏幕上的投影大小,自动选择最接近该大小的Mipmap层级进行采样。

三线性滤波 (Trilinear Filtering): 在两个最接近的Mipmap层级上分别进行双线性滤波,然后再对这两个结果进行线性插值。这能有效消除从一个Mipmap层级跳变到另一个层级时的突变痕迹。

各向异性滤波 (Anisotropic Filtering): Mipmapping假设像素的投影区域是正方形,但当视线与表面夹角很小时(如观察一条长长的公路),像素的投影区域会是一个狭长的矩形。各向异性滤波通过对不同方向进行不同频率的采样,能够在这种极端视角下依然保持纹理的清晰度,是目前最高质量的滤波技术。

5. 纹理坐标的处理

UV坐标: 通常用(s, t)或(u, v)表示,范围是[0, 1]。这个标准化坐标系使得一张纹理可以被应用到任意大小的模型上。

寻址模式 (Wrapping/Clamping): 当UV坐标超出了[0, 1]的范围时,该如何处理?

GL_REPEAT: 重复/平铺纹理。

GL_CLAMP_TO_EDGE: 钳制到边缘,拉伸边缘的纹素颜色。

GL_MIRRORED_REPEAT: 镜像重复。

程序化生成 (Procedural Generation): 除了使用图片,纹理也可以通过数学函数在运行时动态生成。这种程序化纹理可以产生无限的细节,且占用存储空间极小,常用于模拟木纹、石材、云雾等自然现象。