web-dev-qa-db-ja.com

光線と三角形の交点

私は、MollerとTrumboreによる 高速最小ストレージ光線/三角形交差 が頻繁に推奨されることを見ました。

重要なのは、交差点の速度が上がる限り、データを事前に計算して保存してもかまいません。

だから私の質問は、記憶を気にしないで、光線と三角形の交差を行う最も速い方法は何ですか?

編集:三角形を移動しません。つまり、静的なシーンです。

20
Ecir Hana

他の人が述べているように、物事をスピードアップする最も効果的な方法は、加速構造を使用して、必要な光線と三角形の交点の数を減らすことです。とはいえ、光線と三角形の交差を高速にする必要があります。事前計算に満足している場合は、次のことを試すことができます。

光線線と三角形のエッジを プリュッカー座標 に変換します。これにより、光線がエッジごとに6回の乗算/加算で三角形を通過するかどうかを判断できます。光線の始点と終点を三角形の平面と比較して(ポイントごとに4つの乗算/加算で)、実際に三角形に当たることを確認する必要があります。

最悪の場合の実行時費用は、26の乗算/加算の合計です。また、レイ/エッジの組み合わせごとにレイ/エッジの符号を1回だけ計算する必要があるため、メッシュを評価する場合は、各エッジの評価を2回使用できる可能性があることに注意してください。

また、これらの数値は、すべてが同次座標で行われていることを前提としています。事前に正規化することで、乗算の数を減らすことができる場合があります。

9
comingstorm

私はlotのベンチマークを実行しましたが、fastest(公開された)メソッドはHavelとHeroutによって発明され、彼らの論文で提示されたものであると自信を持って言えます さらに高速な光線と三角形の交差(SSE4を使用)SSEを使用しないでも、MöllerとTrumboreのアルゴリズムの約2倍の速度です。

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;
}
5

1つの提案は、octree(http://en.wikipedia.org/wiki/Octree)アルゴリズムを実装して、3Dスペースを非常に細かいブロックに分割することです。パーティション分割が細かいほど、必要なメモリは多くなりますが、ツリーの精度は高くなります。

光線と三角形の交点を確認する必要がありますが、光線が三角形に当たらないことが保証されているため、光線と三角形の交点をスキップできるタイミングをツリーが通知するという考え方です。

ただし、三角形を動かし始めた場合は、オクトリーを更新する必要があります。そうすると、何も節約できるかどうかわかりません。

2
Simon Ejsing

ダンサンデーによるこの記事を見つけました:

最初の拒否テストまでに実行された操作の数に基づくと、このアルゴリズムはMT(Möller&Trumbore)アルゴリズム[...]よりも少し効率が低くなります。ただし、 MTアルゴリズムは2つの外積を使用しますが、アルゴリズムは1つのみを使用し、使用するアルゴリズムは、線パラメーターの計算に必要な三角形の平面の法線ベクトルを計算しますrI。ただし、シーン内のすべての三角形に対して正規ベクトルが事前に計算されて保存されている場合(これはよくあることです)、アルゴリズムは次の場所でこの外積を計算する必要はありません。ただし、この場合、MTアルゴリズムは、2つの外積を計算し、アルゴリズムよりも効率が低くなります。

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

2
Jack