intersect()で判定が取れない場所も平面式を使い、近いプリミティブの平面を延長した平面とみなして衝突点を計算する。
//
// 境界外を考慮したRay Intersect
//
// input0: 対象
// input1: 実際のコリジョンメッシュ
// input2: 平面(P.y = 0)につぶしたコリジョンメッシュ
// 平面と直線の交差座標を返す
vector rayIntersectPlane(vector planePos; vector planeNormal; vector origin; vector ray;)
{
float d = -(planeNormal.x * planePos.x + planeNormal.y * planePos.y + planeNormal.z * planePos.z);
float t = -(planeNormal.x * origin.x + planeNormal.y * origin.y + planeNormal.z * origin.z + d) / (planeNormal.x * ray.x + planeNormal.y * ray.y + planeNormal.z * ray.z);
return set(origin.x + ray.x * t, origin.y + ray.y * t, origin.z + ray.z * t);
}
// 交差
vector origin = @P + set(0, 5000, 0);
vector pos;
vector uv;
vector dir = set(0, -1, 0) * 10000;
int hitId = intersect(1, origin, dir, pos, uv);
// 平面がヒット
if(hitId >= 0)
{
@P = pos;
}
else
{
// 平面につぶした状態で一番近いプリティブ番号を取得
int index;
origin = set(@P.x, 0, @P.z);
xyzdist(2, origin, index, uv);
// 実際のメッシュから座標や法線を取得する
int pts[] = primpoints(1, index);
vector p0 = point(1, "P", pts[0]);
vector p1 = point(1, "P", pts[1]);
vector p2 = point(1, "P", pts[2]);
vector normal = normalize(cross(p2 - p1, p1 - p0));
// 平面とレイの交差を取る
vector planePos = point(1, "P", pts[0]);
vector planeNormal = normal;
@P = rayIntersectPlane(planePos, planeNormal, origin, set(0, -1, 0));
}
input2につなぐメッシュはVEXで平面にしておく。
@P.y = 0;