首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >采光与取样BRDF:强度的差异

采光与取样BRDF:强度的差异
EN

Computer Graphics用户
提问于 2020-01-29 12:58:34
回答 1查看 476关注 0票数 3

(可能重复)

我正在尝试实现多重重要性抽样,正如在PBRT簿中所描述的(还没有反弹,我想让管理信息系统首先工作)。

我的问题是,尽管BRDF采样看起来还不错,但是光采样要暗得多(但是根据书中的图片,它们的强度应该是一样的)。

我上传了(更新的) 可编译代码 (VS 2015)。相关部位可在multipleimportance.frag (SampleLightsExplicit)和pbr_common.head (ConeSampleSphere)中找到。

(请注意,我还没有应用MIS权重)

代码语言:javascript
复制
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格式是:

代码语言:javascript
复制
PDF = D(h) * dot(n, h)

而一些实现(包括UE4)错误地将其写成

代码语言:javascript
复制
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部分,看看为什么这些亮点会消失。

EN

回答 1

Computer Graphics用户

回答已采纳

发布于 2020-02-03 15:22:22

开枪打我..。在我上面发布的补丁之后,我开始调试三菱,看看它是否大规模地做了不同的事情。当然没有;我的代码是完全正确的,模糊是由于这个宏def:

代码语言:javascript
复制
#define EPSILON   1e-5

这是用于除法,以避免除以零。不幸的是,在计算过程中,它累积到了一个很大的值。将其更改为1e-9可以修复所有问题:

对于后代,我保留源代码(只需记住更改此值)。

更新:

我在计算中发现了另一个错误,但在这个场景中并不明显。基于微表面的BRDF通常根据微面正态分布函数(D(h,a),在这种情况下是GGX)进行采样。

但是,不要忘记,你也有一个遮蔽函数(G(l,v,a)),它必须根据所选的微面分布进行评估。这意味着我不能只是混搭。GGX抽样和Smith-Schlick评估;我必须使用Smith-GGX解决方案:

代码语言:javascript
复制
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方法,如:

代码语言:javascript
复制
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);

有关派生,请参见这篇文章

票数 2
EN
页面原文内容由Computer Graphics提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://computergraphics.stackexchange.com/questions/9525

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档