(可能重复)
我正在尝试实现多重重要性抽样,正如在PBRT簿中所描述的(还没有反弹,我想让管理信息系统首先工作)。
我的问题是,尽管BRDF采样看起来还不错,但是光采样要暗得多(但是根据书中的图片,它们的强度应该是一样的)。


我上传了(更新的) 可编译代码 (VS 2015)。相关部位可在multipleimportance.frag (SampleLightsExplicit)和pbr_common.head (ConeSampleSphere)中找到。
(请注意,我还没有应用MIS权重)
for (int k = 0; k < numLights; ++k) {
SceneObject light = objects.data[k];
center = vec3(light.toworld[3].xyz);
radius = light.toworld[0][0];
// importance sample light (xyz = direction, w = PDF)
sample1 = ConeSampleSphere(p, center, radius, pixel, seed + float(k));
// cast shadow ray
vis = Visibility(p, sample1.xyz, k);
ndotl = vis * max(0.0, dot(sample1.xyz, n));
// evaluate BRDF
fd = vec3(0.0); //obj.color.rgb * ONE_OVER_PI;
fs = CookTorrance_General(sample1.xyz, v, n, vec3(0.04), roughness);
sum += (light.color.rgb * (fd + fs) * ndotl) / sample1.w;
}我的问题是为什么光取样看起来这么模糊?我有误解什么吗?
看一看代码,我注意到一些不一致之处,这可能源于SIGGRAPH的一个旧的课程注释中的一个错误(不能区分哪一个)。
GGX发行版的PDF格式是:
PDF = D(h) * dot(n, h)而一些实现(包括UE4)错误地将其写成
PDF = (D(h) * dot(n, h)) / (4 * dot(v, h))这在本质上意味着它们在这个变量中包含了Cook-Torrance分母(ndotl抵消了)。用正确的PDF除法可以消除库克-托朗斯模型中的D,我忘记了这一点,而1/ (4 *点(v,h))项进入了Vis_Schlick函数。
因此,关于强度,第二张图片是“正确的”一张。昏暗仍然是一个问题。将菲涅耳F0改为0.11 (在书中应该是这样),并应用管理信息系统权重,这幅图看起来更有希望,除了最上面的板,它几乎应该明确地反射光源:

所以现在几乎没问题了。我会更深入地研究MIS部分,看看为什么这些亮点会消失。
发布于 2020-02-03 15:22:22
开枪打我..。在我上面发布的补丁之后,我开始调试三菱,看看它是否大规模地做了不同的事情。当然没有;我的代码是完全正确的,模糊是由于这个宏def:
#define EPSILON 1e-5这是用于除法,以避免除以零。不幸的是,在计算过程中,它累积到了一个很大的值。将其更改为1e-9可以修复所有问题:

对于后代,我保留源代码(只需记住更改此值)。
我在计算中发现了另一个错误,但在这个场景中并不明显。基于微表面的BRDF通常根据微面正态分布函数(D(h,a),在这种情况下是GGX)进行采样。
但是,不要忘记,你也有一个遮蔽函数(G(l,v,a)),它必须根据所选的微面分布进行评估。这意味着我不能只是混搭。GGX抽样和Smith-Schlick评估;我必须使用Smith-GGX解决方案:
float G_Smith_GGX(float ndotl, float ndotv, float roughness)
{
float a = roughness * roughness;
float a2 = a * a;
float lambda_l = sqrt(a2 + (1.0 - a2) * ndotl * ndotl);
float lambda_v = sqrt(a2 + (1.0 - a2) * ndotv * ndotv);
return (2.0 * ndotl * ndotv) / (ndotv * lambda_l + ndotl * lambda_v);
}它解释了UE4方法,如:
vec3 F = F_Schlick(F0, ldoth);
float G = G_Smith_GGX(ndotl, ndotv, roughness);
// PDF = (D(h) * dot(n, h)) / (4 * dot(v, h))
return (F * G * vdoth) / (ndotv * ndoth + EPSILON);有关派生,请参见这篇文章。
https://computergraphics.stackexchange.com/questions/9525
复制相似问题