7

Cook-Torrance BRDF 和 Lambert BRDF 上有很多材料。Unreal Engine 4 中的 Real ShadingMoving Frostbite to BPR深入解释了如何实现它们以进行实时渲染。

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

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

  • 反照率 (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.

kd之后通过以下方式计算:

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

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

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

4

1 回答 1

1

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

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

对于电介质,这很简单,镜面反射颜色始终为纯白色(无着色),由菲涅耳和基本反射率(也称为F0定义:这个标量仅表示在观察物体时反射的光的百分比表面直上。

0.04 ”值对应于4%的基础反射率,您可以通过将菲涅耳反射率公式中的 n1 替换为 1.5 的 IOR以及n2替换为空气的 IOR(近似为1.0)来计算(从维基百科中删除)

在此处输入图像描述

给定材料的 IOR 在 Internet 上很容易找到,而且大多数电介质无论如何都在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);

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

于 2021-04-11T20:45:30.573 回答