光線と平面の間の交差を計算するにはどうすればよいですか?
これは間違った結果をもたらします。
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
は平面を定義します
一度コメントしたように、分母を負にすることもできます。そうしないと、飛行機の前面との交差が失われます。ただし、光線が平面に平行であることを示すゼロによる除算を回避するためのテストも必要です。また、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;
最初に、光線と平面の交差の数学を考えてみましょう。
一般的には、光線のパラメトリック形式とジオメトリの暗黙の形式が交差します。
したがって、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の実際の値を取得できます。ここではマキシマにあります:
答えは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);
}
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;
}
最初の点_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;
}
_