如何在PBR中实施金属工作流程?

时间:2016-04-04 11:23:52

标签: opengl graphics directx rendering pbr

Cook-Torrance BRDF以及Lambert BRDF上有很多材料。 Real Shading in Unreal Engine 4Moving Frostbite to BPR深入解释了如何将它们实现为实时渲染。

他们省略的是两个BRDF的组合,以创建完整的着色模型。如果我理解正确,我们可以使用至少两个基本原则来做到这一点:镜面和金属工作流程。 Here是对它们的比较。

我决定实施金属工作流程。所以我有以下参数来计算:

  • Albedo(RGB)
  • 粗糙度(漂浮物)
  • 金属度(浮动)

对于镜面反射部分,我需要确定镜面反射颜色。

Mamoset表示

  

使用金属度贴图时,绝缘曲面 - 像素设置为0.0   金属度图中的(黑色) - 被赋予固定的反射率值   (线性:0.04 sRGB:0.22)并使用反射率映射进行漫反射   值。对于金属表面 - 像素设置为1.0(白色)   金属度图 - 镜面颜色和强度取自   反照率地图,着色器中的漫反射值设置为0(黑色)。

因此,镜面反射颜色应按以下方式计算:

vec3 specularColor = mix(vec3(0.04), material.albedo, material.metalness);

随后,这可用于计算反射辐射。为了限制我的问题的范围,我将在这里参考Brian Karis的实现,其中包括:

vec3 L_specular = specularIBL(specularColor, material.roughness, normal, view);

对于漫反射部分,我需要确定反照率。

上述相同的引用描述了它的工作原理:

vec3 albedo = mix(material.albedo, vec3(0), material.metalness);

现在,Lambert BRDF可用于计算来自某些入射辐照度E的漫反射光照:

vec3 L_diffuse = f_lambert(albedo) * E;

为了获得最终的光亮度,漫反射和镜面反射部分组合在一起:

vec3 L = kd * L_diffuse + ks * L_specular;

我的问题是如何计算kdks

  1. Codinglabs建议将菲涅尔函数整合到半球上以计算ks
  2. 之后

    kd计算:

    vec3 kd = (1 - ks) * (1 - material.metalness);
    

    我在非金属上得到的结果并不是我所期望的,例如将它与虚幻引擎进行比较。在正常入射时预期的反射要低得多,这应该归因于在非金属情况下设定的低F0。但我检查了更多的来源,0.04似乎是常用的值。

    有人可以确认Codinglabs的建议计算吗?或者甚至提供Epic使用的代码?

1 个答案:

答案 0 :(得分:1)

正如您已经确定的,反照率对应于材质的漫反射颜色。

说到镜面反射,它有两种方式:电介质或导体(通常为金属)

对于电介质,这很简单,镜面反射颜色始终为纯白色(无着色),并由菲涅尔和基础反射率(也称为 F0< /strong>) :此标量仅表示直视表面时反射的光的百分比。

0.04”值对应于 4% 基础反射率,您可以通过将 1.5 的 IOR 替换为 < em>n1 在菲涅耳反射率公式和空气的 IOR(近似于 1.0)对于 n2 (taken off Wikipedia)

enter image description here

在互联网上很容易找到给定材料的 IOR,而且大多数介电常数都在 1.5 左右。


在导体的情况下,公式不是那么简单,所以你会发现实现的通常方法(由 Codinglabs、UE4 和其他引擎)是明确指定金属的色调/反射/镜面颜色,因为它对艺术家更友好。例如,纯红色意味着 100% 的红光被反射,而 100% 的蓝光和绿光被吸收。

金属性术语只是一个粗略的近似值,用于在明确的艺术家指定的反射颜色与正确/计算出的 F0 之间进行插值,后者适用于电介质。 >


我不相信您发布的链接上的公式是完全正确的。能量守恒定律意味着漫反射和镜面反射能量之和为1.0。因此,kd 应该是:

kd = (1 - ks)

这样想:任何未被材料吸收的光都应该被反射。

此外,(1 - material.metalness) 在计算镜面反射颜色时已经考虑在内:

vec3 specularColor = mix(vec3(0.04), material.albedo, material.metalness);

还有漫反射颜色:

vec3 albedo = mix(material.albedo, vec3(0), material.metalness);

纯导体基本上只有镜面反射,没有扩散。