NSDT工具推荐Three.js AI纹理开发包 - YOLO合成数据生成器 - GLTF/GLB在线编辑 - 3D模型格式在线转换 - 可编程3D场景编辑器 - REVIT导出3D模型插件 - 3D模型语义搜索引擎 - Three.js虚拟轴心开发包 - 3D模型在线减面 - STL模型在线切割

在深入探讨 BRDF 和照明模型的概念之前,我们将介绍一种用于模拟有光泽(glossy)表面(例如塑料球)外观的技术。 从那里开始,推广该技术将变得更加容易,这就是 BRDF 和照明或反射模型概念的全部内容。

图 1:镜面高光只是球周围场景中最强光源的反射。 球既是漫反射的又是镜面反射的(有光泽的)

在上一课中,我们学习了如何模拟镜面(mirror-like)和漫反射(diffuse)表面的外观。 但是有光泽的(glossy)表面呢? 首先,你应该注意到,我们刚才提到的塑料球示例不仅仅是纯粹的光滑表面。 与大多数材质一样,它可以被描述为同时具有漫反射成分和光泽成分(可以在图 1 中的球中看到的光泽或镜面反射)。

1、Phong模型

材料由于不同的原因而表现出这种双重特性。 在某些情况下,这仅仅是因为材料本身是不同材料的复合材料。 例如,塑料球可以由充当漫射器的薄片或小颗粒制成,但通过充当反射(通常是透射)材料的聚合物粘合在一起。 尽管薄片或小颗粒会漫射光,而聚合物会反射光。 在其他情况下,物体是由多种材料叠加而成的。 许多水果的皮都是这种情况。 例如,橙子有一层厚的皮层,其作用更像是漫射表面,其本身覆盖有一层薄薄的油层,其作用更像是镜面或反射表面。 总之,我们可以将许多材质的外观描述为具有漫反射分量和镜面或光泽分量。 我们可以用方程的形式表达这个概念:

其中Sp代表“P 处的着色”。 在这个等式中, diffuse() 就是我们在上一课中学习模拟的漫反射效果, specular() 是新的,将用于模拟对象的光泽外观。 两种效应的强度,或者说它以不同的方式平衡一种效应和另一种效应,可以通过这两个参数Kd和Ks来控制。在着色和计算机图形学的世界中,这些术语被赋予了许多名称,并且人们对它们进行了大量的研究。 你可以将它们视为漫反射和镜面反射分量的强度或增益。 通过调整它们,人们可以创造出各种各样的效果。 但这两个参数应该如何设置,我们稍后会讨论。 现在,让我们关注 specular()函数本身。

图 2:水面的波浪打破了背景场景的反射

Bui Tuong Phong 是计算机图形学领域一位有前途的研究员,他在 1973 年发表论文后不久于 1975 年不幸去世。他在这篇论文中提出的想法之一是,实际上许多材料可以通过加权漫反射和加权镜面反射分量来计算模拟。 有兴趣了解导致某些表面有光泽的原因的读者请阅读上一课的第一章。 有光泽高光只是物体对光源的反射。 这种现象类似于完美的镜状表面反射光源图像或场景中物体的图像,尽管光泽材料的表面不像镜子那样完全光滑,轻微的破碎(在微观尺度上)导致光以与镜面方向稍有不同的方向反射(水面的波浪会产生类似的效果,如图 2 所示)。 这具有模糊从物体表面反射的光的效果。 由于粗糙表面的表面就像一面破碎的镜子,因此计算机图形学研究人员喜欢将其定义为小镜子的集合,也称为微面(micro-facets)。

这里的微面概念纯粹是一种思想观点,并不明显“反映”粗糙表面的表面外观。 虽然表示粗糙表面,但微面的集合简化了数学方程的解析,然后可以使用数学方程来模拟粗糙表面的外观。 这是微面着色模型的基础。 可以在下一节中找到专门讨论此主题的课程。
图3:表面越粗糙,镜面反射越大且越暗。 可以将其视为光线在物体表面上“模糊”。

此时有两点值得观察:

  • 光源的光泽反射比镜状表面对同一光源的反射要暗(我们假设观察者沿着光线反射方向观看光源的反射,如图 3 所示)。 其原因是,只有一小部分微面或构成光滑物体表面的小镜子会沿观察方向反射光线,而对于类似镜子的情况 表面上,所有光线都沿该方向反射(图 3)。 在粗糙表面的情况下,当观察者沿着表面的理想反射方向向下看时,只有一小部分光线被反射向眼睛,因此亮度降低。
  • 随着观察方向与理想反射方向之间的角度增大,镜面反射的亮度会降低。 这是因为随着这个角度的增加,将光反射到眼睛的微面的数量减少,因此亮度降低。 当表面是完美的镜子时,当我们从观察到光反射的点在物体表面上走开时,找到沿观察者方向反射光的微面的概率就会降低。 这是微面分布方式的统计特性。

