2017-02-20 17 views
0

現在,我正在嘗試使用分離軸定理來實現Java中的動態3-D OBB碰撞測試。我試圖從0到1的交叉點找到每個分離軸的實體的時間,其中0表示幀的開始,1表示幀的結束。動態OBB碰撞檢測(分離軸定理):找出碰撞發生的時間?

這裏是我的代碼:

private float calculateITime(OBB obb, 
Vector3f axis /*the separating axis we are testing*/, 
Vector3f d /*Current OBB's origin minus other OBB's origin*/, 
float ra /*the first obb's projection*/, 
float rb /*the second obb's projection*/, 
float r /*what I understand to be the total length of the combined projections*/) { 
    //Find the time, from 0 (the beginning of the frame) to 1 (the end of the frame), that the obb's first intersected. 
    float intersectionLength = r - Math.abs(ra) - Math.abs(rb); //The measure of how much the two projections overlap 

    Vector3f aVelocity = this.getCollisionPacket().getVelocity(); 
    Vector3f bVelocity = obb.getCollisionPacket().getVelocity(); 

    double aMagnitude = Mathematics.dotProduct(axis, Mathematics.crossProduct(aVelocity, d)); 
    double bMagnitude = Mathematics.dotProduct(axis, Mathematics.crossProduct(bVelocity, d)); 

    double totalDistanceCovered = 0; 

    if(aMagnitude <= 0 && bMagnitude <= 0) { 
     totalDistanceCovered = Math.abs(aMagnitude - bMagnitude); 
    } else if((aMagnitude >= 0 && bMagnitude <= 0) || (aMagnitude <= 0 && bMagnitude >= 0)) { 
     totalDistanceCovered = Math.abs(aMagnitude + bMagnitude); 
    } else if(aMagnitude >= 0 && bMagnitude >= 0) { 
     totalDistanceCovered = Math.abs(aMagnitude - bMagnitude); 
    } 

    System.out.println("PotentialITime: " + Math.abs(intersectionLength/totalDistanceCovered)); 
    return (float) Math.abs(intersectionLength/totalDistanceCovered); 
} 

但是,我得到的值遠高於之一。我錯在哪裏,假設我甚至正確理解如何正確實施分離軸定理?

如果您認爲自己有答案,但如果我發佈了其他課程(雖然時間很長),請告訴我,我會爲您做。謝謝!

最終備註:

此功能位於OBB類中。因此,「this」是指OBB,「obb」是指其他OBB。

collisionPacket.getVelocity()返回在沒有碰撞的情況下單幀出現的總位移。

「數學」是我自己的靜態類。假設它正常工作。我沒有意識到Vector3f在我做完之後才擁有所有這些有用的功能。

This是我正在使用的PDF。我在第9頁卡住了2.3.1。

回答

0

幾個星期後,我想出瞭如何做我想做的事情。幾周前我確實想到了這一點,但我現在想要發佈我的解決方案。

private boolean determineCollision(OBB obb, Vector3f separatingAxis, double velocityMagnitude, float ra, float rb, float r) { 
    //Find the time, from 0 (the beginning of the frame) to 1 (the end of the frame), that the obb's first intersected. 

    //If r is negative, the first OBB is to the "right." Otherwise, it is to the "left." 
    collisionRightSide.add(r < 0); 
    boolean currColRightSide = collisionRightSide.get(collisionRightSide.size() - 1); 

    double timeRange[] = new double[2]; //From 0 (beginning of frame) to 1 (end of frame) 

    //Perform a regular static test if there is no movement for optimization's sake 
    boolean noStaticOverlap = Math.abs(r) > (ra + rb); 
    if(velocityMagnitude == 0) { 
     timeRange[0] = 0; timeRange[1] = 1; 
     axisTimes.add(timeRange); 
     return !noStaticOverlap; 
    } 

    double spaceBetweenProjections = Math.abs(r) - Math.abs(ra) - Math.abs(rb); 

    //Note that if velocity magnitude is negative, the first OBB is moving "right," and the other way for positive. 
    if(currColRightSide) { 
     if(velocityMagnitude < 0) { 
      if(noStaticOverlap) { 
//     System.out.println("(Right side) OBBs are moving away"); 
       return false; 
      } else { 
       timeRange[0] = 0; 
       timeRange[1] = Math.abs(spaceBetweenProjections/velocityMagnitude); 
      } 
     } else if(velocityMagnitude > 0) { 
      if(noStaticOverlap) { 
       timeRange[0] = Math.abs(spaceBetweenProjections/velocityMagnitude);; 
       timeRange[1] = Math.abs((spaceBetweenProjections + 2 * rb)/velocityMagnitude); 
      } else { 
       timeRange[0] = 0; 
       timeRange[1] = Math.abs((spaceBetweenProjections + 2 * rb)/velocityMagnitude); 
      } 
     } 
    } else { 
     if(velocityMagnitude > 0) { 
      if(noStaticOverlap) { 
//     System.out.println("(Left side) OBBs are moving away"); 
       return false; 
      } else { 
       timeRange[0] = 0; 
       timeRange[1] = Math.abs(spaceBetweenProjections/velocityMagnitude); 
      } 
     } else if(velocityMagnitude < 0) { 
      if(noStaticOverlap) { 
       timeRange[0] = Math.abs(spaceBetweenProjections/velocityMagnitude); 
       timeRange[1] = Math.abs((spaceBetweenProjections + 2 * rb)/velocityMagnitude); 
      } else { 
       timeRange[0] = 0; 
       timeRange[1] = Math.abs((spaceBetweenProjections + 2 * rb)/velocityMagnitude); 
      } 
     } 
    }  

    //Clamp values 
    if(timeRange[0] < 0) timeRange[0] = 0; 
    if(timeRange[1] > 1) timeRange[1] = 1; 

    //Switch so that the greater value comes last 
    if(timeRange[0] > timeRange[1]) { 
     double temp = timeRange[0]; 
     timeRange[0] = timeRange[1]; 
     timeRange[1] = temp; 
    } 

    if(timeRange[0] > 1 && timeRange[1] < 0) return false; 

    axisTimes.add(timeRange); 

    return true; 
} 

感謝StackOverflow給我這個問題的Tumbleweed徽章。如果有人提出了更好或更優化的方式,請告訴我。謝謝! :D