概要概要
- このブログのソース:https://www.jianshu.com/p/2c842362fb22/
- OBBは、方向付けされた境界ボックス(方向付けられた境界ボックス)の略
で、下の図に示すように、複雑な幾何学的図形を抽象化して衝突を単純化するために使用されます。ご覧のとおり、2Dビューで実際の衝突を計算するには、外側を離散化する必要があります。オブジェクトの輪郭を複数の線分に分割します。オブジェクトの位置関係を計算します。境界ボックスの衝突を計算することは、問題を抽象化して単純化することと同じです。2つの長方形の位置関係を見つける
真の輪郭と境界ボックス
2つの長方形間の距離を決定します
-
次の図に示すように、座標系には2つの長方形があります。解決したい問題は、次のように説明できます
。2つの長方形の中心位置、長さ、幅、および方向を知り、2つの長方形が分離されており、分離されている場合、どのくらい離れていますか?それらが交差する場合、それはどのくらいの深さですか?
座標系の2つの長方形 -
長方形の分離に関しては、問題を次のように単純化できます。2つの長方形を分離する直線を見つけることができますか?存在する場合、2つは分離されます。存在しない場合、2つは交差します。
説明:暗い部屋に2つの長方形の四角い柱があると想像できます。平行光線を放射するランプを使用して2つの長方形を照らすと、それらの影が分離されていること、つまり光が通過していることを確認するだけで済みます。 2つの間で、2つの長方形が分離されていることがわかります。
仕切りが存在することを証明する
-
どの方向でも、長方形を区切る直線があるかどうかを計算できます。方法は次のとおりです。
-
下の図に示すように、オレンジ色の矢印の方向を選択します。boxAとboxBの間の接続ABの投影はABプロジェクトです。長方形の対称性により、長方形の4分の1がABの範囲内に投影され、この4分の1の長方形の投影の長さは次のようになります。元の長方形の2つの辺の半分(ここで画像を理解するのは簡単ですが、適切な説明と説明はまだ考えていません)
任意の方向への投影 -
boxAとboxBのABprojとxVtprojおよびyVtprojの関係を観察し、結論を導き出すことができます。
AB proj> sum(Vt proj)の場合、長方形は分離されます
AB proj = sum(Vt proj)の場合、長方形は接線になります
AB proj <sum(Vt proj)の場合、長方形は交差します
線の方向を決定します
-
これで、長方形の影が特定の方向に重なっているかどうかを確認する方法がわかりました。では、どちらの方向から照らしたいのでしょうか。長方形が1つの角度(1°、2°、3°... 360°)から互いに分離されているかどうかを確認しますか?
-
既知の条件に基づいて、長方形の位置関係をできるだけ少ない回数で確認するにはどうすればよいですか?実際、必要なのは4つの方向だけで、これらの4つの方向は、2つの長方形の辺の方向です。証明は次のとおりです。次
の図に示すように、現在の状況では、複数の直線を直感的に見つけることができます。長方形を分離します。
2つの長方形の間の線の分割 -
簡単にわかります。2つの長方形の間の距離が遠いほど分割線が多くなり、近いほど分割線が少なくなります。上の写真の2つの長方形が互いに接近しているとき、それらはちょうど接線であると想像できます。現時点では、2つを分離する直線は1つだけです。
-
描くことができます:
定理①:2つの長方形が接している場合、常に長方形の1辺と一致する接線があります。証明:2つの長方形が接している場合、次の3つの状況があります。①終点と終点が一致する②終点とエッジ一致③辺と辺が一致します。いずれの場合も、片側に一致する直線があり、2つの長方形に同時に接し、2つの長方形を分離します。
- それは拡張することができます:
定理②:2つの長方形が分離されている場合、2つの長方形を分離する直線は常に少なくとも1つあり、この直線は2つの長方形の特定の辺に平行です。定理②から、使用する必要があるのは長方形に平行なものです。直線で確認してください。図に示すように、boxAのxVt、yVtとboxBのxVt、yVtは、4つの光の方向の1つが別の影を照らすことができる限り、2つの長方形が分離されていることがわかります。 2つの長方形が交差します
アルゴリズムフローの概要
- オブジェクトの衝突問題を次のように抽象化します。OBB衝突問題(2つの長方形が平面で分離されているかどうか)
- 2つの長方形の分離の問題を次のように単純化します。分割線の存在
- さらに、長方形の位置関係を決定するために、4方向の分割線の存在を確認するだけでよいことを証明しました。
アルゴリズムコード
// 矩形结构体
class OBB {
center: Vector2; // 矩形中心
xVt: Vector2; // 平行于矩形的 x 边,长度为 x 的一半
yVt: Vector2; // 平行于矩形的 y 边,长度为 y 的一半
}
/** 判断两矩形是否相离*/
function isSeparate(boxA: OBB, boxB: OBB) {
const vectorAB = boxB.center.clone().sub(boxA.center); // 矩形中心连线
const vectors = [boxA.xVt, boxA.yVt, boxB.xVt, boxB.yVt]; // 矩形四个方向向量
// 只要存在 d > 0,便说明两矩形相离。此处得到的 d 便是相离之远,相交之深
return vectors.some(v => {
const len = v.length();
const project = (vector: Vector2) => {
return Math.abs(vector.dot(v)) / len; }; // 计算向量在该方向上的投影
const d = project(vectorAB) // AB 的投影
- project(boxA.xVt) - project(boxA.yVt) // boxA 的投影
- project(boxB.xVt) - project(boxB.yVt); // boxB 的投影
return d > 0; // d > 0,则在该方向上,矩形的投影是相离的
});
}