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

Hen*_*nkk 6 opengl directx graphics rendering pbr

Cook-Torrance BRDF以及Lambert BRDF上有很多材料.虚幻引擎4中的真实着色将霜冻运动转换为BPR,可以深入解释如何将它们实现为实时渲染.

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

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

  • 反照率(RGB)
  • 粗糙度(浮法)
  • 金属(浮法)

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

Mamoset说明了这一点

当使用metalness地图,绝缘表面 - 在metalness地图设定为0.0(黑色)像素 - 被分配一个固定的反射率值(线性:0.04的sRGB:0.22),并使用反射率的地图为漫反射值.对于金属表面 - 金属度贴图中设置为1.0(白色)的像素 - 镜面反射颜色和强度取自反照率贴图,漫反射器中的漫反射值设置为0(黑色).

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

vec3 specularColor = mix(vec3(0.04), material.albedo, material.metalness);
Run Code Online (Sandbox Code Playgroud)

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

vec3 L_specular = specularIBL(specularColor, material.roughness, normal, view);
Run Code Online (Sandbox Code Playgroud)

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

如何工作在上面的相同引用中描述:

vec3 albedo = mix(material.albedo, vec3(0), material.metalness);
Run Code Online (Sandbox Code Playgroud)

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

vec3 L_diffuse = f_lambert(albedo) * E;
Run Code Online (Sandbox Code Playgroud)

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

vec3 L = kd * L_diffuse + ks * L_specular;
Run Code Online (Sandbox Code Playgroud)

我的问题是如何计算kdks

  1. Codinglabs建议将菲涅尔函数整合到半球上进行计算ks.

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

vec3 kd = (1 - ks) * (1 - material.metalness);
Run Code Online (Sandbox Code Playgroud)

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

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

Alt*_*r93 2

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

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

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

0.04 ”值对应于4% 的基本反射率,您可以通过用1.5的 IOR 代替菲涅耳反射率公式中的 n1 和用空气的 IOR(近似于1.0 代替n2 来计算 出该值(摘自维基百科)

在此输入图像描述

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


对于导体,公式并不那么简单,因此您会发现实现的常用方法(由 Codinglabs、UE4 和其他引擎)是明确指定金属的色调/反射率/镜面颜色,因为它更具艺术性-友好的。例如,纯红色意味着 100% 的红光被反射,而 100% 的蓝光和绿光被吸收。

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


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

kd = (1 - ks)
Run Code Online (Sandbox Code Playgroud)

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

此外,在计算镜面反射颜色时已经考虑了(1 - 材质.金属度) :

vec3 specularColor = mix(vec3(0.04), material.albedo, material.metalness);
Run Code Online (Sandbox Code Playgroud)

对于漫反射颜色也:

vec3 albedo = mix(material.albedo, vec3(0), material.metalness);
Run Code Online (Sandbox Code Playgroud)

纯导体本质上只是镜面反射而没有漫射。