2017-12-18 366 views
2

我可以實現AABB方法來檢測碰撞,它很容易且便宜,但是我想實現OBB以獲得更高的精度,所以我創建了包含8個邊界的模型初始化的邊界框頂點和中心,每幀我轉換所有的頂點與變換矩陣,以適應定向包圍盒,但我不明白的方法來檢測兩個OBB之間的碰撞,我找不到一個簡單和清晰的教程,解釋算法與代碼觀點不是數學,因爲我不是數學家。簡單定向邊界框OBB碰撞檢測解釋

,如果我有

struct Box { 
    glm::vec3 vertices[8]; 
    Box() { 
     for (int i = 0; i < 8; i++) { 
      vertices[i] = glm::vec3(0); 
     } 
    } 
    glm::vec3 max; 
    glm::vec3 min; 
    glm::vec3 origin; 

    void reCompute() { 
     max = vertices[0]; 
     min = vertices[0]; 
     for (int i = 1; i < 8; i++) { 
      max.x = max.x > vertices[i].x ? max.x : vertices[i].x; 
      max.y = max.y > vertices[i].y ? max.y : vertices[i].y; 
      max.z = max.z > vertices[i].z ? max.z : vertices[i].z; 

      min.x = min.x < vertices[i].x ? min.x : vertices[i].x; 
      min.y = min.y < vertices[i].y ? min.y : vertices[i].y; 
      min.z = min.z < vertices[i].z ? min.z : vertices[i].z; 
     } 
     origin = glm::vec3((max.x + min.x)/2.0f, (max.y + min.y)/2.0f, (max.z + min.z)/2.0f); 
    } 
//AABB intersection 
    bool intersects(const Box &b) const { 
     return (min.x < b.max.x) && (max.x > b.min.x) && (min.y < b.max.y) && (max.y > b.min.y) && (min.z < b.max.z) && (max.z > b.min.z) && *this != b; 
    } 

    bool operator==(const Box& b) const { 
     return (max.x == b.max.x && max.y == b.max.y && max.z == b.max.z && min.x == b.min.x && min.y == b.min.y && min.z == b.min.z); 
    } 
    bool operator!=(const Box& b) const { 
     return (max.x != b.max.x) || (max.y != b.max.y) || (max.z != b.max.z) || (min.x != b.min.x) || (min.y != b.min.y) || (min.z != b.min.z); 
    } 
}; 
在模型初始化創建盒子

box.vertices[0] = glm::vec3(meshMinX, meshMinY, meshMinZ); 
    box.vertices[1] = glm::vec3(meshMaxX, meshMinY, meshMinZ); 
    box.vertices[2] = glm::vec3(meshMinX, meshMaxY, meshMinZ); 
    box.vertices[3] = glm::vec3(meshMaxX, meshMaxY, meshMinZ); 
    box.vertices[4] = glm::vec3(meshMinX, meshMinY, meshMaxZ); 
    box.vertices[5] = glm::vec3(meshMaxX, meshMinY, meshMaxZ); 
    box.vertices[6] = glm::vec3(meshMinX, meshMaxY, meshMaxZ); 
    box.vertices[7] = glm::vec3(meshMaxX, meshMaxY, meshMaxZ); 

,每幀

我重新計算與模型

for (int n = 0; n < 8; n++) { 
     boxs[j].vertices[n] = glm::vec3(matrix * glm::vec4(box.vertices[n], 1)); 
    } 
boxs[j].reCompute(); 
+0

本研究報告在這裏解釋了它在相當詳細。見「5」。 https://www.researchgate.net/publication/220721196_OBBTree_A_Hierarchical_Structure_for_Rapid_Interference_Detection –

+0

它有非常多的數學細節,所以我覺得它理解起來很複雜 –

回答

1

的變換矩陣箱知道兩個OBB碰撞你使用SAT(分離軸定理):你必須投影這兩個點的所有點在兩個形狀的每個法線上形狀。然後你會看到兩個形狀的投影是否重疊在每個法線上都有碰撞。如果至少有一個沒有重疊的法線,它們不會相互碰撞。所有這一切,你需要一種方法來做一個矢量在另一個上的正交投影,並返回一個標量,並且用一個方法來檢查兩個區間是否重疊。 我有一些代碼,但它的Java:

/** 
* Vec u is projected on Vec v 
* @param u 2d point 
* @param v 2d axe 
* @return the orthogonal projection 
*/ 
public static float orthagonalProjectionOf(Vector2f u, Vector2f v){ 
    float norme_u = u.lenght(); 
    float norme_v = v.lenght(); 
    float dot_u_v = dot(u, v); 
    float buffer = (dot_u_v/(norme_u*norme_v))*norme_u; 
    if(Float.isNaN(buffer))return 0;//If the vector u is null, then is orthogonal projection is 0, not a NaN 
    else return buffer; 
} 

