https://schuttejoe.github.io/post/ggximportancesamplingpart1/ -我在实现这个方法时遇到了问题。以前有人问过这个问题( 无法理解GGX抽样的重要性 ),但它并没有完全回答我的问题。
上面的博客文章描述了基于重要性抽样NDF的重要性抽样方法。让我们从库克-托兰斯BRDF开始:
求正态分布函数PDF后的应用
从呈现方程+找到的PDF的术语,我们有最后的方程式:
我只是为了完成而加入最后的方程式。所有的转换都是相当长的,最好查看我发送的博客文章。在文章的末尾,有代码应该是正确工作的。然而,在我的情况下,它并没有给出正确的结果,我的怀疑是我用错误的方式填补了空白:
我在这里使用相关的多抖动抽样:
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。我提出的校正结果,上面的图像稍好,但仍然有很高的方差和一些亮点。
发布于 2020-10-15 12:08:28
我已经对我的代码做了一些修改,所以让我们从我遇到问题的基本图像开始--我们将在开始时将其描述为一个问题:

在将代码的一部分从以下位置更改后:
float weight = abs(dot(wo, wm) / (dot(normalTS, wo) * dot(normalTS, wm)));
if (dot(normalTS, wi) > 0.0f && dot(wi, wm) > 0.0f)为此(即将部分计算移至世界-空间):
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更暗。原因是这条路径可能没有任何变化,因此平均颜色越来越暗。你可以在主帖子的最后一行看到它。我将把它放在下面供参考:
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次反弹:

总之,我摆脱了奇怪的噪音和人工制品。算法更接近于更好的方法,我认为它可以看作是固定的。
https://computergraphics.stackexchange.com/questions/10292
复制相似问题