最后观察中重要的是,镜面反射的亮度随着物体表面上的点与如果表面是完美镜面则形成光源反射的点之间的距离的增加而降低。 下面的一系列图像说明了这个想法。 在左边,你可以在完美的镜子中看到小灯泡的反射。 当我们转向右图时,表面粗糙度会增加。 请注意反射的亮度如何降低以及灯泡的反射如何扩散到更大的区域。 另请注意,随着物体表面上的点与原始反射光位置的距离增加,高光亮度的强度会降低。

图 4:如果视线方向与镜子方向不完全一致,我们就看不到光源的反射。 尽管我们可以获取视图方向和反射方向之间的点积,但这可以指示两个向量彼此偏离的程度。 这就是用 Phong 模型模拟镜面反射的原理

Phong 观察到,通过计算入射到阴影点上的光线的理想反射方向并计算该反射光线与实际观看方向之间的点积,可以以某种方式模拟这种效果。 从上一课我们知道,要看到镜面表面上一点的反射,视线方向或视线需要与反射方向完全重合。 如果这些方向不同(即使是很小的差异),那么观察者将根本看不到该点的反射。 当两个向量相同时(当视角方向与反射方向平行时),它们的点积等于1。随着视角方向与反射方向之间的角度增大,两个向量之间的点积减小( 最终达到0)。

其中V是视图方向,R等于:

图5:不同的n值对应的(V.R)^n的形状

L是着色点P处的入射光方向,你可以在图 5 中看到该方程的图(红色曲线)。 尽管 Phong 注意到该曲线具有相当大的形状,其本身会产生相当大的镜面高光。 为了解决这个问题并塑造镜面高光,他将方程提升到某个值n的幂(通常称为镜面反射指数):

图 4 显示了该方程对于不同n值的形状。n值越高,曲线越窄,从而产生更小、更紧密的镜面高光。 如果你应用此模型并渲染一系列具有递增n值的球体,就会得到:

正如你所看到的,其中一些球体开始看起来像闪亮的灰色球体。 虽然有问题。 由于随着物体粗糙度的增加,微面向观察者反射光的概率会降低,因此镜面反射高光的整体亮度也应随着物体粗糙度的增加而降低。换句话说,高光越大,它应该越暗。 尽管在此渲染中情况并非如此。 不幸的是,Phong 的模型是经验性的,正如他在论文中指出的那样,这些数字n和Ks没有物理意义。 要调整镜面高光强度,你需要调整参数Ks直到获得想要的外观。

这是用于计算上面图像的代码:

Vec3f castRay(...)
{
    ...
    if (trace(orig, dir, objects, isect)) {
        ...
        switch (isect.hitObject->type) {
            case kPhong:
            {
                Vec3f diffuse = 0, specular = 0;
                for (uint32_t i = 0; i < lights.size(); ++i) {
                    Vec3f lightDir, lightIntensity;
                    IsectInfo isectShad;
                    lights[i]->illuminate(hitPoint, lightDir, lightIntensity, isectShad.tNear);

                    bool vis = !trace(hitPoint + hitNormal * options.bias, -lightDir, objects, isectShad, kShadowRay);
                    
                    // compute the diffuse component
                    diffuse += vis * isect.hitObject->albedo * lightIntensity * std::max(0.f, hitNormal.dotProduct(-lightDir));
                    
                    // compute the specular component
                    // what would be the ideal reflection direction for this light ray
                    Vec3f R = reflect(lightDir, hitNormal);
                    specular += vis * lightIntensity * std::pow(std::max(0.f, R.dotProduct(-dir)), isect.hitObject->n);
                }
                hitColor = diffuse * isect.hitObject->Kd + specular * isect.hitObject->Ks;
                break;
            }
            default:
                break;
        }
    }
    else {
        ...
    }

    return hitColor;
}

2、着色/反射模型

