在PBRT中,BSDF表示为一个BxDF瓣数组。每个瓣都设置一个位标志,表示它是哪种类型的瓣。(镜面、漫射、反射、透射等)我正在研究PBRT是如何为输入方向采样BSDF的,wi。
按照标准的Monte抽样,我期望代码能够随机地采样一个适当的瓣,然后设置pdf = pdf_{picked}/n,其中n是适当类型的叶数。然而,这不是PBRT所做的。我的问题是为什么?为了进一步发展,这是PBRT函数:
Spectrum BSDF::Sample_f(const Vector3f &woWorld, Vector3f *wiWorld,
const Point2f &u, Float *pdf, BxDFType type,
BxDFType *sampledType) const {
// Choose which _BxDF_ to sample
int matchingComps = NumComponents(type);
if (matchingComps == 0) {
*pdf = 0;
if (sampledType)
*sampledType = BxDFType(0);
return Spectrum(0);
}
int comp = std::min((int)std::floor(u[0] * matchingComps), matchingComps - 1);
// Get _BxDF_ pointer for chosen component
BxDF *bxdf = nullptr;
int count = comp;
for (int i = 0; i < nBxDFs; ++i)
if (bxdfs[i]->MatchesFlags(type) && count-- == 0) {
bxdf = bxdfs[i];
break;
}
// Remap _BxDF_ sample _u_ to [0,1)^2#qcStackCode#
Point2f uRemapped(std::min(u[0] * matchingComps - comp, OneMinusEpsilon),
u[1]);
// Sample chosen _BxDF_
Vector3f wi, wo = WorldToLocal(woWorld);
if (wo.z == 0)
return 0.;
*pdf = 0;
if (sampledType) *sampledType = bxdf->type;
Spectrum f = bxdf->Sample_f(wo, &wi, uRemapped, pdf, sampledType);
if (*pdf == 0) {
if (sampledType) *sampledType = BxDFType(0);
return 0;
}
*wiWorld = LocalToWorld(wi);
// Compute overall PDF with all matching _BxDF_s
if (!(bxdf->type & BSDF_SPECULAR) && matchingComps > 1)
for (int i = 0; i < nBxDFs; ++i)
if (bxdfs[i] != bxdf && bxdfs[i]->MatchesFlags(type))
*pdf += bxdfs[i]->Pdf(wo, wi);
if (matchingComps > 1)
*pdf /= matchingComps;
// Compute value of BSDF for sampled direction
if (!(bxdf->type & BSDF_SPECULAR)) {
bool reflect = Dot(*wiWorld, ng) * Dot(woWorld, ng) > 0;
f = 0.;
for (int i = 0; i < nBxDFs; ++i)
if (bxdfs[i]->MatchesFlags(type) &&
((reflect && (bxdfs[i]->type & BSDF_REFLECTION)) ||
(!reflect && (bxdfs[i]->type & BSDF_TRANSMISSION))))
f += bxdfs[i]->f(wo, wi);
}
return f;
}在伪代码中,它看起来正在执行以下操作:
// Get the number of lobes that match the ones we asked for
numMatchingLobes = NumComponents(type);
// Early out check
if (numMatchingLobes == 0):
return
// Randomly pick one of the matching lobes
pickedBxDF = Rand()
// Transform wo from world space to local space
// Then sample the chosen BxDF to get f, pdf, and wi
f, pdf, wi = pickedBxDF.sample_f(woWorld.ToLocal())
// Early out check
if (pdf == 0):
return
// Transform wi to world space
wiWorld = wi.ToWorld()
// Add all of the pdfs of the matching lobes if the picked BxDF wasn't specular
if pickedBxDF.type not Specular && numMatchingLobes > 1:
for BxDF in matchingLobes:
pdf += BxDF.pdf(wi, wo)
// Divide the resulting pdf by the number of matching lobes
pdf /= numMatchingLobes;
// Calculate the combined f if the picked BxDF isn't specular
if pickedBxDF.type not Specular:
// Reset f to zero
f = 0
// Add each BxDF's f, iff it matches reflection / transmission
reflect = wo and wi on same hemisphere as geoNormal
for BxDF in matchingLobes:
// Add the
if reflect and BxDF.type == Reflection:
f += BxDF.f(wo, wi)
elif !reflect and BxDF.type == Transmission:
f += BxDF.f(wo, wi)我不理解的部分是,为什么它会在已经计算出来的pdf的基础上添加所有匹配的叶的pdf。这似乎会使摘取的叶的pdf数加倍。
例如,如果有两个匹配的叶,称为A和B。
我们用A计算f,pdf和wi,然后用一个for循环,我们把A和B的pdf相加,除以2。
这似乎不对。PBRT代码错误吗?它是否应该重置pdf,类似于下面的f计算代码?
发布于 2019-11-13 21:20:43
求和不包括被挑选来取样的BxDF。再看看这一行:
if (bxdfs[i] != bxdf && bxdfs[i]->MatchesFlags(type))在这里,bxdf是前面取样的那个,所以当它迭代到那个样本时,它会跳过它。
https://computergraphics.stackexchange.com/questions/9343
复制相似问题