OBB เป็นตัวเรือนูน ฮัลล์นูนเป็นรูปร่าง 3 มิติที่ไม่มี "crannies" บนพื้นผิว ทุก "ชน" (จุดสุดยอด) บนตัวเรือนูนยื่นออกมาด้านนอกไม่เข้าด้านใน หากคุณหั่นเครื่องบินผ่านตัวถังนูนคุณจะได้รูปหลายเหลี่ยมนูน (เพียงรูปเดียว) หากคุณอยู่ในลำเรือนูนและยิงเลเซอร์ชี้ออกไปด้านนอกคุณจะเจาะทะลุพื้นผิวของลำเรือเพียงหนึ่งครั้งเท่านั้น (ไม่ถึงสองครั้ง)
การทดสอบทฤษฎีการแยกแกนสามารถใช้ตรวจจับการชนของเปลือกนูนได้ การทดสอบ SAT นั้นง่าย มันทำงานได้ใน 2D และ 3D แม้ว่ารูปภาพด้านล่างจะเป็นแบบ 2D แต่ก็สามารถนำไปใช้กับ 3D ได้อย่างง่ายดาย
แนวคิด
นี่คือแนวคิดหลักที่คุณใช้กับ SAT:
- สองรูปทรงตัดเฉพาะถ้าพวกเขามีการทับซ้อนกันเมื่อ "คาดการณ์" เข้าสู่ทุกแกนปกติของรูปร่างทั้ง
"Projection" ของรูปร่างบนเวกเตอร์ 1D มีลักษณะเช่นนี้ (สิ่งที่ฉันเรียกว่า "crushing")
รูปร่างที่มี verts สีแดงและแกน
"การฉายรูปร่างให้กับแกน" หมายถึงการวางฉากตั้งฉากจากแต่ละจุดบนรูปร่างเพื่อให้ถึงจุดบนแกน คุณสามารถคิดได้ว่านี่คือ "บดขยี้" คะแนนด้วยมือที่รวบรวมทุกอย่างและตั้งฉากกับแกน
สิ่งที่คุณเหลือ: คะแนนบนแกน
SAT พูดว่า:
สำหรับลำตัวนูน 2 ลูกเพื่อตัดกันพวกมันจะต้องทับซ้อนกันในทุกแกน (ที่ทุกรูปร่างปกตินับเป็นแกนที่เราต้องตรวจสอบ)
ใช้รูปทรงเหล่านี้ 2:
คุณเห็นว่าพวกมันไม่ตัดกันดังนั้นให้ลองใช้สองสามแกนเพื่อแสดงว่าการทับซ้อนไม่เกิดขึ้น
ลองใช้ยอดปกติของเพนตากอน:
นี่คือขอบเขต พวกเขาทับซ้อนกัน
ลองทางด้านซ้ายของสี่เหลี่ยม ตอนนี้พวกมันไม่ทับซ้อนกันในแกนนี้ดังนั้นจึงไม่มีสัญญาณรบกวน
ขั้นตอนวิธีการ:
สำหรับแต่ละใบหน้าปกติทั้งสองรูปร่าง:
- ค้นหาขอบเขตขั้นต่ำและสูงสุด (ค่าที่มากที่สุดและน้อยที่สุด) ของการฉายภาพของจุดยอดมุมทั้งหมดของรูปร่างทั้งสองบนแกนนั้น
- หากพวกเขาไม่ได้ทับซ้อนไม่มีสี่แยก
และนั่นเป็นเรื่องจริง รหัสที่ทำให้การทำงานของ SAT นั้นสั้นและง่ายมาก
นี่คือรหัสบางส่วนที่แสดงให้เห็นถึงวิธีการฉายแกน SAT:
void SATtest( const Vector3f& axis, const vector<Vector3f>& ptSet, float& minAlong, float& maxAlong )
{
minAlong=HUGE, maxAlong=-HUGE;
for( int i = 0 ; i < ptSet.size() ; i++ )
{
// just dot it to get the min/max along this axis.
float dotVal = ptSet[i].dot( axis ) ;
if( dotVal < minAlong ) minAlong=dotVal;
if( dotVal > maxAlong ) maxAlong=dotVal;
}
}
รหัสโทร:
// Shape1 and Shape2 must be CONVEX HULLS
bool intersects( Shape shape1, Shape shape2 )
{
// Get the normals for one of the shapes,
for( int i = 0 ; i < shape1.normals.size() ; i++ )
{
float shape1Min, shape1Max, shape2Min, shape2Max ;
SATtest( normals[i], shape1.corners, shape1Min, shape1Max ) ;
SATtest( normals[i], shape2.corners, shape2Min, shape2Max ) ;
if( !overlaps( shape1Min, shape1Max, shape2Min, shape2Max ) )
{
return 0 ; // NO INTERSECTION
}
// otherwise, go on with the next test
}
// TEST SHAPE2.normals as well
// if overlap occurred in ALL AXES, then they do intersect
return 1 ;
}
bool overlaps( float min1, float max1, float min2, float max2 )
{
return isBetweenOrdered( min2, min1, max1 ) || isBetweenOrdered( min1, min2, max2 ) ;
}
inline bool isBetweenOrdered( float val, float lowerBound, float upperBound ) {
return lowerBound <= val && val <= upperBound ;
}