2017-02-21 97 views
0

我試圖在我的遊戲中實現Kasper Fauerby的碰撞檢測和響應,但我在檢測部分遇到了一些問題。多邊形湯橢圓碰撞誤報(Kasper Fauerby)

頂點和邊緣碰撞都會返回誤報,此時我並沒有將自由凸輪的速度添加到碰撞即將發生時的位置(半徑1)。

當我的下一個位置在三角形的平面上時,它看起來像頂點延伸了很多,然後它應該。但是,當我朝着頂點方向移動時,這隻會影響我。我可以平行於三角形的法線移動而不與頂點發生碰撞。

此刻,我剝了下來代碼一路的代碼Kasper provided in his paper,但這裏是我目前正在使用的代碼:

bool MeshCollider::CheckTriangleEllipsoid(glm::vec3 p1, glm::vec3 p2, glm::vec3 p3, Ellipsoid *colPackage) 
{ 
    // Make the plane containing this triangle. 
    Collision::PLANE trianglePlane(p1, p2, p3); 
    // Is triangle front-facing to the velocity vector? 
    // We only check front-facing triangles 
    // (your choice of course) 
    if (trianglePlane.isFrontFacingTo(
    colPackage->normalizedVelocity)) { 
    // Get interval of plane intersection: 
     double t0, t1; 
     bool embeddedInPlane = false; 
     // Calculate the signed distance from sphere 
     // position to triangle plane 
     double signedDistToTrianglePlane = trianglePlane.signedDistanceTo(colPackage->ePosition); 
     // cache this as we’re going to use it a few times below: 
     float normalDotVelocity = glm::dot(trianglePlane.normal, colPackage->eVelocity); 
     // if sphere is travelling parrallel to the plane: 
     if (normalDotVelocity == 0.0f) { 
      if (fabs(signedDistToTrianglePlane) >= 1.0f) { 
      // Sphere is not embedded in plane. 
      // No collision possible: 
       return false; 
      } 
      else { 
      // sphere is embedded in plane. 
      // It intersects in the whole range [0..1] 
       embeddedInPlane = true; 
       t0 = 0.0; 
       t1 = 1.0; 
      } 
     } 
     else { 
     // N dot D is not 0. Calculate intersection interval: 
      t0 = (-1.0 - signedDistToTrianglePlane)/normalDotVelocity; 
      t1 = (1.0 - signedDistToTrianglePlane)/normalDotVelocity; 
      // Swap so t0 < t1 
      if (t0 > t1) { 
       double temp = t1; 
       t1 = t0; 
       t0 = temp; 
      } 
      // Check that at least one result is within range: 
      if (t0 > 1.0f || t1 < 0.0f) { 
       // Both t values are outside values [0,1] 
       // No collision possible: 
       return false; 
      } 
      // Clamp to [0,1] 
      if (t0 < 0.0) t0 = 0.0; 
      if (t1 < 0.0) t1 = 0.0; 
      if (t0 > 1.0) t0 = 1.0; 
      if (t1 > 1.0) t1 = 1.0; 
     } 
     // OK, at this point we have two time values t0 and t1 
     // between which the swept sphere intersects with the 
     // triangle plane. If any collision is to occur it must 
     // happen within this interval. 
     glm::vec3 collisionPoint; 
     bool foundCollison = false; 
     float t = 1.0; 
     // First we check for the easy case - collision inside 
     // the triangle. If this happens it must be at time t0 
     // as this is when the sphere rests on the front side 
     // of the triangle plane. Note, this can only happen if 
     // the sphere is not embedded in the triangle plane. 

     if(!embeddedInPlane) { 
      glm::vec3 planeIntersectionPoint = 
      (colPackage->ePosition - trianglePlane.normal) 
      + (float)t0 * colPackage->eVelocity; 
      if (checkPointInTriangle(planeIntersectionPoint, 
       p1, 
       p2, 
       p3)) 
      { 
       foundCollison = true; 

       t = t0; 
       collisionPoint = planeIntersectionPoint; 
      } 
     } 

     // if we haven’t found a collision already we’ll have to 
     // sweep sphere against points and edges of the triangle. 
     // Note: A collision inside the triangle (the check above) 
     // will always happen before a vertex or edge collision! 
     // This is why we can skip the swept test if the above 
     // gives a collision! 


     if (foundCollison == false) { 
     // some commonly used terms: 
      glm::vec3 velocity = colPackage->eVelocity; 
      glm::vec3 base = colPackage->ePosition; 

      float velocitySquaredLength = glm::length(velocity); 
      float a, b, c; // Params for equation 
      float newT; 

      // For each vertex or edge a quadratic equation have to 
      // be solved. We parameterize this equation as 
      // a*t^2 + b*t + c = 0 and below we calculate the 
      // parameters a,b and c for each test. 
      // Check against points: 
      a = velocitySquaredLength; 
      // P1 
      b = 2.0 * (glm::dot(velocity, base - p1)); 
      c = glm::length(p1 - base) - 1.0; 
      if (getLowestRoot(a, b, c, t, &newT)) { 
       t = newT; 
       foundCollison = true; 
       collisionPoint = p1; 
       std::cout << "point 1\n"; 
      } 
      // P2 
      b = 2.0 * (glm::dot(velocity, base - p2)); 
      c = glm::length(p2 - base) - 1.0; 
      if (getLowestRoot(a, b, c, t, &newT)) { 
       t = newT; 
       foundCollison = true; 
       collisionPoint = p2; 
       std::cout << "point 2\n"; 
      } 

      // P3 
      b = 2.0*(glm::dot(velocity, base - p3)); 
      c = glm::length(p3 - base) - 1.0 ; 
      if (getLowestRoot(a, b, c, t, &newT)) { 
       t = newT; 
       foundCollison = true; 
       collisionPoint = p3; 
       std::cout << "point 3\n"; 
      } 

      // Check agains edges: 
      // p1 -> p2: 
      glm::vec3 edge = p2 - p1; 
      glm::vec3 baseToVertex = p1 - base; 
      float edgeSquaredLength = glm::length(edge); 
      float edgeDotVelocity = glm::dot(edge, velocity); 
      float edgeDotBaseToVertex = glm::dot(edge, baseToVertex); 
      // Calculate parameters for equation 
      a = edgeSquaredLength * -velocitySquaredLength + 
      edgeDotVelocity*edgeDotVelocity; 
      b = edgeSquaredLength*(2*glm::dot(velocity, baseToVertex)) - 
      2.0*edgeDotVelocity*edgeDotBaseToVertex; 
      c = edgeSquaredLength*(1 - glm::length(baseToVertex)) + 
      edgeDotBaseToVertex*edgeDotBaseToVertex; 
      // Does the swept sphere collide against infinite edge? 
      if(getLowestRoot(a, b, c, t, &newT)) { 
      // Check if intersection is within line segment: 
       float f = (edgeDotVelocity*newT - edgeDotBaseToVertex)/
       edgeSquaredLength; 
       if (f >= 0.0 && f <= 1.0) { 
       // intersection took place within segment. 
        t = newT; 
        foundCollison = true; 
        collisionPoint = p1 + f*edge; 
        std::cout << "p1 p2\n"; 
       } 
      } 

      // p2 -> p3: 
      edge = p3 - p2; 
      baseToVertex = p2 - base; 
      edgeSquaredLength = glm::length(edge); 
      edgeDotVelocity = glm::dot(edge, velocity); 
      edgeDotBaseToVertex = glm::dot(edge, baseToVertex); 
      // Calculate parameters for equation 
      a = edgeSquaredLength * -velocitySquaredLength + 
      edgeDotVelocity*edgeDotVelocity; 
      b = edgeSquaredLength*(2*glm::dot(velocity, baseToVertex)) - 
      2.0*edgeDotVelocity*edgeDotBaseToVertex; 
      c = edgeSquaredLength*(1 - glm::length(baseToVertex)) + 
      edgeDotBaseToVertex*edgeDotBaseToVertex; 
      if (getLowestRoot(a, b, c, t, &newT)) { 
       float f = (edgeDotVelocity*newT - edgeDotBaseToVertex)/
       edgeSquaredLength; 
       if (f >= 0.0 && f <= 1.0) { 
        t = newT; 
        foundCollison = true; 
        collisionPoint = p2 + f*edge; 
        std::cout << "p2 p3\n"; 
       } 
      } 
      // p3 -> p1: 
      edge = p1 - p3; 
      baseToVertex = p3 - base; 
      edgeSquaredLength = glm::length(edge); 
      edgeDotVelocity = glm::dot(edge, velocity); 
      edgeDotBaseToVertex = glm::dot(edge, baseToVertex); 
      // Calculate parameters for equation 
      a = edgeSquaredLength * -velocitySquaredLength + 
      edgeDotVelocity*edgeDotVelocity; 
      b = edgeSquaredLength*(2*glm::dot(velocity, baseToVertex)) - 
      2.0*edgeDotVelocity*edgeDotBaseToVertex; 
      c = edgeSquaredLength*(1 - glm::length(baseToVertex)) + 
      edgeDotBaseToVertex*edgeDotBaseToVertex; 
      if (getLowestRoot(a, b, c, t, &newT)) { 
       float f = (edgeDotVelocity*newT - edgeDotBaseToVertex)/
       edgeSquaredLength; 
       if (f >= 0.0 && f <= 1.0) { 
        t = newT; 
        foundCollison = true; 
        collisionPoint = p3 + f*edge; 
        std::cout << "p3 p1\n"; 
       } 
      } 
     } 

     if (foundCollison) 
      std::cout << t << " t"; 
     return foundCollison;// Exit here since I'm not using collision response yet. 


     // Set result: 
     if (foundCollison == true) { 
     // distance to collision: ’t’ is time of collision 
      float distToCollision = t * colPackage->velocity.length(); 
      // Does this triangle qualify for the closest hit? 
      // it does if it’s the first hit or the closest 
      if (colPackage->foundCollision == false || 
      distToCollision < colPackage->nearestDistance) { 
      // Collision information nessesary for sliding 
       colPackage->nearestDistance = distToCollision; 
       colPackage->intersectionPoint = collisionPoint; 
       colPackage->foundCollision = true; 
      } 
     } 
    } // if not backface 
    return false; 
} 

我假設在文件中提供的代碼實際上有效。人們似乎在Kasper的論文中取得了成功。不幸的不是我。

到目前爲止,我已經試過是:

  • 再審現在執行它兩次(如果我的地方犯了一個錯誤)。
  • 嘗試了碰撞檢測的單獨部分,找出造成問題的原因。

現在我只是出於想法,一切似乎都對我正確,但它仍然給我誤報。

回答

0

發現問題:

我使用GLM ::長度而不是返回squaredlength的函數。 這是造成誤報。