【问题标题】:Ray-triangle intersection射线三角相交
【发布时间】:2012-10-21 05:12:46
【问题描述】:

我看到 Moller 和 Trumbore 的 Fast Minimum Storage Ray/Triangle Intersection 经常被推荐。

问题是,我不介意预先计算和存储任何数量的数据,只要它能加快交叉路口的速度。

所以我的问题是,不关心内存,进行射线三角形相交的最快方法是什么?

编辑:我不会移动三角形,即这是一个静态场景。

【问题讨论】:

  • 我经常使用 Moller 和 Trumbore 的 Fast Minimum Storage Ray/Triangle Intersecton。但这是我第一次知道这篇论文。我认为对于大量的射线和三角形,除了空间分割技术外,可以同时考虑并行方法。我正在做一个 OpenCL 实现,但我不知道是否有人已经这样做了。你听说过吗?
  • @squid 你可以试试看 LuxRender 的 LuxRays here

标签: algorithm graphics geometry rendering


【解决方案1】:

正如其他人所提到的,加快速度的最有效方法是使用加速结构来减少所需的射线与三角形相交的数量。也就是说,您仍然希望您的射线三角形相交速度快。如果您乐于预先计算内容,可以尝试以下方法:

将您的射线线和三角形边缘转换为Plücker coordinates。这使您可以确定您的射线线是否以每条边 6 次乘法/加法通过三角形。您仍然需要将您的光线起点和终点与三角形平面(每点 4 次乘法/加法)进行比较,以确保它实际上击中了三角形。

最坏情况下的运行时间开销是 26 次乘法/加法的总和。另外,请注意,您只需为每个光线/边缘组合计算一次光线/边缘符号,因此如果您正在评估网格,您可以使用每个边缘评估两次。

此外,这些数字假设一切都是在齐次坐标中完成的。您可以通过提前对事物进行归一化来减少乘法次数。

【讨论】:

  • 谢谢。通过任何更改,您不知道示例代码在哪里吗?顺便说一句,您推荐哪种加速结构,为什么?
  • 几年前,最先进的技术使用高度优化的 k-d 树。特别是对于静态场景,这可能是您最好的选择。重新示例代码,我在 Google 上找到了一些 relevant。不能保证——这篇论文似乎有些陈旧,但它的解释似乎足够清晰,而且它的基准测试将显着优势归功于 Plücker 代码。
【解决方案2】:

我已经做了很多 基准测试,我可以自信地说,最快(已发布)方法是 Havel 和 Herout 发明并在他们的论文中提出的方法Yet Faster Ray-Triangle Intersection (Using SSE4)。即使不使用 SSE,它的速度也大约是 Möller 和 Trumbore 算法的两倍。

Havel-Herout 我的 C 实现:

    typedef struct {
        vec3 n0; float d0;
        vec3 n1; float d1;
        vec3 n2; float d2;
    } isect_hh_data;

    void
    isect_hh_pre(vec3 v0, vec3 v1, vec3 v2, isect_hh_data *D) {
        vec3 e1 = v3_sub(v1, v0);
        vec3 e2 = v3_sub(v2, v0);
        D->n0 = v3_cross(e1, e2);
        D->d0 = v3_dot(D->n0, v0);

        float inv_denom = 1 / v3_dot(D->n0, D->n0);

        D->n1 = v3_scale(v3_cross(e2, D->n0), inv_denom);
        D->d1 = -v3_dot(D->n1, v0);

        D->n2 = v3_scale(v3_cross(D->n0, e1), inv_denom);
        D->d2 = -v3_dot(D->n2, v0);
    }

    inline bool
    isect_hh(vec3 o, vec3 d, float *t, vec2 *uv, isect_hh_data *D) {
        float det = v3_dot(D->n0, d);
        float dett = D->d0 - v3_dot(o, D->n0);
        vec3 wr = v3_add(v3_scale(o, det), v3_scale(d, dett));
        uv->x = v3_dot(wr, D->n1) + det * D->d1;
        uv->y = v3_dot(wr, D->n2) + det * D->d2;
        float tmpdet0 = det - uv->x - uv->y;
        int pdet0 = ((int_or_float)tmpdet0).i;
        int pdetu = ((int_or_float)uv->x).i;
        int pdetv = ((int_or_float)uv->y).i;
        pdet0 = pdet0 ^ pdetu;
        pdet0 = pdet0 | (pdetu ^ pdetv);
        if (pdet0 & 0x80000000)
            return false;
        float rdet = 1 / det;
        uv->x *= rdet;
        uv->y *= rdet;
        *t = dett * rdet;
        return *t >= ISECT_NEAR && *t <= ISECT_FAR;
    }

【讨论】:

    【解决方案3】:

    一个建议可能是实施八叉树 (http://en.wikipedia.org/wiki/Octree) 算法将您的 3D 空间划分为非常精细的块。分区越精细,所需的内存就越多,但树的准确度就越高。

    您仍然需要检查射线/三角形的交点,但想法是树可以告诉您何时可以跳过射线/三角形的交点,因为保证射线不会击中三角形。

    但是,如果您开始四处移动三角形,则需要更新八叉树,然后我不确定它是否会为您节省任何东西。

    【讨论】:

    • 谢谢!三角形不会四处移动。八叉树的问题,也许我误解了,是在一片叶子中可能有几个三角形,对吧?在那种情况下,我仍然需要一个快速的交叉路口例程。
    【解决方案4】:

    找到了 Dan Sunday 的这篇文章:

    根据直到第一次拒绝测试完成的操作计数,该算法的效率略低于 MT(Möller & Trumbore)算法,[...]。然而,MT 算法使用两个叉积,而我们的算法只使用一个叉积,而我们使用的那个计算三角形平面的法向量,这是计算直线参数 rI 所必需的。但是,当已经为场景中的所有三角形预先计算并存储了法线向量时(通常是这种情况),我们的算法根本不需要计算这个叉积。但是,在这种情况下,MT 算法仍然会计算两个叉积,并且效率低于我们的算法。

    http://geomalgorithms.com/a06-_intersect-2.html

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-03-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-04-03
      • 1970-01-01
      相关资源
      最近更新 更多