首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >重要抽样GGX NDF -萤火虫和光明的最终结果

重要抽样GGX NDF -萤火虫和光明的最终结果
EN

Computer Graphics用户
提问于 2020-10-06 09:54:39
回答 1查看 383关注 0票数 0

https://schuttejoe.github.io/post/ggximportancesamplingpart1/ -我在实现这个方法时遇到了问题。以前有人问过这个问题( 无法理解GGX抽样的重要性 ),但它并没有完全回答我的问题。

上面的博客文章描述了基于重要性抽样NDF的重要性抽样方法。让我们从库克-托兰斯BRDF开始:

f_r = \frac{F(w_i, w_m) ~ G_2(w_i, w_o, w_m) ~ D(w_m)}{4 ~ |w_i \cdot w_g| ~ |w_o \cdot w_g|}

求正态分布函数PDF后的应用

|w_i \cdot w_g|

从呈现方程+找到的PDF的术语,我们有最后的方程式:

\frac{F(w_i, w_m) ~ G_2(w_i, w_o, w_m) ~ |w_o \cdot w_m|}{|w_o \cdot w_g| ~ |w_m \cdot w_g|}

我只是为了完成而加入最后的方程式。所有的转换都是相当长的,最好查看我发送的博客文章。在文章的末尾,有代码应该是正确工作的。然而,在我的情况下,它并没有给出正确的结果,我的怀疑是我用错误的方式填补了空白:

我在这里使用相关的多抖动抽样:

代码语言:javascript
复制
float SmithGGXMaskingShadowing(float3 n, float3 l, float3 v, float a2)
{
    float dotNL = saturate(dot(n, l));
    float dotNV = saturate(dot(n, v));

    float denomA = dotNV * sqrt(a2 + (1.0f - a2) * dotNL * dotNL);
    float denomB = dotNL * sqrt(a2 + (1.0f - a2) * dotNV * dotNV);

    return 2.0f * dotNL * dotNV / (denomA + denomB);
}

float a2 = roughness * roughness;
float theta = acos(sqrt((1.0f - brdfSample.x) / ((a2 - 1.0f) * brdfSample.x + 1.0f)));
float phi = 2.0f * PI * brdfSample.y;

float3 normalTS = float3(0, 1, 0);

float3 wo = -incomingRayDirTS;
float3 wm = float3(sin(theta) * cos(phi), cos(theta), sin(theta) * sin(phi));
float3 wi = 2.0f * dot(wo, wm) * wm - wo;

float3 F = Specular_F_Schlick(specularAlbedo.rgb, saturate(dot(wi, wm)));
float G = SmithGGXMaskingShadowing(wm, wi, wo, a2);
float weight = abs(dot(wo, wm) / (dot(normalTS, wo) * dot(normalTS, wm)));

rayDirWS = normalize(mul(wi, tangentToWorld));

if (dot(normalTS, wi) > 0.0f && dot(wi, wm) > 0.0f)
    throughput = F * G * weight;
else
    throughput = 0.0f;

我主要关心的是-我是否正确地在切线空间(w_g)中使用法线?舒特·乔在评论中提到:

// --确保我们的样本位于上半球/-,因为我们处于y向上坐标// -系统BsdfNDot(wi)的切线空间,因此只返回wi.y。

这就是为什么我决定使用w_g (或normalTS)作为float3(0、1、0)。

下面是路径长度等于4的1024个样本的查找方式:

相比较而言,这里是基于可见法线描述的方法- https://schuttejoe.github.io/post/ggximportancesamplingpart2/;对于1024个样本,路径长度4,结果要好得多。然而,根据文章作者提供的数据,不应该有太大的差别:

编辑:@B_old是对的,我混合了TS和WS。我提出的校正结果,上面的图像稍好,但仍然有很高的方差和一些亮点。

EN

回答 1

Computer Graphics用户

回答已采纳

发布于 2020-10-15 12:08:28

我已经对我的代码做了一些修改,所以让我们从我遇到问题的基本图像开始--我们将在开始时将其描述为一个问题:

在将代码的一部分从以下位置更改后:

代码语言:javascript
复制
float weight = abs(dot(wo, wm) / (dot(normalTS, wo) * dot(normalTS, wm)));
if (dot(normalTS, wi) > 0.0f && dot(wi, wm) > 0.0f)

为此(即将部分计算移至世界-空间):

代码语言:javascript
复制
float weight = abs(dot(wo, wm) / (dot(triangleNormal, incomingRayDirWS) * dot(normalTS, wm)));
if (dot(triangleNormal, rayDirWS) > 0.0f && dot(wi, wm) > 0.0f)

我得到了更好的结果。以下是具有不同设置的一系列图像:

1024 spp,4盎司

5000 spp,4盎司

5000 spp,1跳

请注意,4反弹版本是有更多的萤火虫和噪音。长的镜面路径可能是引入噪声的一个原因。另外,5000 spp比1000 spp更暗。原因是这条路径可能没有任何变化,因此平均颜色越来越暗。你可以在主帖子的最后一行看到它。我将把它放在下面供参考:

代码语言:javascript
复制
if (dot(triangleNormal, rayDirWS) > 0.0f && dot(wi, wm) > 0.0f)
    throughput *= F * G * weight;
else
    throughput *= 0;

最后一件事。下面是用更好的方法( https://schuttejoe.github.io/post/ggximportancesamplingpart2/ )生成的图像。1024 spp,4次反弹:

总之,我摆脱了奇怪的噪音和人工制品。算法更接近于更好的方法,我认为它可以看作是固定的。

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

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

复制
相关文章

相似问题

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