【问题标题】:Why won't my raytracer recreate the "mount" scene?为什么我的光线追踪器不能重新创建“安装”场景?
【发布时间】:2011-03-29 09:55:28
【问题描述】:

我正在尝试从Eric Haines' Standard Procedural Database (SPD) 渲染“mount”场景,但折射部分只是不想合作。我已经尝试了所有我能想到的来修复它。

这是我的渲染图(使用瓦特公式):


(来源:philosoraptor.co.za)

这是我使用“正常”公式的渲染:


(来源:philosoraptor.co.za)

这是正确的渲染:


(来源:philosoraptor.co.za)

如您所见,只有几个错误,主要是在球体的两极附近。这让我觉得应该归咎于折射或某些精度误差。

请注意,场景中实际上有 4 个球体,它们的 NFF 定义 (s x_coord y_coord z_coord radius) 是:

s -0.8 0.8 1.20821 0.17
s -0.661196 0.661196 0.930598 0.17
s -0.749194 0.98961 0.930598 0.17
s -0.98961 0.749194 0.930598 0.17

也就是说,在前景中更明显的三个后面还有第四个球体。从这三个球体之间留下的空隙中可以看出。

这是第四个球体的图片:


(来源:philosoraptor.co.za)

这是单独的第一个球体的图片:


(来源:philosoraptor.co.za)

您会注意到我的版本和正确版本中存在的许多奇怪之处都丢失了。我们可以得出结论,这些影响是球体之间相互作用的结果,问题是哪些相互作用?

我做错了什么?以下是我已经考虑过的一些潜在错误:

  • 折射矢量公式。

据我所知,这是正确的。这是几个网站使用的相同公式,我亲自验证了推导。这是我的计算方法:

double sinI2 = eta * eta * (1.0f - cosI * cosI);

Vector transmit = (v * eta) + (n * (eta * cosI - sqrt(1.0f - sinI2)));

transmit = transmit.normalise();

我在 Alan Watt 的第三版 3D Computer Graphics 中找到了一个替代公式。它更接近正确的图像:

double etaSq = eta * eta;
double sinI2 = etaSq * (1.0f - cosI * cosI);
Vector transmit = (v * eta) + (n * (eta * cosI - (sqrt(1.0f - sinI2) / etaSq)));
transmit = transmit.normalise();

唯一的区别是我最后除以 eta^2。

  • 全内反射。

我对此进行了测试,在我的其余交集代码之前使用以下条件:

if (sinI2 <= 1)
  • eta 的计算。

我使用类似堆栈的方法来解决这个问题:

        /* Entering object. */
        if (r.normal.dot(r.dir) < 0)
        {
           double eta1 = r.iorStack.back();
           double eta2 = m.ior;
           eta = eta1 / eta2;

           r.iorStack.push_back(eta2);
        }
        /* Exiting object. */
        else
        {
           double eta1 = r.iorStack.back();
           r.iorStack.pop_back();
           double eta2 = r.iorStack.back();

           eta = eta1 / eta2;
        }

如您所见,这会将包含此射线的先前对象存储在堆栈中。退出代码时,将当前 IOR 从堆栈中弹出并使用它以及它下面的 IOR 来计算 eta。据我所知,这是最正确的方法。

这适用于嵌套传输对象。但是,对于相交传输对象,它会崩溃。这里的问题是您需要为交叉点独立定义 IOR,而 NFF 文件格式不这样做。那么,“正确”的行动方案是什么就不清楚了。

  • 移动新光线的原点。

新光线的原点必须沿着传输路径稍微移动,这样它就不会与前一个光线相交。

p = r.intersection + transmit * 0.0001f;

p += transmit * 0.01f;

我尝试让这个值更小 (0.001f) 和 (0.0001f),但这会使球体看起来是实心的。我猜这些值不会将光线从前一个交点移开足够远。

编辑:这里的问题是反射代码在做同样的事情。因此,当一个物体既具有反射性又具有折射性时,光线的来源就会完全出现在错误的位置。

  • 光线反弹量。

我人为地将光线反弹的数量限制为 4。我测试了将此限制提高到 10,但这并没有解决问题。

  • 法线。

我很确定我正确计算了球体的法线。我取交点,减去球心,除以半径。

【问题讨论】:

  • 我不知道它是否有帮助,因为我做光线追踪已经有一年半了。是否存在射线应该相交两次以上的情况?如果没有,那么您也许可以特殊情况并避免处理重铸偏移量。
  • 我想我明白你的意思:当我用射线相交球体时,我应该检查 t0 == 0。如果是,那么我应该使用 t1。那我根本不用移动交点?除非我理解错了。 “相交两次以上”和“重铸偏移”是什么意思?
  • 图片不可用 :'(

