Texture Mapping
就目前学习到的知识我们知道,在正常光照场景中,对物体用指定的着色频率进行着色后,可以得到一个单一颜色的塑胶质感的表面。现在有一个需求,要怎样做才能让物体表面显示一些图案,如下图:
纹理映射
这个效果看起来就像是把一张图片“贴”在三角形上,这种将一个二维图像映射到三维模型表面上的过程就叫纹理映射(Texture Mapping)。在 Illumination 中讲 Shading point 时,我们定义了一些着色相关的概念,法线方向、观测方向、光照方向等,其中就包括物体表面参数。 物体表面参数可以包含颜色、亮度等信息,表面上不同的位置的参数也可以包含不同的属性,而纹理映射也正是利用了这一点。
我们把一个三维的物体表面展开,其实可以得到一张二维的图片,而纹理就是这样一张二维的图。
反过来要完成这个二维到三维的映射,我们就需要知道物体表面上所有的点跟纹理上的点的一一对应关系。因此二维的纹理也有自己的一套坐标系(横向 ,纵向 )。
正常情况下,纹理坐标的取值范围 [0, 1] 之间的浮点数。例如,在一个 512x512 像素的纹理图像上,左上角的像素的纹理坐标为 (0, 0),右下角的像素的纹理坐标为 (1, 1)。
对我们来说,通常可以认为三维模型多边形(比如三角形)表面的顶点对应到二维纹理上的坐标是已知的,这些数据可以来源于:
- 专业人士(美工)的创造(是一个非常繁杂的工作)
- 自动生成:也是目前的一个重大研究方向(叫几何参数化),就是在研究一个算法,把三维模型展开成二维纹理时,根据算法计算出模型中的多边形在纹理上的坐标,并使得展开结果依然保持模型的几何特征和拓扑结构。
纹理可以被重复使用。也就是说可以把同一张纹理贴在多个不同的物体表面:
图四:同一张纹理贴在多个不同的物体表面
而在实际应用中,我们却不容易发现纹理间的间隙:
这里面涉及到纹理的设计,可以通过一些纹理生成技术(比如 Wang Tiles 纹理合成算法)来完成。
插值纹理坐标
上面说三维模型多边形(比如三角形)表面的顶点对应到二维纹理上的坐标我们是知道的,但是我们不知道三角形内部的点对应到纹理坐标系上的坐标,这个要怎么办呢?
这里闫老师没有太具体地展开说,我就问了下 ChatGPT,结合 Barycentric Coordinates 里面的知识,它给出了这样的答案:
- 确定三角形顶点的纹理坐标。对于一个三角形 ABC,假设其三个顶点分别对应纹理坐标为(uA, vA),(uB, vB),(uC, vC),则可以得到三个重心坐标系数 λ1、λ2、λ3,满足 λ1+λ2+λ3=1。
- 计算目标点在三角形中的重心坐标系数。对于一个给定的点 P(x,y),可以先计算它相对于三角形顶点的距离比例,即:
λ1 = Area(PBC)/Area(ABC)
λ2 = Area(PCA)/Area(ABC)
λ3 = Area(PAB)/Area(ABC)
其中,Area(PBC)代表三角形 PBC 的面积大小,Area(ABC)代表整个三角形 ABC 的面积大小。可以使用向量叉积的方法计算这些面积,也可以使用海龙公式等几何计算方法。
- 插值计算纹理坐标。根据目标点的重心坐标系数 λ1、λ2、λ3 和三角形顶点的纹理坐标(uA, vA),(uB, vB),(uC, vC),可以得到目标点的纹理坐标(u, v),即:
u = λ1 * uA + λ2 * uB + λ3 * uC
v = λ1 * vA + λ2 * vB + λ3 * vC
这样,就可以根据重心坐标插值算法计算出任意一个三角形内部的点对应的纹理坐标了。
需要注意的是,重心坐标插值在一些特殊情况下可能会出现精度问题或者计算错误的情况,如当三角形面积过小、顶点共线等情况出现时。因此,在实际应用中,需要考虑到这些局限性,并结合具体需求和场景选择最适合的计算方法和算法。
非常详细。插值出目标点在纹理中的坐标后,如何应用呢?通常纹理是一个颜色属性。一个用法是可以直接取对应纹理坐标上的颜色作为漫反射系数 ,整个映射结果就相当于把一张图贴到物体表面。