これは、ここでのスタックオーバーフローに関する最初の質問です。すべてが正しいことを願っています。Java プロジェクトでは、レイトレーシングに octree を使用する必要があります。私はすでに単純な八分木を作成し (隣接情報などを含まない)、オブジェクト メッシュの三角形を八分木の AABB に分類しました。ここで、すべての光線に対してツリーを簡単に横断したいと思います。(このプロジェクトを完了する時間は非常に短いため、非常に簡単なはずです)。基本的なアルゴリズムは次のとおりです。
- 最初のノードから開始
- このノードがヒットした場合、ソートされたリストで交点の場所を記憶します
- このノードに子がある場合は、子ボックスがヒットしているかどうかを確認し、すべての交点をソートされたリストに書き込みます
- 最も近い交点を持つ子ボックスから始めます
- このボックスにも子がある場合は、4) を参照してください。
- ノードに子がない場合は、このボックス内のすべての三角形を光線に対してチェックします
- 三角形がヒットした場合、三角形の色を取得し(シェーディングとすべてを含む)、画面に描画します
残念ながら、私の現在の実装では、交点の計算 (ray と ABBB) に「バグ」があるようです。AABB のいずれかの側がヒットしたかどうかを確認し、最も近い IP (光線の原点からの最小距離) を記憶します。
私の BoundingBox クラスのこの関数のコードは次のとおりです。
public HitResult intersects6(Ray ray) {
double t;
Vec3d ip = new Vec3d();
HitResult finalHitResult = null;
// front xy
if (Math.abs(ray.direction.z) > Helper.EPSYLON) {
t = (vmax.z - ray.origin.z) / ray.direction.z;
ip.x = ray.origin.x + t * ray.direction.x;
ip.y = ray.origin.y + t * ray.direction.y;
ip.z = vmax.z;
if ((ip.x >= vmin.x) && (ip.x <= vmax.x) && (ip.y >= vmin.y) && (ip.y <= vmax.y)) {
// here is an intersection
double distance = Vec3d.distance(ray.origin, ip);
finalHitResult = new HitResult(ip, distance);
}
}
// back xy
if (Math.abs(ray.direction.z) > Helper.EPSYLON) {
t = (vmin.z + ray.origin.z) / -ray.direction.z;
ip.x = ray.origin.x + t * ray.direction.x;
ip.y = ray.origin.y + t * ray.direction.y;
ip.z = vmin.z;
if ((ip.x >= vmin.x) && (ip.x <= vmax.x) && (ip.y >= vmin.y) && (ip.y <= vmax.y)) {
double distance = Vec3d.distance(ray.origin, ip);
if (finalHitResult!= null) {
if(distance < finalHitResult.distance)
finalHitResult.distance = distance;
finalHitResult.point = ip;
}
else
finalHitResult = new HitResult(ip, distance);
}
}
// Side Right
if (Math.abs(ray.direction.x) > Helper.EPSYLON) {
t = (vmax.x - ray.origin.x) / ray.direction.x;
ip.y = ray.origin.y + t * ray.direction.y;
ip.z = ray.origin.z + t * ray.direction.z;
ip.x = vmax.x;
if ((ip.y >= vmin.y) && (ip.y <= vmax.y) && (ip.z >= vmin.z) && (ip.z <= vmax.z)) {
double distance = Vec3d.distance(ray.origin, ip);
if (finalHitResult!= null) {
if(distance < finalHitResult.distance)
finalHitResult.distance = distance;
finalHitResult.point = ip;
}
else
finalHitResult = new HitResult(ip, distance);
}
}
// Side Left
if (Math.abs(ray.direction.x) > Helper.EPSYLON) {
t = (vmin.x + ray.origin.x) / -ray.direction.x;
ip.y = ray.origin.y + t * ray.direction.y;
ip.z = ray.origin.z + t * ray.direction.z;
ip.x = vmin.x;
if ((ip.y >= vmin.y) && (ip.y <= vmax.y) && (ip.z >= vmin.z) && (ip.z <= vmax.z)) {
double distance = Vec3d.distance(ray.origin, ip);
if (finalHitResult!= null) {
if(distance < finalHitResult.distance)
finalHitResult.distance = distance;
finalHitResult.point = ip;
}
else
finalHitResult = new HitResult(ip, distance);
}
}
// Top
if (Math.abs(ray.direction.y) > Helper.EPSYLON) {
t = (vmax.y - ray.origin.y) / ray.direction.y;
ip.x = ray.origin.x + t * ray.direction.x;
ip.z = ray.origin.z + t * ray.direction.z;
ip.y = vmax.y;
if ((ip.x >= vmin.x) && (ip.x <= vmax.x) && (ip.z >= vmin.z) && (ip.z <= vmax.z)) {
double distance = Vec3d.distance(ray.origin, ip);
if (finalHitResult!= null) {
if(distance < finalHitResult.distance)
finalHitResult.distance = distance;
finalHitResult.point = ip;
}
else
finalHitResult = new HitResult(ip, distance);
}
}
// Bottom
if (Math.abs(ray.direction.y) > Helper.EPSYLON) {
t = (vmin.y + ray.origin.y) / -ray.direction.y;
ip.x = ray.origin.x + t * ray.direction.x;
ip.z = ray.origin.z + t * ray.direction.z;
ip.y = vmin.y;
if ((ip.x >= vmin.x) && (ip.x <= vmax.x) && (ip.z >= vmin.z) && (ip.z <= vmax.z)) {
double distance = Vec3d.distance(ray.origin, ip);
if (finalHitResult!= null) {
if(distance < finalHitResult.distance)
finalHitResult.distance = distance;
finalHitResult.point = ip;
}
else
finalHitResult = new HitResult(ip, distance);
}
}
return finalHitResult;
これは最善の方法ではないと思います。私の最初の実装では、t 値を使用してそれらを比較しました (次にアクセスしたいボックスを見つけるため)。しかし、問題は同じでした。一部の交差点が見つかりませんでした。
ここで交差メソッドもチェックアウトしました: https://code.google.com/p/3d-workspace/source/browse/trunk/MathLibrary/Bounding/BoundingBox.cpp?r=17しかし、方法 がわかりませんこのコード (または任意の t 値) との交点を取得します。さらに、ここで説明されているようなスラブ メソッドをテストしまし た 。
public double[] intersects3(Ray ray) {
double Tnear = -1e30;
double Tfar = 1e30;
// First, check slab in X.
if (Math.abs(ray.direction.x) < 0.0) {
// Ray is parallel to X, but starts outside. Fail.
if (ray.origin.x < vmin.x || ray.origin.x > vmax.x) {
return null;
}
} else {
double Ta = ((vmin.x - ray.origin.x) / ray.direction.x), Tb = (vmax.x - ray.origin.x) / ray.direction.x;
double T1 = Math.min(Ta, Tb);
double T2 = Math.max(Ta, Tb);
if (T1 > Tnear)
Tnear = T1;
if (T2 < Tfar)
Tfar = T2;
if (Tnear > Tfar)
return null;
if (Tfar < 0)
return null;
}
// Then check slab in Y.
if (Math.abs(ray.direction.y) < 0.0) {
// Ray is parallel to X, but starts outside. Fail.
if (ray.origin.y < vmin.y || ray.origin.y > vmax.y) {
return null;
}
} else {
double Ta = (vmin.y - ray.origin.y) / ray.direction.y, Tb = (vmax.y - ray.origin.y) / ray.direction.y;
double T1 = Math.min(Ta, Tb);
double T2 = Math.max(Ta, Tb);
if (T1 > Tnear)
Tnear = T1;
if (T2 < Tfar)
Tfar = T2;
if (Tnear > Tfar)
return null;
if (Tfar < 0)
return null;
}
// Then check slab in Z.
if (Math.abs(ray.direction.z) < 0.0) {
// Ray is parallel to X, but starts outside. Fail.
if (ray.origin.z < vmin.z || ray.origin.z > vmax.z) {
return null;
}
} else {
double Ta = (vmin.z - ray.origin.z) / ray.direction.z, Tb = (vmax.z - ray.origin.z) / ray.direction.z;
double T1 = Math.min(Ta, Tb);
double T2 = Math.max(Ta, Tb);
if (T1 > Tnear)
Tnear = T1;
if (T2 < Tfar)
Tfar = T2;
if (Tnear > Tfar)
return null;
if (Tfar < 0)
return null;
}
// If we have survived this far, the test passed.
return new double[] { Tnear, Tfar };
}
たぶん、私はレイトレーシングを行うにはあまりにも愚かです。
しかし、私の実際の質問は次のとおりです。
t値を使用して、どのボックスが最も近い交差点を持っているかを比較することは可能ですか? はいの場合、どうすればこのt値を取得できますか? または、最初に切り取ったコードを機能させるにはどうすればよいですか? (これまでのところ、このソリューションが非常に遅い場合でも、機能するソリューションに満足しています)
前もって感謝します。