表面上的坐标系
一句话总结
UV是纹理图像上的坐标,每个顶点贴在一起,拉丝器会对每个像素进行插值。从那个坐标中提取颜色的方式是取样化,放大时和缩小时需要的方法不同。
为什么需要这个?
如果每个顶点都涂上颜色,那么一个三角形只能涂上三种颜色。要表达砖块图案或文字,就必须将顶点切割成与图案相同的形状,但这是不可能做到的。
纹理颠覆了这个问题。将颜色从几何中分离出来,放在一个单独的图像中,只确定表面每个点的图像指向哪里。那个“哪里”就是UV坐标。然后就可以在两个三角形组成的矩形上贴上任何复杂的图像。
怎么行动
UV通常设定在0到1之间,(0,0)是图像的一个角,(1,1)是对角线对角角。哪个角是(0,0)因API而异——OpenGL在左下角,Direct3D在左上角。一半的纹理反转出来的错误都发生在这里。
如何处理超出范围的UV是包围模式。重复(repeat)只醉了少数部分重复图案,然后剪掉(clamp)增加边缘值,镜子(mirror)一次翻过来粘贴。瓷砖图案有重复,当直接粘贴一张画时,应该剪掉。
去除颜色的方法有两种基本。
최근접(nearest) i = floor(u * 폭), j = floor(v * 높이) 자리의 텍셀 하나
쌍선형(bilinear) 이웃한 텍셀 네 개를 가로세로 비율로 섞는다
在双线型中,重要的是像素的中心在(i+0.5)/宽度处。如果忽略这个半格,画就会向后移动半像素。所以坐标u * 폭 - 0.5搬到后,分开净水部和小水部。
远近校正补间在纹理中特别重要。如果把UV直接混合到从画面坐标中获得的重量中心坐标上,那么在包含远近的面上纹理就会扭曲。因为在3次元空间中,画面均匀分开的间距是不均匀的。正确的方法是u/w,v/w,1/w是将前后两个划分为前后两个。
iw = Σ bary_k * (1 / w_k)
u = Σ bary_k * (u_k / w_k) / iw
这是因为没有做这个校正,早期的控制台游戏会有地板纹理晃动。现在硬件会自己处理,但值得知道为什么需要它。
缩放是另一个问题。如果一个像素覆盖几十个像素,只能选择其中一个,就无法代表原来的图案。即使相机稍微移动,选择的像素也会改变,画面也会闪烁。解决办法很麻烦——提前将纹理减少一半,制成链条,然后选择适合像素覆盖的像素数量的步骤进行写入。而不是使用三分之一更多的内存,而是消除闪烁,在绘制小画时反而提高了快取命中率,速度更快。
异方性滤波弥补了黏糊糊的局限性。黏糊糊假设一个像素横向纵向都均匀覆盖像素,但在看起来像地板一样斜的面上,只向一边长距离覆盖。这时,如果把黏糊糊步骤对准长的一边,短的一边就会模糊得比必要的多。所以游戏中图形设置中的异方性滤波是沿着长的一边抽取多个样本,以恢复模糊度。这个选项的效果是使远处的道路变得清晰。
纹理在内存中的放置方式也会影响性能。屏幕上的相邻像素通常读取纹理的相邻像素,如果按行优先顺序直接放置,垂直相邻的像素就会在内存中远离。因此,GPU会将纹理重新排列成小矩形块来存储。这被称为切换或瓷砖布局,是纹理上传比简单复制慢的原因之一。
在现场相遇的样子
在瓷砖图案的边缘可以看到细线的问题很常见。这是因为在重复模式下,双线性采样将图像的右端和左端混合在一起,这实际上是重复模式按预期操作的结果。相反,使用裁剪模式时,不会混合对面的端点。
另一个是阿特拉斯的漏出。是把很多画合在一张画上,用UV切割后使用的方式,在低级别的混色阶段,邻近画的颜色会混合进来。需要在画之间留出空白或限制混色阶段。
最后,我将指出谁决定UV。顶点的UV是在建模阶段由人或工具决定的。因为是将3维表面展开成2维平面,所以必须决定将切割线放在哪里,将扭曲放在哪里。这项工作被称为UV展开,如果做错了,图案会变长或接缝会显眼。在遮罩方面,只是接受已经确定的UV来使用,但如果图案异常,最好知道原因可能不是遮罩而是模型。
下次实习要做的事情
制作格子图案纹理,分别实现最近接和双线性样本化。然后在包含透视的正方形上贴上图案,并并排观察未校正和校正的图像,提取差异图像。最后,用细小的摇晃图案制作粗糙的步骤,用数字确认噼啪声消失。