4

我试图在不对环面进行三角剖分的情况下,仅通过与射线和环面解析方程相交来对环面进行射线追踪。我使用以下代码做到了这一点:

void circularTorusIntersectFunc(const CircularTorus* circularToruses, RTCRay& ray, size_t item)
{
  const CircularTorus& torus = circularToruses[item];

  Vec3fa O = ray.org /*- sphere.p*/;
  Vec3fa Dir = ray.dir;
  O.w = 1.0f;
  Dir.w = 0.0f;
  O = torus.inv_transform.mult(O);
  Dir = torus.inv_transform.mult(Dir);

  // r1: cross section of torus
  // r2: the ring's radius
  //  _____                     ____
  // / r1  \------->r2<--------/    \
  // \_____/                   \____/

  float r2 = sqr(torus.r1);
  float R2 = sqr(torus.r2);

  double a4 = sqr(dot(Dir, Dir));
  double a3 = 4 * dot(Dir, Dir) * dot(O, Dir);
  double a2 = 4 * sqr(dot(O, Dir)) + 2 * dot(Dir, Dir) * (dot(O, O) - r2 - R2) + 4 * R2 * sqr(Dir.z);
  double a1 = 4 * dot(O, Dir) * (dot(O, O) - r2 - R2) + 8 * R2 * O.z * Dir.z;
  double a0 = sqr(dot(O, O) - r2 - R2) + 4 * R2 * sqr(O.z) - 4 * R2 * r2;

  a3 /= a4; a2 /= a4; a1 /= a4; a0 /= a4;

  double roots[4];
  int n_real_roots;
  n_real_roots = SolveP4(roots, a3, a2, a1, a0);

  if (n_real_roots == 0) return;

  Vec3fa intersect_point;
  for (int i = 0; i < n_real_roots; i++)
  {
    float root = static_cast<float>(roots[i]);
    intersect_point = root * Dir + O;

    if ((ray.tnear <= root) && (root <= ray.tfar)) {

      ray.u = 0.0f;
      ray.v = 0.0f;
      ray.tfar = root;
      ray.geomID = torus.geomID;
      ray.primID = item;
      Vec3fa normal(
        4.0 * intersect_point.x * (sqr(intersect_point.x) + sqr(intersect_point.y) + sqr(intersect_point.z) - r2 - R2),
        4.0 * intersect_point.y * (sqr(intersect_point.x) + sqr(intersect_point.y) + sqr(intersect_point.z) - r2 - R2),
        4.0 * intersect_point.z * (sqr(intersect_point.x) + sqr(intersect_point.y) + sqr(intersect_point.z) - r2 - R2) + 8 * R2*intersect_point.z,
        0.0f
        );

      ray.Ng = normalize(torus.transform.mult(normal));
    }
  }
}

求解SolveP4函数方程的代码取自求解三次和二次函数

问题是当我们仔细观察环面时,它的效果非常好,如下所示:

光线从附近追踪圆环

但是当我缩小相机时,相机正看着远离它的圆环,它突然变得如此嘈杂,并且它的形状没有很好地识别。我尝试使用每个像素超过 1 个样本,但我仍然遇到同样的问题。如下:

光线追踪时从远处看不清楚圆环

看来我面临一个数值问题,但我不知道如何解决它。任何人都可以帮助我吗?

另外,值得一提的是,我正在使用英特尔的 Embree Lib 对圆环进行光线追踪。

更新(单色):

单色校正光线追踪环面 单色不正确的光线追踪环面 非常远单色不正确的光线追踪环面

4

3 回答 3

1

我认为很多问题是使用单精度浮点而不是双精度。

定义两个函数

double dsqr(double x) { return x*x; }

double ddot(const Vec3fa &a,Vec3fa &b) {
  double x1 = a.x, y1 = a.y, z1 = a.z;
  double x2 = b.x, y2 = b.y, z2 = b.z;
  return x1*x2 + y1*y2 + z1*z2;
}

找到平方和点积,但使用双精度。更改 r2 R2 a4 a3 a2 a1 和 a0 的计算以使用这些

double r2 = dsqr(torus.r1);
double R2 = dsqr(torus.r2);

double a4 = dsqr(ddot(Dir, Dir));
double a3 = 4 * ddot(Dir, Dir) * ddot(O, Dir);
double a2 = 4 * dsqr(ddot(O, Dir)) + 2 * ddot(Dir, Dir) * (ddot(O, O) - r2 - R2)
    + 4 * R2 * dsqr(Dir.z);
double a1 = 4 * ddot(O, Dir) * (ddot(O, O) - r2 - R2) + 8 * R2 * O.z * Dir.z;
double a0 = dsqr(ddot(O, O) - r2 - R2) + 4 * R2 * dsqr(O.z) - 4 * R2 * r2;

剩下的所有代码都是一样的。在我的测试中,这使得看起来模糊的图像看起来非常清晰。

于 2015-06-30T00:54:47.767 回答
1

当我写我的光线追踪器时(顺便说一句,我正在使用一本名为“从头开始的光线追踪”的好书)我也遇到了一些关于 Toruses 的问题。那时我使用 Graphics Gems github repo 中的算法来计算射线圆环交点。解决方案是简单地使用更小的环面,例如,当我的环面的外半径大于100.0并且从我的光线追踪器开始的(0,0,0)光线出现大量数值错误时。使用较小的圆环半径1.0解决了我的问题。

这些数值误差的来源在于为环面多项式构建系数,环面的大小100.0在计算过程中生成的某些系数可能超过1e20. double精度保证大约 15 个有效数字,这造成了精度的大量损失。

于 2017-08-28T08:05:05.987 回答
1

PovRay 为此提供了有趣且有效的解决方案。只需将射线的原点移动到非常靠近环面的地方,系数对于多项式求解器就会有很好的值。多近:原点应该在半径为 mayor+2*minor 的球体上。...并按照@csharpfolk 的建议将市长半径保持为一

于 2019-09-16T19:42:34.537 回答