实时渲染中的菲涅尔效应



  光线追踪中使用的菲涅尔效应公式由平行项 r_{\parallel} 和垂直项 r_{\perp} 组成,而且针对绝缘体和导体的公式又不相同,计算非常复杂。用于实时渲染必须进行简化。

菲涅尔效应

  实际上,菲涅尔效应描述了光线的角度和光线反射率的关系。如果视线和法线夹角越大,眼睛接收到的反射光线能量越大;反之,夹角越小,接收到的能量越小。如下图所示:

fresnel_effect
  菲涅尔效应不仅仅局限于光滑的物体。所有的物体,包括石砖或者粗糙的墙面,在一定的角度下也可以察觉到菲涅尔效应——菲涅尔效应无处不在

菲涅尔效应实现

  在实时渲染中,会使用菲涅尔方程的估计公式。目前使用的比较多的公式有两个,它们都可以非常方便地应用到着色器中。
  

Schlick 估计

  Schlick 在 1994 年发表了论文 An Inexpensive BRDF Model for Physically-Based Rendering。这篇论文推导了一个估计公式,可以很好地模拟菲涅尔效应又不需要花费太多计算。由于计算力的提升,光线追踪渲染中的菲涅尔项计算被更精确的 Cook-Torrance 项替代。后来这个公式随着物理渲染被引入到实时渲染中。
  Schlick 近似的 Fresnel 项是:\displaystyle F_{Schlick}(c_{spec},v,h)=c_{spec} + (1-c_{spec})(1-(v\cdot h))^5  在上面的公式中,c_{spec} 表示着色点高亮的颜色,v 表示入射光线,由着色点指向相机,h 表示半角向量,定义为入射向量和反射向量的中间向量 h=normalize(v+l)。如果没有应用微面元模型,则有半角向量等于法向量 h=n。实际上,h 向量的意义就是在微面元模型下替代法向量的作用,本文不再赘述。下图为微面元模型图示:


microfacet

  代码的实现也非常简单:

float dotVH = saturate(dot(v, h))
FresnelTerm = SpecularColor + (1.0f - SpecularColor) * pow(1 - dotVH, 5);

  实际上,上述公式往往会使用 Spherical Gaussian 进行优化,替换掉效率低的 pow 函数,可以更好地使用硬件加速。这是另外一个话题。

Nvidia 提出的估计

  第二个公式时间更久远些,出自 Nvidia 公司出版书 Cg Tutorial 的第七章,也是一个经验公式。
  定义如下:\displaystyle F=bias+(1-v\cdot n)^{power}*scale  在上式中,v 表示视线,n 表示法向量。biasscale 则要根据经验和渲染结果来调整,bias 代表最小的阈值,scale 调节最大值,power 则调节主瓣的宽度,power 越大,fresnel 衰减得越快。
  代码实现如下所示:

float my_fresnel(vec3 V, vec3 N, float power,  float scale,  float bias)
{
    return bias + (pow(clamp(1.0 - dot(V, N), 0.0, 1.0), power) * scale);
}


About the Author

1 thought on “实时渲染中的菲涅尔效应

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注