pastebin - collaborative debugging

pastebin is a collaborative debugging tool allowing you to share and modify code snippets while chatting on IRC, IM or a message board.

This site is developed to XHTML and CSS2 W3C standards. If you see this paragraph, your browser does not support those standards and you need to upgrade. Visit WaSP for a variety of options.

C# pastebin - collaborative debugging tool View Help


Posted by XNA Collision Detection on Thu 5 Nov 21:10
report abuse | download | new post

  1.        private bool GetLowestRoot(float a, float b, float c, float maxR, ref float root)
  2.         {
  3.             // Check if a solution exists
  4.             float determinant = b * b - 4.0f * a * c;
  5.  
  6.             // If determinant is negative it means no solutions.
  7.             if (determinant < 0.0f) return false;
  8.  
  9.             // calculate the two roots: (if determinant == 0 then
  10.             // x1==x2 but let’s disregard that slight optimization)
  11.             float sqrtD = (float)Math.Sqrt(determinant);
  12.             float r1 = (-b - sqrtD) / (2 * a);
  13.             float r2 = (-b + sqrtD) / (2 * a);
  14.  
  15.             // Sort so x1 <= x2
  16.             if (r1 > r2)
  17.             {
  18.                 float temp = r2;
  19.                 r2 = r1;
  20.                 r1 = temp;
  21.             }
  22.            
  23.             // Get lowest root:
  24.             if (r1 > 0 && r1 < maxR)
  25.             {
  26.                 root = r1;
  27.                 return true;
  28.             }
  29.            
  30.             // It is possible that we want x2 - this can happen
  31.             // if x1 < 0
  32.             if (r2 > 0 && r2 < maxR)
  33.             {
  34.                 root = r2;
  35.                 return true;
  36.             }
  37.  
  38.             // No (valid) solutions
  39.             return false;
  40.         }
  41.  
  42.  
  43.         /// <summary>
  44.         /// Check point P to see if it is within the triangle A B C.
  45.         /// </summary>
  46.         private bool CheckPointInTriangle(Vector3 P, Vector3 A, Vector3 B, Vector3 C)
  47.         {
  48.             //Distance Vectors        
  49.             Vector3 p1 = C - A;
  50.             Vector3 p2 = B - A;
  51.             Vector3 p3 = P - A;
  52.  
  53.             //Get all the Vector Dots
  54.             float dot11 = Vector3.Dot(p1, p1);
  55.             float dot12 = Vector3.Dot(p1, p2);
  56.             float dot13 = Vector3.Dot(p1, p3);
  57.             float dot22 = Vector3.Dot(p2, p2);
  58.             float dot23 = Vector3.Dot(p2, p3);
  59.  
  60.             //Barycentric Co-ordinates
  61.             float invDenom = 1 / (dot11 * dot22 - dot12 * dot12);
  62.             float u = (dot22 * dot13 - dot12 * dot23) * invDenom;
  63.             float v = (dot11 * dot23 - dot12 * dot13) * invDenom;
  64.  
  65.             // Is 'P' in the Triangle?
  66.             return (u > 0) && (v > 0) && (u + v < 1);
  67.         }
  68.  
  69.  
  70.         /// <summary>
  71.         /// Check a triangle for collision. Assumes p1,p2 and p3 are given in ellipsoid space.
  72.         /// </summary>
  73.         private void CheckTriangle(CollisionPacket colPackage, Vector3 p1, Vector3 p2, Vector3 p3)
  74.         {
  75.             // Make the plane containing this triangle.
  76.             tPlane trianglePlane = new tPlane(p1, p2, p3);
  77.  
  78.             // Is triangle front-facing to the velocity vector?
  79.             // We only check front-facing triangles
  80.             // (your choice of course)
  81.  
  82.             //if (trianglePlane.isFrontFacingTo(colPackage.normalizedVelocity))
  83.             if(true)
  84.             {
  85.                 // Get interval of plane intersection:
  86.                 double t0, t1;
  87.                 bool embeddedInPlane = false;
  88.  
  89.                 // Calculate the signed distance from sphere
  90.                 // position to triangle plane
  91.                 double signedDistToTrianglePlane = trianglePlane.signedDistanceTo(colPackage.basePoint);
  92.  
  93.                 // cache this as we’re going to use it a few times below:
  94.                 float normalDotVelocity = Vector3.Dot(trianglePlane.normal, colPackage.velocity);
  95.  
  96.                 // if sphere is travelling parrallel to the plane:
  97.                 if (normalDotVelocity == 0.0f){
  98.                     if (Math.Abs(signedDistToTrianglePlane) >= 1.0f){
  99.                         // Sphere is not embedded in plane.
  100.                         // No collision possible:
  101.                         return;
  102.                     }else{
  103.                         // sphere is embedded in plane.
  104.                         // It intersects in the whole range [0..1]
  105.                         embeddedInPlane = true;
  106.                         t0 = 0.0;
  107.                         t1 = 1.0;
  108.                     }
  109.                 }else{
  110.                     // N dot D is not 0. Calculate intersection interval:
  111.                     t0 = (-1.0 - signedDistToTrianglePlane) / normalDotVelocity;
  112.                     t1 = (1.0 - signedDistToTrianglePlane) / normalDotVelocity;
  113.                    
  114.                     // Swap so t0 < t1
  115.                     if (t0 > t1){
  116.                         double temp = t1;
  117.                         t1 = t0;
  118.                         t0 = temp;
  119.                     }
  120.                    
  121.                     // Check that at least one result is within range:
  122.                     if (t0 > 1.0f || t1 < 0.0f){
  123.                         // Both t values are outside values [0,1]
  124.                         // No collision possible:
  125.                         return;
  126.                     }
  127.  
  128.                     // Clamp to [0,1]
  129.                     if (t0 < 0.0) t0 = 0.0;
  130.                     if (t1 < 0.0) t1 = 0.0;
  131.                     if (t0 > 1.0) t0 = 1.0;
  132.                     if (t1 > 1.0) t1 = 1.0;
  133.                 }
  134.  
  135.                 // OK, at this point we have two time values t0 and t1
  136.                 // between which the swept sphere intersects with the
  137.                 // triangle plane. If any collision is to occur it must
  138.                 // happen within this interval.
  139.                 Vector3 collisionPoint = new Vector3();
  140.                 bool foundCollison = false;
  141.                 float t = 1.0f;
  142.  
  143.                 // First we check for the easy case - collision inside
  144.                 // the triangle. If this happens it must be at time t0
  145.                 // as this is when the sphere rests on the front side
  146.                 // of the triangle plane. Note, this can only happen if
  147.                 // the sphere is not embedded in the triangle plane.
  148.                 if (!embeddedInPlane)
  149.                 {
  150.                     Vector3 planeIntersectionPoint;
  151.  
  152.                     planeIntersectionPoint =
  153.                         (trianglePlane.isFrontFacingTo(colPackage.normalizedVelocity)) ?
  154.                             (colPackage.basePoint - trianglePlane.normal) :
  155.                             (colPackage.basePoint + trianglePlane.normal);
  156.                     planeIntersectionPoint += Vector3.Multiply(colPackage.velocity, (float)t0);
  157.  
  158.  
  159.  
  160.                     if (CheckPointInTriangle(planeIntersectionPoint, p1, p2, p3))
  161.                     {
  162.                         foundCollison = true;
  163.                         t = (float)t0;
  164.                         //myDebug.write(trianglePlane.isFrontFacingTo(colPackage.normalizedVelocity).ToString() + " - " + colPackage.normalizedVelocity.ToString());
  165.                         collisionPoint = planeIntersectionPoint;
  166.                         //myDebug.writeVector("Found collision in a plane: ", planeIntersectionPoint * colPackage.eRadius);
  167.                         //myDebug.writeVector("Base Point: ", colPackage.basePoint * colPackage.eRadius);
  168.                         colPackage.collisionTri.v1 = p1;
  169.                         colPackage.collisionTri.v2 = p2;
  170.                         colPackage.collisionTri.v3 = p3;
  171.                     }
  172.                 }
  173.  
  174.                 // if we haven’t found a collision already we’ll have to
  175.                 // sweep sphere against points and edges of the triangle.
  176.                 // Note: A collision inside the triangle (the check above)
  177.                 // will always happen before a vertex or edge collision!
  178.                 // This is why we can skip the swept test if the above
  179.                 // gives a collision!
  180.                 if (foundCollison == false)
  181.                 {
  182.                     // some commonly used terms:
  183.                     Vector3 velocity = colPackage.velocity;
  184.                     Vector3 basePoint = colPackage.basePoint;
  185.                     float velocitySquaredLength = velocity.LengthSquared();
  186.                     float a, b, c; // Params for equation
  187.                     float newT = 0.0f;
  188.  
  189.                     // For each vertex or edge a quadratic equation have to
  190.                     // be solved. We parameterize this equation as
  191.                     // a*t^2 + b*t + c = 0 and below we calculate the
  192.                     // parameters a,b and c for each test.
  193.                     // Check against points:
  194.                     a = velocitySquaredLength;
  195.  
  196.                     // P1
  197.                     b = 2 * Vector3.Dot(velocity, basePoint - p1);
  198.                     c = (p1 - basePoint).LengthSquared() - 1.0f;
  199.                     if (GetLowestRoot(a, b, c, t, ref newT))
  200.                     {
  201.                         t = newT;
  202.                         foundCollison = true;
  203.                         collisionPoint = p1;
  204.                         myDebug.writeVector("Found collision in a p1 corner:", p1 * colPackage.eRadius);
  205.                     }
  206.  
  207.                     // P2
  208.                     b = 2 * Vector3.Dot(velocity, basePoint - p2);
  209.                     c = (p2 - basePoint).LengthSquared() - 1.0f;
  210.                     if (GetLowestRoot(a, b, c, t, ref newT))
  211.                     {
  212.                         t = newT;
  213.                         foundCollison = true;
  214.                         collisionPoint = p2;
  215.                         myDebug.writeVector("Found collision in a p2 corner: ", p2 * colPackage.eRadius);
  216.                     }
  217.  
  218.                     // P3
  219.                     b = 2 * Vector3.Dot(velocity, basePoint - p3);
  220.                     c = (p3 - basePoint).LengthSquared() - 1.0f;
  221.                     if (GetLowestRoot(a, b, c, t, ref newT))
  222.                     {
  223.                         t = newT;
  224.                         foundCollison = true;
  225.                         collisionPoint = p3;
  226.                         myDebug.writeVector("Found collision in a p3 corner: ", p3 * colPackage.eRadius);
  227.                     }
  228.  
  229.                     //------------------------------
  230.                     // Check agains edges:
  231.                     //------------------------------
  232.  
  233.                     // p1 -> p2:
  234.                     //------------------------------
  235.                     Vector3 edge = p2 - p1;
  236.                     Vector3 baseToVertex = p1 - basePoint;
  237.                     float edgeSquaredLength = edge.LengthSquared();
  238.                     float edgeDotVelocity = Vector3.Dot(edge, velocity);
  239.                     float edgeDotBaseToVertex = Vector3.Dot(edge, baseToVertex);
  240.  
  241.                     // Calculate parameters for equation
  242.                     a = (edgeSquaredLength * -velocitySquaredLength) + (edgeDotVelocity * edgeDotVelocity);
  243.                     b = edgeSquaredLength * (2 * Vector3.Dot(velocity, baseToVertex)) - (2 * edgeDotVelocity * edgeDotBaseToVertex);
  244.                     c = edgeSquaredLength * (1 - baseToVertex.LengthSquared()) + (edgeDotBaseToVertex * edgeDotBaseToVertex);
  245.  
  246.                     // Does the swept sphere collide against infinite edge?
  247.                     if (GetLowestRoot(a, b, c, t, ref newT))
  248.                     {
  249.                         // Check if intersection is within line segment:
  250.                         float f = (edgeDotVelocity * newT - edgeDotBaseToVertex) / edgeSquaredLength;
  251.                         if (f >= 0.0 && f <= 1.0)
  252.                         {
  253.                             // intersection took place within segment.
  254.                             t = newT;
  255.                             foundCollison = true;
  256.                             collisionPoint = p1 + (f * edge);
  257.                             myDebug.writeVector("Found collision on the p1 - p2 edge:", collisionPoint * colPackage.eRadius);
  258.                         }
  259.                     }
  260.  
  261.                     // p2 -> p3:
  262.                     //------------------------------
  263.                     edge = p3 - p2;
  264.                     baseToVertex = p2 - basePoint;
  265.                     edgeSquaredLength = edge.LengthSquared();
  266.                     edgeDotVelocity = Vector3.Dot(edge, velocity);
  267.                     edgeDotBaseToVertex = Vector3.Dot(edge, baseToVertex);
  268.  
  269.                     a = (edgeSquaredLength * -velocitySquaredLength) + (edgeDotVelocity * edgeDotVelocity);
  270.                     b = edgeSquaredLength * (2 * Vector3.Dot(velocity, baseToVertex)) - (2.0f * edgeDotVelocity * edgeDotBaseToVertex);
  271.                     c = edgeSquaredLength * (1 - baseToVertex.LengthSquared()) + (edgeDotBaseToVertex * edgeDotBaseToVertex);
  272.  
  273.                     if (GetLowestRoot(a, b, c, t, ref newT))
  274.                     {
  275.                         float f = (edgeDotVelocity * newT - edgeDotBaseToVertex) / edgeSquaredLength;
  276.                         if (f >= 0.0 && f <= 1.0)
  277.                         {
  278.                             t = newT;
  279.                             foundCollison = true;
  280.                             collisionPoint = p2 + (f * edge);
  281.                             myDebug.writeVector("Found collision on the p2 - p3 edge:", collisionPoint * colPackage.eRadius);
  282.                         }
  283.                     }
  284.  
  285.                     // p3 -> p1:
  286.                     //------------------------------
  287.                     edge = p1 - p3;
  288.                     baseToVertex = p3 - basePoint;
  289.                     edgeSquaredLength = edge.LengthSquared();
  290.                     edgeDotVelocity = Vector3.Dot(edge, velocity);
  291.                     edgeDotBaseToVertex = Vector3.Dot(edge, baseToVertex);
  292.  
  293.                     a = edgeSquaredLength * -velocitySquaredLength + (edgeDotVelocity * edgeDotVelocity);
  294.                     b = edgeSquaredLength * (2 * Vector3.Dot(velocity, baseToVertex)) - (2.0f * edgeDotVelocity * edgeDotBaseToVertex);
  295.                     c = edgeSquaredLength * (1 - baseToVertex.LengthSquared()) + (edgeDotBaseToVertex * edgeDotBaseToVertex);
  296.  
  297.                     if (GetLowestRoot(a, b, c, t, ref newT))
  298.                     {
  299.                         float f = (edgeDotVelocity * newT - edgeDotBaseToVertex) / edgeSquaredLength;
  300.                         if (f >= 0.0 && f <= 1.0)
  301.                         {
  302.                             t = newT;
  303.                             foundCollison = true;
  304.                             collisionPoint = p3 + (f * edge);
  305.                             myDebug.writeVector("Found collision on the p3 - p1 edge:", collisionPoint * colPackage.eRadius);
  306.                         }
  307.                     }
  308.                 }//Emd If Collision Found
  309.  
  310.                 //------------------------------
  311.                 // Set result:
  312.                 //------------------------------
  313.                 if (foundCollison == true)
  314.                 {
  315.                     // distance to collision: ’t’ is time of collision
  316.                     float distToCollision = t * colPackage.velocity.Length();
  317.                    
  318.                     // Does this triangle qualify for the closest hit?
  319.                     // it does if it’s the first hit or the closest
  320.                     if (colPackage.foundCollision == false || distToCollision < colPackage.nearestDistance){
  321.  
  322.                         // Collision information nessesary for sliding
  323.                         colPackage.nearestDistance = distToCollision;
  324.                         colPackage.intersectionPoint = collisionPoint;
  325.                         colPackage.foundCollision = true;
  326.                         colPackage.t = t;
  327.                     }
  328.                 }
  329.             }//End if not backface
  330.         }
  331.  
  332.  
  333.         /// <summary>
  334.         ///
  335.         /// </summary>
  336.         private Vector3 CollideWithWorld(Vector3 pos, Vector3 vel)
  337.         {
  338.  
  339.             float unitsPerMeter = 1000.0f; //Set this to match application scale.
  340.             // All hard-coded distances in this function is
  341.             // scaled to fit the setting above..
  342.             float unitScale = unitsPerMeter / 100.0f;
  343.             float veryCloseDistance = 0.005f * unitScale;
  344.  
  345.             // do we need to worry?
  346.             if (collisionRecursionDepth > 5)
  347.                 return pos;
  348.  
  349.             // Ok, we need to worry:
  350.             collisionPackage.velocity = vel;
  351.             collisionPackage.normalizedVelocity = vel;
  352.             collisionPackage.normalizedVelocity.Normalize();
  353.             collisionPackage.basePoint = pos;
  354.             collisionPackage.foundCollision = false;
  355.  
  356.             //Check all triangles for collision.
  357.             foreach (TriangleVertexIndice t in idcs)
  358.             {
  359.                 CheckTriangle(collisionPackage,
  360.                                         vtcs[t.i0] / collisionPackage.eRadius,
  361.                                         vtcs[t.i1] / collisionPackage.eRadius,
  362.                                         vtcs[t.i2] / collisionPackage.eRadius);
  363.                 if (collisionPackage.foundCollision)
  364.                 {
  365.                     //Console.WriteLine("Collision Found! "+ collisionPackage.intersectionPoint.ToString());
  366.                     collisionPoint.tri = collisionPackage.collisionTri;
  367.                     collisionPoint.tri.v1 *= collisionPackage.eRadius;
  368.                     collisionPoint.tri.v2 *= collisionPackage.eRadius;
  369.                     collisionPoint.tri.v3 *= collisionPackage.eRadius;
  370.                     collisionPoint.colpack = collisionPackage;
  371.                     //break;
  372.  
  373.                 }
  374.             }
  375.  
  376.             // If no collision we just move along the velocity
  377.             if (collisionPackage.foundCollision == false)
  378.             {
  379.                 return pos + vel;
  380.             }
  381.  
  382.             // *** Collision occured ***
  383.             // The original destination point
  384.             Vector3 destinationPoint = pos + vel;
  385.             Vector3 newBasePoint = pos;
  386.  
  387.             // only update if we are not already very close
  388.             // and if so we only move very close to intersection..not
  389.             // to the exact spot.
  390.  
  391.             if (collisionPackage.nearestDistance >= veryCloseDistance)
  392.             {
  393.                 Vector3 V = vel;
  394.                 V.Normalize();
  395.                 V = Vector3.Multiply(V, (float)(collisionPackage.nearestDistance - veryCloseDistance));
  396.                 //V.SetLength = (collisionPackage.nearestDistance - veryCloseDistance);
  397.  
  398.                 newBasePoint = collisionPackage.basePoint + V;
  399.  
  400.                 // Adjust polygon intersection point (so sliding
  401.                 // plane will be unaffected by the fact that we
  402.                 // move slightly less than collision tells us)
  403.                 V.Normalize();
  404.                 collisionPackage.intersectionPoint -= (veryCloseDistance * V);
  405.             }
  406.  
  407.             // Determine the sliding plane
  408.             Vector3 slidePlaneOrigin = collisionPackage.intersectionPoint;
  409.             Vector3 slidePlaneNormal = newBasePoint - collisionPackage.intersectionPoint;
  410.             slidePlaneNormal.Normalize();
  411.             tPlane slidingPlane = new tPlane(slidePlaneOrigin, slidePlaneNormal);
  412.  
  413.             // Again, sorry about formatting.. but look carefully ;)
  414.             Vector3 newDestinationPoint = destinationPoint - Vector3.Multiply(slidePlaneNormal, (float)slidingPlane.signedDistanceTo(destinationPoint));
  415.  
  416.             // Generate the slide vector, which will become our new velocity vector for the next iteration
  417.             Vector3 newVelocityVector = newDestinationPoint - collisionPackage.intersectionPoint;
  418.  
  419.             // Recurse: Don't recurse if the new velocity is very small
  420.             if (newVelocityVector.Length() < veryCloseDistance)
  421.             {
  422.                 return newBasePoint;
  423.             }
  424.  
  425.             collisionRecursionDepth++;
  426.             return CollideWithWorld(newBasePoint, newVelocityVector);
  427.         }
  428.  
  429.  
  430.         /// <summary>
  431.         /// Conversion to eSpace for collideWithWorld.
  432.         /// </summary>
  433.         public Vector3 CollideAndSlide(Vector3 pos, Vector3 vel, Vector3 gravity)
  434.         {
  435.  
  436.  
  437.             // Do collision detection:
  438.             collisionPackage.R3Position = pos;
  439.             collisionPackage.R3Position.Y += collisionPackage.eRadius.Y;
  440.             collisionPackage.R3Velocity = vel;
  441.  
  442.             // calculate position and velocity in eSpace
  443.             Vector3 eSpacePosition = collisionPackage.R3Position / collisionPackage.eRadius;
  444.             Vector3 eSpaceVelocity = collisionPackage.R3Velocity / collisionPackage.eRadius;
  445.  
  446.             // Iterate until we have our final position.
  447.             collisionRecursionDepth = 0;
  448.             Vector3 finalPosition = CollideWithWorld(eSpacePosition, eSpaceVelocity);
  449.            
  450.             // [gravity]
  451.             collisionPackage.R3Position = finalPosition * collisionPackage.eRadius;
  452.             collisionPackage.R3Velocity = gravity;
  453.             eSpaceVelocity = gravity / collisionPackage.eRadius;
  454.             collisionRecursionDepth = 0;
  455.             finalPosition = CollideWithWorld(finalPosition, eSpaceVelocity);
  456.             // [/gravity]
  457.  
  458.            
  459.             // Convert final result back to R3:
  460.             finalPosition = finalPosition * collisionPackage.eRadius;
  461.             finalPosition.Y -= collisionPackage.eRadius.Y;
  462.  
  463.             // Move the entity (application specific function)
  464.             return finalPosition;
  465.         }

Submit a correction or amendment below (click here to make a fresh posting)
After submitting an amendment, you'll be able to view the differences between the old and new posts easily.

Syntax highlighting:

To highlight particular lines, prefix each line with @@


Remember me so that I can delete my post