标签: graphics raytracing


【解决方案1】:

只是基于进行图像差异的猜测(并且没有阅读您的其余问题)。在我看来,这个问题是球体背面的折射。你可能是:

  • 倒着做:例如反转(或不反转)折射率。
  • 完全想念它?

检查这一点的一种方法是通过一个几乎正对着摄像机的立方体观察底座。如果折射是正确的,图片应该稍微偏移,否则保持不变。如果不正确,则图片会显得有些倾斜。

【讨论】:

  • 我测试过,我没有错过球体的背面。我有处理背面和插入打印的代码,其中有数十行输出。我也确定我正在正确计算 eta,我使用的代码在我的问题中。自发布以来,我已经稍微更新了这段代码以使用一堆 IOR 值。我将尝试使用多边形查看山,不幸的是我没有实现立方体。或许我可以试试两个平行的平面?
  • @fluffels 我认为 BCS 有一个很好的观点......查看第一张图像和正确的图像,正确的图像显示山脉由于折射的影响而凸出,而您的第一张图像显示了它们起皱。我相信您可以看到这一点,但是您的评论“只有几个错误,主要是在两极附近”似乎忽略了这种差异。看起来确实有些东西颠倒了,但我不知道是什么。 (另外我不明白第四个球体......它应该在其他人的前面还是后面?)
  • @fluffels,两个平行的平原可以工作:用它们渲染和没有它们,并检查图像是否略微移动。还要确保它们彼此背离,而不是指向同一个方向。我查看了您发布的 eta 计算,它似乎是不对称的。我希望进入和退出的代码几乎相同,可能只有两个术语从一个交换到另一个。
  • @LarsH 我添加了更多图片,希望能解释场景的性质。
  • @LarsH 我明白你所说的失真的意思。但我不知道该怎么办。我尝试过翻转法线、eta 值等所有内容。
【解决方案2】:

所以经过一年多的时间,我终于弄清楚这里发生了什么。头脑清醒等等。我完全偏离了公式。我现在改用 Heckbert 的公式,我确信它是正确的,因为我自己使用几何和离散数学证明了它。

这是正确的向量计算:

double c1 = v.dot(n) * -1;
double c1Sq = pow(c1, 2);

/* Heckbert's formula requires eta to be eta2 / eta1, so I have to flip it here. */
eta = 1 / eta;
double etaSq = pow(eta, 2);

if (etaSq + c1Sq >= 1)
{
   Vector transmit = (v / eta) + (n / eta) * (c1 - sqrt(etaSq - 1 + c1Sq));
   transmit = transmit.normalise();
...
}
else
{
   /* Total internal reflection. */
}

在上面的代码中,eta 是 eta1(光线来自的表面的 IOR)超过 eta2(目标表面的 IOR),v 是入射光线,n 是法线。

还有一个问题,使问题更加混乱。退出对象时我必须翻转 normal(这很明显 - 我错过了它,因为其他错误掩盖了它)。

最后,我的视线算法(确定一个表面是否被点光源照亮)没有正确地穿过透明表面。

所以现在我的图像排列正确:)

【讨论】:

  • 我在这方面遇到了可笑的困难。我不知道到底出了什么问题 - 我从 我的 之前的一个光线追踪器中逐行复制了折射代码,但我的球体中出现了全内反射,导致出现黑色轮廓。在您的帖子中使用 Heckbert 公式给出的结果与 Snell 算法完全相同,所以这不是问题所在,至少对我而言。我也颠倒了正常情况,画了十五张图,描绘了每一种可能的情况——sigh。您必须在某个地方修复了其他东西。我想我会在 2015 年修复它,哈哈。
  • 您发帖提问了吗?另外,您确定您计算的 eta 正确吗?
  • 不,还没有发布问题。我想我计算 eta 是正确的,基本上决定光线是在球体内还是在球体外(通过将其点积与法线进行比较)并正确选择 n1 和 n2,以及如果光线在球体内则翻转法线。我认为这是因为我试图将它硬塞到我的 BRDF 课程中——我真的应该把它改成 BTDF,因为它可以传输。但它以前工作过......所以......
  • 然后你翻转正常的之后检查 eta?另外,您确实在相交后移动了射线吗?不这样做也会导致您的问题。
  • 可能是。 Python有许多陷阱w.r.t。浮点值。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-08-18
  • 1970-01-01
  • 2021-07-24
  • 2013-12-04
  • 2010-10-21
相关资源
最近更新 更多