重疊兩類區間的:

/** 
* Get the overlapping of two interval on an axis. 
* @param minA 
* @param maxA 
* @param minB 
* @param maxB 
* @return true overlapping. false if there is no overlapping 
*/ 
public static boolean isOverlapping(float minA, float maxA, float minB, float maxB) { 

    float minOverlap = Float.NaN; 
    float maxOverlap = Float.NaN; 


    //If B contain in A 
    if(minA <= minB && minB <= maxA) { 
     if(Float.isNaN(minOverlap) || minB < minOverlap)minOverlap = minB; 
    } 
    if(minA <= maxB && maxB <= maxA) { 
     if(Float.isNaN(maxOverlap) || maxB > minOverlap)maxOverlap = maxB; 
    } 

    //If A contain in B 
    if(minB <= minA && minA <= maxB) { 
     if(Float.isNaN(minOverlap) || minA < minOverlap)minOverlap = minA; 
    } 
    if(minB <= maxA && maxA <= maxB) { 
     if(Float.isNaN(maxOverlap) || maxA > minOverlap)maxOverlap = maxA; 
    } 

    if(Float.isNaN(minOverlap) || Float.isNaN(maxOverlap))return false; //Pas d'intersection 
    else return true;//Intersection 

} 

隨着你都能夠做到的方法來測試的U開V

Orthagonal投影兩個OBB之間的碰撞:

public boolean OBBwOBB(RigidBody bodyA, RigidBody bodyB) { 
    Shape shapeA = bodyA.getObb().getShape(); 
    Shape shapeB = bodyB.getObb().getShape(); 

    short overlapCompt = 0; 

    //We test for each normal the projection of the two shape 
     //Shape A : 
    for(int i = 0; i < shapeA.getNbrOfNormals(); i++) { 
     Vector2f normal = shapeA.getNormal(i, bodyA.getAngle()); 
     boolean overlap = overlapOnThisNormal(bodyA, bodyB, normal); 
     if(overlap) { 
      overlapCompt++; 
     } 
    } 
     //Shape B : 
    for(int i = 0; i < shapeB.getNbrOfNormals(); i++) { 
     Vector2f normal = shapeB.getNormal(i, bodyB.getAngle()); 
     boolean overlap = overlapOnThisNormal(bodyA, bodyB, normal); 
     if(overlap){ 
      overlapCompt++; 
     } 
    } 

    //Now we see if there is a collision 
    short howManyNormals = (short) (shapeA.getNbrOfNormals() + shapeB.getNbrOfNormals()); 
    if(overlapCompt == howManyNormals){//If the number of overlap equal the number of normal in both shape : 
     return true; 
    } 
    else return false; 

} 

而且您將需要它t爲兩個形式投影在向量的投影的最小值和最大值:

/** 
* Test if the orthogonal projection of two shape on a vector overlap. 
* @param bodyA 
* @param bodyB 
* @param normal 
* @return null if no overlap, else Vector2f(minOverlaping, maxOverlaping). 
*/ 
public static boolean overlapOnThisNormal(RigidBody bodyA, RigidBody bodyB, Vector2f normal) { 
    Shape shapeA = bodyA.getObb().getShape(); 
    Shape shapeB = bodyB.getObb().getShape(); 

    //We test each vertex of A 
    float minA = Float.NaN; 
    float maxA = Float.NaN; 
    for(short j = 0; j < shapeA.getNbrOfPoint(); j++){ 
     Vector2f vertex = shapeA.getVertex(j, bodyA.getScale().x, bodyA.getScale().y, bodyA.getPosition().x, bodyA.getPosition().y, bodyA.getAngle()); 
     float bufferA = Vector2f.orthagonalProjectionOf(vertex, normal); 
     if(Float.isNaN(minA) || bufferA < minA)minA = bufferA;//Set min interval 
     if(Float.isNaN(maxA) || bufferA > maxA)maxA = bufferA;//Set max interval 
    } 

    //We test each vertex of B 
    float minB = Float.NaN; 
    float maxB = Float.NaN; 
    for(short j = 0; j < shapeB.getNbrOfPoint(); j++){ 
     Vector2f vertex = shapeB.getVertex(j, bodyB.getScale().x, bodyB.getScale().y, bodyB.getPosition().x, bodyB.getPosition().y, bodyB.getAngle()); 
     float bufferB = Vector2f.orthagonalProjectionOf(vertex, normal); 
     if(Float.isNaN(minB) || bufferB < minB)minB = bufferB;//Set min interval 
     if(Float.isNaN(maxB) || bufferB > maxB)maxB = bufferB;//Set max interval 
    } 

    //We test if there overlap 
    boolean overlap = isOverlapping(minA, maxA, minB, maxB); 
    return overlap; 
} 

我希望這個幫你;)