web-dev-qa-db-ja.com

レイプレーンを交差させる方法は?

光線と平面の間の交差を計算するにはどうすればよいですか?

コード

これは間違った結果をもたらします。

float denom = normal.dot(ray.direction);

if (denom > 0)
{
    float t = -((center - ray.Origin).dot(normal)) / denom;

    if (t >= 0)
    {
        rec.tHit = t;
        rec.anyHit = true;
        computeSurfaceHitFields(ray, rec);
        return true;
    }
}

パラメーター

rayは光線オブジェクトを表します。
ray.directionは方向ベクトルです。
ray.Originは、Originベクトルです。
recは結果オブジェクトを表します。
rec.tHitはヒットの値です。
rec.anyHitはブール値です。

私の機能は飛行機にアクセスできます:
centerおよびnormalは平面を定義します

14

一度コメントしたように、分母を負にすることもできます。そうしないと、飛行機の前面との交差が失われます。ただし、光線が平面に平行であることを示すゼロによる除算を回避するためのテストも必要です。また、tの計算に不必要な否定があります。全体として、次のようになります。

float denom = normal.dot(ray.direction);
if (abs(denom) > 0.0001f) // your favorite epsilon
{
    float t = (center - ray.Origin).dot(normal) / denom;
    if (t >= 0) return true; // you might want to allow an epsilon here too
}
return false;
21
Trillian

最初に、光線と平面の交差の数学を考えてみましょう。

一般的には、光線のパラメトリック形式とジオメトリの暗黙の形式が交差します。

したがって、x = a * t + a0、y = b * t + b0、z = c * t + c0という形式の光線が与えられます。

および次の形式の平面:A x * B y * C z + D = 0;

ここで、x、y、zの光線方程式を平面方程式に代入すると、tに多項式が得られます。次に、tの実数値についてその多項式を解きます。これらのtの値を使用して、光線方程式に逆代入すると、x、y、zの実際の値を取得できます。ここではマキシマにあります:

enter image description here

答えは2つのドット積の商のように見えることに注意してください。平面の法線は、平面方程式A、B、Cの最初の3つの係数です。平面を一意に決定するには、Dが必要です。次に、次のように選択した言語でコードを記述します。

Point3D intersectRayPlane(Ray ray, Plane plane)
{
    Point3D point3D;

    //  Do the dot products and find t > epsilon that provides intersection.


    return (point3D);
}
8
vwvan

vwvanの回答の実装

Vector3 Intersect(Vector3 planeP, Vector3 planeN, Vector3 rayP, Vector3 rayD)
{
    var d = Vector3.Dot(planeP, -planeN);
    var t = -(d + rayP.z * planeN.z + rayP.y * planeN.y + rayP.x * planeN.x) / (rayD.z * planeN.z + rayD.y * planeN.y + rayD.x * planeN.x);
    return rayP + t * rayD;
}
3
Bas Smit

最初の点_p = p0 + t*v_の_p0_および_t >= 0_の方向ベクトルvによって光線がパラメトリックに与えられるようにします。

平面は、法線ベクトルdot(n, p) + d = 0と定数dに対してn = (a, b, c)で与えられます。 rが平面上の点である場合、d = - dot(n, r)です。完全に展開すると、平面方程式も_ax + by + cz + d = 0_と書くことができます。

光線を平面方程式に代入すると、次のようになります。

_t = - (dot(n, p) + d) / dot(n, v)
_

実装例:

_std::optional<vec3> intersectRayWithPlane(
    vec3 p, vec3 v,  // ray
    vec3 n, float d  // plane
) {
    float denom = dot(n, v);

    // Prevent divide by zero:
    if (abs(denom) <= 1e-4f)
        return std::nullopt;

    // If you want to ensure the ray reflects off only
    // the "top" half of the plane, use this instead:
    if (-denom <= 1e-4f)
        return std::nullopt;

    float t = -(dot(n, p) + d) / dot(n, v);

    // Use pointy end of the ray.
    // It is technically correct to compare t < 0,
    // but that may be undesirable in a raytracer.
    if (t <= 1e-4)
        return std::nullopt;

    return p + t * v;
}
_
1
Mateen Ulhaq