はじめに
今回は最近3Dを触り初めたので3Dの衝突判定について書こうと思います。
自己紹介
HAL大阪ゲーム学科2年のゲームプログラマ目指してる人です。
@konojunya にアドベントカレンダーに誘われ書くことになりました。
アドベントカレンダーは今回が初めてです。
境界ボリューム( Bounding Volume,BV)
境界ボリューム( Bounding Volume,BV)とは
単体の単純なボリュームで複雑なオブジェクトを包んで判定を簡単するというものです。
単純なボリュームを使うことで複雑なオブジェクトと比べて重なりの判定にかかる時間が短いです。
いい境界ボリューム
-
交差判定のコストがかからない
-
オブジェクトの形に密着している
-
計算に時間がかからない
-
回転と移動が簡単である
-
わずかなメモリのみ使用
軸平行境界ボックス(AABB:Axis-Aligned Bounding Box)
軸平行境界ボックス(AABB:Axis-Aligned Bounding Box)とは
軸平行境界ボックス(AABB:Axis-Aligned Bounding Box)は最も一般的な境界ボリュームの1つです。
直方体3Dの場合は6つ、2Dでは4つの面を持つボックス型で、各面の方向はその面の法線が常に座標系の軸に対して平行になっています。AABBの最大の特徴は重なりの判定が高速に行えることです。
struct AABB {
D3DXVECTOR3 max;
D3DXVECTOR3 min;
};
struct AABB {
D3DXVECTOR3 min;
float d[3];
};
struct AABB {
D3DXVECTOR3 center;
D3DXVECTOR3 r[3];
};
コードにしたらこんな感じです。
実装
(1)の最小-最大の判定を簡単に書いてみた。
このコードの使い勝手はおいといて、、、、
取り敢えず、最大値と最小値と当たり判定を取りたいオブジェクトの座標を渡します。
オブジェクトが移動するとupdateでオブジェクトの座標を渡しバウンディングボリュームを更新します。
intersectAABBで判定したいAABBを渡してあげておわりです。
struct AABB {
D3DXVECTOR3 min; // 最大値
D3DXVECTOR3 max; // 最小値
D3DXVECTOR3 actorOldPos; // 前の座標値
AABB() = default;
~AABB() = default;
AABB(D3DXVECTOR3 minValue, D3DXVECTOR3 maxValue, D3DXVECTOR3 actorPos) {
min = minValue;
max = maxValue;
actorOldPos = actorPos;
}
// 更新
void update(const D3DXVECTOR3& actorPosition) {
D3DXVECTOR3 diff = actorPosition - actorOldPos;
min += diff;
max += diff;
actorOldPos= actorPosition;
}
};
// AABBとAABBの衝突判定
inline bool intersectAABB(const AABB& box1,const AABB& box2) {
if (box1.min.x > box2.max.x) return false;
if (box1.max.x < box2.min.x) return false;
if (box1.min.y > box2.max.y) return false;
if (box1.max.y < box2.min.y) return false;
if (box1.min.z > box2.max.z) return false;
if (box1.max.z < box2.min.z) return false;
return true; // 衝突!!
}
終わり
もっと書くはずだったのに()
参考文献
もっと参考にするはずだった最高の技術書
ゲームプログラミングのためのリアルタイム衝突判定
ゲーム3D数学
ゲームアプリの数学Unityで学ぶ基礎からシェーダーまで
ゲームプログラミングのための3Dグラフィックス数学