Phong 用于模拟闪亮材质外观的模型就是我们在 CG 中所说的反射(reflection)或着色(shading)模型。 材料看起来如此的原因通常是光与构成材料的微观结构之间非常复杂的相互作用的结果。 模拟这些相互作用太复杂,因此我们使用数学模型来近似它们。 Phong 模型因其简单性而非常流行,它只是这种反射模型的一个例子,但还存在各种各样的其他数学模型。 仅举几例:Blinn-Phong、Lafortune、Torrance-Sparrow、Cook-Torrance、Ward anistropy、Oren-Nayar 模型等。

3、BRDF的概念与Phong模型的兴衰

图6:光线方向I和视图方向V

如上所述,Phong 用来模拟闪亮材质外观的本质是一个函数。 此函数(包括镜面反射和漫反射计算)包含一定数量的参数,例如可以通过调整n来改变材质的外观,但更重要的是,它取决于两个变量,入射光方向(用于计算漫反射和镜面反射分量)和视图方向(仅用于计算镜面反射分量)。 我们基本上可以将此函数写为:

其中W0是表面法线N和视图方向V之间的角度,Wi是表面法线N和光线方向I之间的角度(图6)。 下标o代表向外的方向。 在计算机图形学中,该函数被赋予了“双向反射分布函数”或简称 BRDF 的奇特名称。 BRDF 只不过是一个函数,它返回给定入射光方向时给定视图方向反射的光量:

我们上面提到的任何着色模型,例如 Oren-Nayar 模型的 Cook-Torrance 模型都是 BRDF 的示例。 如果你愿意,还可以将 BRDF 视为描述给定对象如何散射或反射光的函数。 正如所建议的,反射光的数量取决于入射光方向和观察方向。 多年来已经提出了许多 BRDF:其中一些旨在模拟特定类型的材料。 例如,Oren-Nayar 模型非常适合模拟月球的外观,月球反射的光与漫反射表面所反射的光不完全一样。 其中一些模型是根据光学原理设计的,或者只是为了适应一些物理测量。 其他一些模型(例如 Phong 反射模型)更具经验性。 本课程专门介绍 BRDF 的概念,因此如果我们现在只触及该主题的表面,请不要担心。

BRDF 有好有坏。 糟糕的 BRDF 本质上是违反以下三个规则中的一个或多个:

  • 首先,BRDF 在有效传入和传出方向范围内的任何地方都是正函数。
  • 第二,BRDF 是互易的。 换句话说, BRDF(Wo, Wi) = BRDF(Wi, Wo) 。如果在函数中交换传入和传出方向,函数将返回相同的结果。
  • 最后,BRDF 是能量守恒的。 这本质上意味着 BRDF 不能产生比它接收到的光更多的光(除非表面本身是发射性的,但这是一种特殊情况)。 总体而言,物体反射的光量不能多于入射到其表面的光量。 BRDF 自然应该遵循相同的规则。

一个好的 BRDF 是符合这三个规则的 BRDF。 Phong模型的问题在于它本质上不是能量守恒的。 在本课程中演示这一点会太长,但如果你阅读有关 BRDF 的课程,就会了解原因。 一般来说,有几个因素有助于使 BRDF 变得有用且良好。 它需要物理上准确,需要准确,并且需要计算高效(这里应该考虑速度和内存消耗)。 Phong 模型在物理上并不正确,但计算效率高且紧凑,这就是它多年来非常流行的原因。 Phong 模型虽然被认为对于教授人们着色的基础知识仍然有用,但如今已不再使用,而是被更新的、物理上更正确的模型所取代。

4、镜面波瓣或漫射波瓣是什么意思?

图 7:漫反射波瓣和镜面波瓣。为了模拟复杂材质的外观,通常需要组合多个波瓣(例如,一个漫反射波瓣和 2 到 3 个具有不同镜面指数和权重的镜面波瓣)

让我们以您可能听说过或读过的镜面波瓣概念来结束本章。 当表面粗糙时,其反射光的方向与完美反射方向略有不同,但以完美反射方向为中心。 你可以通过绘制某种以反射方向为中心的细长形状来绘制或可视化此过程,如图 6 所示。这在某种程度上表示表面将光反射到的一组可能方向。 这就是我们在 CG 中所说的镜面反射波瓣。

在图 7 中,我们将此波瓣表示为二维形状,但该形状应该是三维的。 该波瓣的形状随着入射光方向的变化而变化。 这是大多数材料都具有的特性。 它们对每个可能的入射光方向都有独特的反射光方式。 对于真实材料来说,该波瓣或该波瓣的形状可能相当复杂。 我们可以使用一种称为测角反射计的仪器来获取它。 该仪器的功能是测量给定材料在给定入射光方向上在其表面上方每个可能方向反射的光量。 所得三维数据的形状取决于材料特性。 如果材质更加分散,结果将看起来像一个半球。 如果材质更具镜面性,则会出现围绕反射方向的长形波瓣。 从真实材料获取的数据对于派生数学模型非常有用,可用于模拟给定材料或验证给定 BRDF 模型的准确性。

