【GAD翻译馆】关于环境映射光照我们犯了哪些错误?让我来数数有多少……
翻译:王成林(麦克斯韦的麦斯威尔 ) 审校:黄秀美(厚德载物)
使用预过滤立方图的环境映射光照在实时CG中非常流行。
人们都了解它的基本功能:
1. 生成你的环境辐射亮度(radiance)(一个探头,离线或者实时)的一张立方图
2. 使用一个余弦半球内核模糊它可以实现漫反射光(辐射照度(irradiance)),而使用一些不同指数的phong叶片模糊它可以实现高光。phong不同的卷积都存储在立方图的mip链中,指数越大的叶片会被放在越粗糙的mip上。
3. 在运行时我们使用表面法线获取漫射立方体,使用反射向量获取高光立方体,使后者发生在与材料粗糙度相对应的mip上。
许多引擎止步于此,但是最近又新出现了几项拓展:
· 我们可以通过使用普通mip金字塔的多个层级避开过滤,这样权衡下来可以提高运行时的性能。
· 我们可以扭曲立方体,尝试对其进行调正,使其不被用在捕捉环境的准确位置上。
· 我们可以将理论从一个简单的Phong高光拓展到更复杂的Cook-Torrance模型。
尤其最后一项拓展会极大提升质量和适用性,它简直太棒了,我们有必要解释一下它。
Cook-Torrance BRDFs的问题在于它们依赖三个函数:一个取决于N.H的分布函数,一个取决于N.H,N.L和N.V的遮挡函数和一个取决于N. V的菲涅尔函数。
虽然我们可以通过在反射方向获取一个预先过滤的立方体对取决于N.H的函数求解(事实上有些不同,但是Phong和Blinn高光模型之间也有不同),但是如果有取决于N.V的部分,那么它会在预整合解法中加入另外一个维度(需要一个立方图数组),而我们完全不知道如何处理N.L,因为在环境光中我们没有一个单一的光照向量。
该解法的高明之处可以通过观察BRDF以及当改变菲涅尔函数和遮挡成分时它的形状的变化方式得到解释。
你应该注意到BRDF的形状,即环境贴图上的过滤内核,很大程度上取决于分布函数,而我们知道如何处理该分布函数。另外两个成分并没有改变太多的形状,而是会改变它的大小以及可以使它“远离”H向量。
我们可以想象一个近似,它将一个预先卷积的立方图mip金字塔整合到分布函数中,而其它的成分都以某种方式被转移到一个比例因子中,通过将它们预先整合到一张全白立方图中忽略了光照的分布。
以上是我们现在采用的主流拓展方法,我们使用一个(非常聪明的)平衡参数纠正只使用分布叶片预整合的立方图。
一切正常,但是现在万事大吉了吗?显然不是!我不会提供(至少现在不会)解决方法,但是你能数一数我们犯了多少错误吗?
1. 首先也是最重要的,反射向量明显不是半角向量。
a. 预先卷积的BRDF表示的是一个围绕反射向量径向对称的叶片,但是半角向量BRDF在掠射角(当H!=N)不是径向对称的,它被拉伸了。
b. 当R=H=N时它和基于反射向量的那个向量也不相同,但是这种情况下它可以用一个恒定的粗糙度校正值进行调整(只是记得要这样做!)
2. 如我们所说的,Cook-Torrance不只取决于半角向量叶片。
a. 我们有一个很好的解决方法,但是它只基于一个偏移量,而这虽然可以解释只使用分布和使用完整的CT构成之间的区别,它不是唯一的不同之处。
b. 菲涅尔函数和遮挡函数也“推动”了BRDF叶片,所以它在反射方向没有达到它的峰值。
3. 如果我们从近到需要考虑透视的点烘焙光照,那么抛弃位置的依赖性是错误的。
a. 最终当我们看见一束高光时我们会很难判断光照的来源方向(不错!),但是我们很容易发现附近物体反射中的错误。
b. 我们可以使用上文提到的扭曲,但是这样的话预卷积也会被扭曲。
c. 举个例子,如果我们认为立方图表示的是来自场景中的盒子的光从而对其进行扭曲,那么我们应该向盒子的方向跟踪BRDF,看看它是如何被投影到上面的。在大多数情况下,该投影不会是一个径向对称的过滤内核。
d. 在“盒子”附近的环境贴图中,问题和纹理卡片区域光紧密相关。
4. 我们没有考虑遮挡。
a. 任何形式的预卷积的环境光照的遮挡都会使其比例缩小,这是错误的,因为遮挡应该发生在预过滤之前。
b. 仍然以某种方式做阴影环境贴图光照。一个不错的方法是通过从反射向量中发射一个圆锥体使用屏幕空间(或者体素跟踪的)计算出的遮挡,即使该方法没有考虑圆锥体的粗糙度,或者以某种方式预先计算并烘焙了某种形式的定向遮挡信息。
c. 其实这仍是由于我们使用了某一点的环境贴图信息,而贴图不是在该点烘焙出来的。
d. 另外一个尝试修复该问题的不错的方法是重新标准化,如《使命召唤》中那样。
5. 我们没有考虑表面法线变化。
a. 我们需要强制一个特定的mip级别(texCubeLod),因为在我们的情况中mip代表了不同粗糙程度中的不同的叶片,但是这意味着考虑到在一个像素空间中法线改变的方式我们没有对该纹理进行抗锯齿。(注意:一些HW甚至将普通的texCube获取都搞错了)
b. 这里的解决方法很“简单”,因为它和高光抗锯齿相关,我们将法线的变化放到高光粗糙度中以实现抗锯齿。
c. 但是以上想法,就算不考虑细节,也有可能是错误的(仍然这样做)。它的问题和球面光照的“粗糙度修改”解决方法紧密相关,而且它也有同样的问题,即带有一个法向圆锥体的BRDF的常义积分要比任何粗糙度下的原始BRDF都要平。
d. 另外,法线空间不会是一个圆底的圆锥体,甚至我们使用有限差分ddx/ddy得到的近似结果也是椭圆形的。
6. 额外补充:立方图和dx9硬件的压缩问题。
a. 老旧的硬件不能正确地沿着立方图边缘做双线性过滤,因此会造成一些肉眼可见的缺陷,其中一些可以通过确保边缘纹素沿平面相同来弥补。
b. 大多数人不会想到如果我们在立方图上使用块压缩模式(DXT,BCn等等),那么块之间会有中断的地方,这会使边缘纹素再次不同。我们应该修改这些情况中的压缩器使得边缘块共享相同的引用颜色。
c. 添加边框会更佳。
d. 这些技巧也和沿立方图边缘做双线性过滤的硬件有关,因为使用那些硬件也许会慢一些……另外,避免使用底部mip……
最后我列出了一些链接,它们也许会激发你的灵感:
· 一个简介
· 记住你可以而且应该检查你犯的错误,通过对比预过滤的解决方法和重要性采样引用,可以通过在一个无预先过滤的环境映射上做很多测试(很慢地)进行实时计算。
· 一个最新的用于立方图环境光照的测试台。
· 通过多次快速抽调完成的过滤
【版权声明】
原文作者未做权利声明,视为共享知识产权进入公共领域,自动获得授权。