实时渲染管线与纹理映射
(1)管线(Pipeline)
从一个场景到最后一张图,中间到底经历了一个什么样的过程,这个过程就叫做管线(Pipeline)。
(2)纹理映射
任何一个三维物体的表面都是二维的,使之与一张图有一一对应的关系。纹理就这样一张图。
下面第一幅图是 Blinn-Phong 可以做到的,但是我想让它蒙上一张图。纹理映射。在三维物体上应该如何映射到纹理空间上。
有两个解决办法:
1)需要艺术家的创造,或者美工来完成的。任何一个三角形它会被映射到哪。
2)自动化。这块很难,在几何上是非常厉害的研究,或者叫参数化。
怎么把空间中的三角形映射到纹理上,我们不管,我们假设这块已经完成了,已经有了这样一个映射关系。
纹理上的坐标 (u, v)
纹理可以像贴瓷砖一样不断地进行重复。四方连续,无缝贴图,需要进行精心设计。关于纹理无缝衔接的合成也是非常值得研究的事情。
(3)如果纹理太小了
以上讲的是双线性插值,做了两趟插值,水平一趟,竖直一趟。效果也挺不错的。
(4)如果纹理太大了
纹理更大了不是什么信息都有了吗,怎么会引起什么问题呢?反直觉
如果仍然用原先简单的方法,像素中心找纹理坐标,就会得到右边的效果,近处严重的锯齿,原处摩尔纹。出现走样问题。
如果一个像素覆盖在纹理上有很大一块区域,如果我现在还用它的中心去查纹理坐标上的中心,然后用这个点去代替这区埃区域所有像素的值,但它实际上代表不了这块区域的值,就会出现问题。
我们如果用之前抗锯齿 MSAA 的方法,一个像素我用更多的样本,来感知像素内的变化函数,没问题。
每个像素用 512 个采样点值的平均,能得到一个不错的结果。但是肯定会让算法变得特别慢,我们不希望这么做。
这是一个点查询问题和范围查询问题
前面的像素覆盖在纹理上范围小,后面的像素覆盖在纹理上范围大。
Mipmap 可以做快的、大约的、正方形的范围查询。
每做一次,每一条边都砍一半
想办法先将这些 Mipmap 先生成。在图像界叫做图像金字塔。
经过级数求和可以得到最终需要存储的大小是原来的 4 / 3。也就是说跟原来相比其实只增加了 1 / 3。也可以通过上图直观理解。
也就是说,我可以用正方形框来近似这个不规则区域:
那么现在我可以用边长是 L 的区域跟之前计算好了的 Mipmap 进行一个查询。假如这个区域的大小是 1 * 1,我就可以直接在原图上进行查询,如果是区域大小是 4 * 4,那么在第二层上会变成一个像素。所以在第 log2L 层去查询它。
但是不连续的层的像素之间的衔接问题怎么办?我们是在第 0 层、第 1 层 ... 进行查询,我们可没算第 1.5 层是什么。
插值就行了。
我们在第 D 层做双线性插值,在第 D+1 层做双线性插值。之前我们是在水平和垂直方向做的插值,现在我们在层与层之间再做一次双线性插值,离哪层近哪层的权重就大。我们管它叫三线性插值。
这样一来就没有任何死角了。
三线性插值非常有效,所以它在各种各样的游戏、各种各样的实时渲染中得到了非常非常广泛的应用。
Mipmap 确实挺好的,但是 Mipmap 是否真能完全解决问题,这是我们要思考的。
Mipmap 到了远处它会把所有细节信息全部糊掉。
有一个办法可以部分解决 Mipmap 这个问题:各向异性过滤。
因为我们使用的是正方形
各向异性过滤如下:
可以看到,做了不同的长宽比的预计算,Mipmap 做的其实只是对角线上的图片。
这时可以查询到对应到原始图像的矩形的区域,而不用限制在一个正方形的区域上。对于一些长条形的区域就可得到很好的解决。各向异性过滤允许我们对这种长条形的区域做一个快速的范围查询。
但是各向异性过滤仍然没能解决这个问题,因为有些斜着的矩形框的效果也不是特别好。即各向异性过滤只解决了部分的问题。并且存储的开销是原来的 4 倍。人们又发明了另外的一些方法,比如 EWA 过滤:
但是 EWA 需要多次查询,也付出了一定代价。