如果 BRDF 模型的行为与测量数据类似(以相同的方式反射光),则该模型非常适合模拟测量材料的外观。 请注意,当你查看测量材料的反射率函数时,您会发现它们通常具有多个波瓣。 在 CG 中,我们通过组合具有不同参数和权重的多个波瓣来模拟这种效果。 例如,在图 7 的底部图中,我们组合了漫反射波瓣和镜面反射波瓣。 生成的材质应该看起来像 Phong 模型一样有光泽和漫射。 有关此主题的更多信息可以在下一节中找到。

5、其他类型的材料又如何呢?

图 8:对于 BRDF,我们假设光线照射到表面的点与同一光线被物体反射的点相同。 对于半透明物体,这两点是不同的。 光线可以在 x 点照射到表面,穿过物体构成的材料,然后在距 x 一定距离的 x' 点离开物体。

与看起来相反,材料只有几种类型。 正如前面提到的,物体的外观有时很复杂,但只需要组合不同的波瓣即可。 我们找到混合这些波瓣的配方的过程通常很复杂,但创建波瓣本身的方程,甚至反射定律或斯涅尔定律本身都非常简单。

正如前面课程中提到的,我们通常将材料分为两大类:电介质和导体。 导体本质上是金属:它们导电。 相反,电介质是绝缘体。 这包括塑料、纯水、玻璃、木材、橡胶、蜡等。导体(金、铝等)本质上是反射性的,并且可以使用反射定律轻松模拟它们的外观。

但请记住,你应该对电介质和导体使用不同的菲涅耳方程。 许多电介质的外观也有很大差异。 水木、塑料、蜡有不同的外观。 可以使用反射、透射和菲涅耳的组合来模拟水和玻璃。 木材本质上可以使用漫反射来模拟。 可以使用漫反射和镜面反射的组合来模拟塑料(Phong 模型可用于模拟塑料,因为它结合了这两个组件)。

模拟蜡是一个稍微不同的问题,因为蜡是半透明的。 在我们迄今为止研究的所有示例中,我们认为光线照射到表面的点和物体上相同光线反射到环境中的点是相同的。 BRDF 是基于事实确实如此的假设而设计的。 但在半透明材料的情况下,当光线照射到物体表面的 x 点时,它通常会穿过构成物体的材料,最终在不同的 x' 点离开物体。 当光线进入物体时,它会被材料的结构散射一次或多次。 射线通常遵循某种随机游走,直到它最终将物体留在某个随机位置。 BRDF 不能用于模拟此类对象。 我们需要另一种模型,称为 BSSRDF。 这个复杂的缩写词代表双向散射表面反射分布函数。 这种现象也称为次表面散射。 请查看下一节,了解有关 BSSRDF 和模拟半透明材质外观的更多信息。

6、我应该用物体的颜色对镜面反射着色吗?

CG 艺术家经常问这个问题,但即使是最有经验的艺术家有时也不知道确切的答案应该是什么。 这个问题的答案是……不。

如果该材料是电介质,换句话说,如果它不是导体/金属。 镜面反射只是光源在物体表面的反射。 因此,反射光的颜色应该与光源发出的光的颜色相同。 如果光源发出红光,则镜面高光应为红色。 如果光源发出白光,则镜面高光应该是白色的。 永远不要给镜面反射着色,尤其是物体的颜色。 如果物体是黄色的并且反射的光是白色的,则镜面反射不会是黄色的。 它会是白色的。

但对于金属来说,这条规则有一个例外。 有些金属有颜色(青铜色、金色、紫铜色)并且是纯反射性的。 如果你愿意,金属可以用它们的颜色改变镜面反射的颜色。 例如,金色是黄色。 对于铜来说,它是一些深橙红色等。如果你想模拟黄金的外观,你必须将反射光乘以金属的颜色:黄色。 但是,如果金属上覆盖有一层油漆,那么您模拟的外观就不再是金属,而是油漆层,油漆层本身就是电介质。 因此,在这种情况下,你不应该对镜面反射进行着色。


原文链接:The Phong Model, Introduction to the Concepts of Shader, Reflection Models and BRDF

BimAnt翻译整理,转载请标明出处