因此路径跟踪的维基百科页面(http://en.wikipedia.org/wiki/Path_tracing)包含一个简单的算法实现,下面有以下解释:
“然后必须对所有这些样本进行平均以获得输出颜色。请注意,这种始终对正常半球中的随机光线进行采样的方法仅适用于完美漫反射的表面。对于其他材料,通常必须使用重要性采样,即根据BRDF的分布概率性地选择新的光线。例如,完美的镜面(镜面)材料不适用于上述方法,因为新光线是正确的反射光线的概率 - 这是唯一的光线通过任何辐射将被反射 - 是零。在这些情况下,必须将反射率除以采样方案的概率密度函数,按照蒙特卡罗积分(在上面的天真案例中,没有特定的采样)方案,所以PDF原来是1)。“
我理解困难的部分是粗体部分。我熟悉PDF,但我不太确定它们是如何适应这里的。如果我们坚持镜像示例,那么我们将划分的PDF值是多少?为什么?如果我使用任意BRDF值(例如Phong反射模型或Cook-Torrance反射模型等),我将如何找到要除以的PDF值?最后,为什么我们除以PDF而不是乘法?如果我们分开,难道我们不会对概率较低的方向给予更大的权重吗?
答案 0 :(得分:3)
假设我们只有没有颜色的材质(灰度)。然后,他们在每个点的BDRF可以表示为单值函数
float BDRF(phi_in, theta_in, phi_out, theta_out, pointWhereObjWasHit);
此处,phi
和theta
是所考虑的两条射线的方位角和天顶角。对于纯朗伯反射,此函数将如下所示:
float lambertBRDF(phi_in, theta_in, phi_out, theta_out, pointWhereObjWasHit)
{
return albedo*1/pi*cos(theta_out);
}
albedo
的范围从0到1 - 这可以测量多少入射光被重新发射。因子1/pi
确保BRDF对所有传出向量的积分不超过1.使用维基百科文章(http://en.wikipedia.org/wiki/Path_tracing)的朴素方法,可以使用此BRDF如下:
Color TracePath(Ray r, depth) {
/* .... */
Ray newRay;
newRay.origin = r.pointWhereObjWasHit;
newRay.direction = RandomUnitVectorInHemisphereOf(normal(r.pointWhereObjWasHit));
Color reflected = TracePath(newRay, depth + 1);
return emittance + reflected*lambertBDRF(r.phi,r.theta,newRay.phi,newRay.theta,r.pointWhereObjWasHit);
}
正如文章和罗斯所提到的,这种随机抽样是不幸的,因为它跟踪传入的方向(newRay),从这些方向反射的小光与具有大量光线的方向具有相同的概率。相反,应该优先选择向观察者反射大量光的方向,以在每个方向上对最终颜色的每次贡献具有相等的采样率。为此,需要一种从概率分布生成随机射线的方法。假设存在一个能够做到这一点的功能;此函数将所需的PDF(理想情况下应该等于BDRF)和传入光线作为输入:
vector RandomVectorWithPDF(function PDF(p_i,t_i,p_o,t_o,point x), Ray incoming)
{
// this function is responsible to create random Rays emanating from x
// with the probability distribution PDF. Depending on the complexity of PDF,
// this might somewhat involved. It is possible, however, to do it for Lambertian
// reflection (how exactly is math, not programming):
vector randomVector;
if(PDF==lambertBDRF)
{
float phi = uniformRandomNumber(0,2*pi);
float rho = acos(sqrt(uniformRandomNumber(0,1)));
float theta = pi/2-rho;
randomVector = getVectorFromAzimuthZenithAndNormal(phi,zenith,normal(incoming.whereObjectWasHit));
}
else // deal with other PDFs
return randomVector;
}
TracePath
例程中的代码将如下所示:
newRay.direction = RandomVectorWithPDF(lambertBDRF,r);
Color reflected = TracePath(newRay, depth + 1);
return emittance + reflected;
由于在选择样本时首选亮方向,因此您不必将BDRF作为缩放因子应用于reflected
。但是,如果PDF和BDRF由于某种原因不同,那么只要PDF> BDRF(如果你从相应的方向选择了很多)就必须缩小输出,并在你选择的时候增强它。
在代码中:
newRay.direction = RandomVectorWithPDF(PDF,r);
Color reflected = TracePath(newRay, depth + 1);
return emittance + reflected*BDRF(...)/PDF(...);
但是,如果BDRF/PDF
等于1,则输出效果最佳。
问题仍然是为什么不能总是选择与BDRF完全相同的完美PDF?首先,一些随机分布比其他分布更难计算。例如,如果albedo
参数存在轻微变化,则对于非天真采样而言,算法仍然会比统一采样更好,但是需要更正项BDRF/PDF
。略有变化。有时甚至根本不可能做到这一点。想象一下有红色绿色和蓝色的不同反射行为的彩色物体 - 你可以在三个通道中渲染,每种颜色一个,或者使用平均PDF,它适合所有颜色成分,但不是完美的。
如何实施像Phong着色这样的东西?为简单起见,我仍然假设只有一个颜色成分,并且漫反射与镜面反射的比率为60%/ 40%(环境光的概念在路径追踪中没有意义)。然后我的代码看起来像这样:
if(uniformRandomNumber(0,1)<0.6) //diffuse reflection
{
newRay.direction=RandomVectorWithPDF(lambertBDRF,r);
reflected = TracePath(newRay,depth+1)/0.6;
}
else //specular reflection
{
newRay.direction=RandomVectorWithPDF(specularPDF,r);
reflected = TracePath(newRay,depth+1)*specularBDRF/specularPDF/0.4;
}
return emittance + reflected;
此处specularPDF
是一个在反射光线周围有一个窄峰的分布(theta_in = theta_out,phi_in = phi_out + pi),为此可以创建一个创建随机向量的方法,specularBDRF
返回来自Phong模型的镜面反射强度(http://en.wikipedia.org/wiki/Phong_reflection_model)。
请注意PDF的修改方式分别为0.6和0.4。
答案 1 :(得分:1)
我绝不是光线追踪方面的专家,但这似乎是经典的蒙特卡罗:
你有很多可能的光线,你随机选择一个,然后在很多试验中取平均值。 你用来选择其中一条射线的分布是均匀的(它们都是一样的) 所以你不必做任何聪明的重新规范化。
然而,也许有很多可能的光线可供选择,但只有少数可能会产生有用的结果。因此我们偏向于以更高的概率选择那些“有用”的可能性,然后重新规范化(我们不选择光线均匀,所以我们不能只取平均值)。这是 重要性抽样。
镜像示例似乎如下:只有一条可能的光线会产生有用的结果。 如果我们随机选择一条射线,那么我们击中有用射线的概率为零:这是一个属性 条件概率对连续空间的影响(它实际上不是连续的,它是隐含的离散化的 通过你的计算机,所以它并不完全正确...):当有无限多的东西时,击中某些东西的概率必须为零。
因此,我们通过概率为零的标准条件概率定义重新规范化 当我们考虑概率为零的事件时就会中断,这就是问题的来源。