home *** CD-ROM | disk | FTP | other *** search
/ Programming a Multiplayer FPS in DirectX / Programming a Multiplayer FPS in DirectX (Companion CD).iso / Source / Chapter 10 / Engine / CollisionDetection.h < prev    next >
Encoding:
C/C++ Source or Header  |  2004-10-01  |  24.4 KB  |  592 lines

  1. //-----------------------------------------------------------------------------
  2. // Provides basic collision detection in a 3D environment that includes both
  3. // static geometry and dynamic objects.
  4. //
  5. // Note: This uses an adaptation of the algorithm from the Improved Collision
  6. //       Detection and Response article written by Kasper Fauerby.
  7. //
  8. // Programming a Multiplayer First Person Shooter in DirectX
  9. // Copyright (c) 2004 Vaughan Young
  10. //-----------------------------------------------------------------------------
  11. #ifndef COLLISION_H
  12. #define COLLISION_H
  13.  
  14. //-----------------------------------------------------------------------------
  15. // Collision Data Structure
  16. //-----------------------------------------------------------------------------
  17. struct CollisionData
  18. {
  19.     float scale; // Scale used by thge calling scene manager.
  20.     float elapsed; // Elapsed time for the current frame.
  21.     unsigned long frameStamp; // Current frame stamp according to the scene manager.
  22.  
  23.     SceneObject *object; // Pointer to the object to perform collision detection with.
  24.  
  25.     D3DXVECTOR3 translation; // Translation in ellipsoid space.
  26.     D3DXVECTOR3 velocity; // Velocity in ellipsoid space.
  27.     D3DXVECTOR3 normalizedVelocity; // Normalized velocity in ellipsoid space.
  28.  
  29.     D3DXVECTOR3 gravity; // Gravity vector, which will be converted to ellipsoid space.
  30.  
  31.     bool collisionFound; // Indicates if a collision has been found.
  32.     float distance; // Distance to the point of collision.
  33.     D3DXVECTOR3 intersection; // Actual intersection point where the collision occured.
  34. };
  35.  
  36. //-----------------------------------------------------------------------------
  37. // Returns the lowest root of a quadratic equation.
  38. //-----------------------------------------------------------------------------
  39. inline float GetLowestRoot( float a, float b, float c, float max )
  40. {
  41.     // Calculate the determinant, then get the square root of it if it's valid.
  42.     float determinant = b * b - a * c;
  43.     if( determinant < 0.0f )
  44.         return 0.0f;
  45.     determinant = (float)sqrt( determinant );
  46.  
  47.     // Calculate the first root and ensure it is within the bounds.
  48.     float root1 = ( b + determinant ) / a;
  49.     if( root1 <= 0.0f || root1 > max )
  50.         root1 = max + 1.0f;
  51.  
  52.     // Calculate the second root and ensure it is within the bounds.
  53.     float root2 = ( b - determinant ) / a;
  54.     if( root2 <= 0.0f || root2 > max )
  55.         root2 = max + 1.0f;
  56.  
  57.     // Get the lowest of the two roots.
  58.     float root = min( root1, root2 );
  59.  
  60.     // Ensure the root is valid.
  61.     if( root == max + 1.0f )
  62.         return 0.0f;
  63.  
  64.     return root;
  65. }
  66.  
  67. //-----------------------------------------------------------------------------
  68. // Checks a single face for intersection.
  69. //-----------------------------------------------------------------------------
  70. inline void CheckFace( CollisionData *data, D3DXVECTOR3 vertex0, D3DXVECTOR3 vertex1, D3DXVECTOR3 vertex2 )
  71. {
  72.     // Create a plane from the face's vertices.
  73.     D3DXPLANE plane;
  74.     D3DXPlaneFromPoints( &plane, &vertex0, &vertex1, &vertex2 );
  75.  
  76.     // Get the angle between the plane's normal and the velocity vector.
  77.     float angle = D3DXPlaneDotNormal( &plane, &data->normalizedVelocity );
  78.  
  79.     // Ensure the plane is facing the velocity vector (i.e. ignore back faces).
  80.     if( angle > 0.0f )
  81.         return;
  82.  
  83.     // Get the plane's normal vector.
  84.     D3DXVECTOR3 planeNormal;
  85.     D3DXVec3Cross( &planeNormal, &( vertex0 - vertex1 ), &( vertex1 - vertex2 ) );
  86.     D3DXVec3Normalize( &planeNormal, &planeNormal );
  87.  
  88.     // Calculate the signed distance from sphere's translation to plane.
  89.     float signedPlaneDistance = D3DXVec3Dot( &data->translation, &planeNormal ) + plane.d;
  90.  
  91.     // Get interval of plane intersection
  92.     float time0, time1;
  93.     bool embedded = false;
  94.  
  95.     // Cache this as we're going to use it a few times below
  96.     float normalDotVelocity = D3DXVec3Dot( &planeNormal, &data->velocity );
  97.  
  98.     // Check if the sphere is travelling parallel to the plane.
  99.     if( normalDotVelocity == 0.0f )
  100.     {
  101.         // If the sphere is not embedded in the plane, then it cannot collide.
  102.         if( fabs( signedPlaneDistance ) >= 1.0f )
  103.             return;
  104.         else
  105.         {
  106.             // The sphere is embedded in plane, therefore it will collide
  107.             // for the entire time frame.
  108.             embedded = true;
  109.             time0 = 0.0f;
  110.             time1 = 1.0f;
  111.         }
  112.     }
  113.     else
  114.     {
  115.         // Calculate the time frame of intersection.
  116.         time0 = ( -1.0f - signedPlaneDistance ) / normalDotVelocity;
  117.         time1 = ( 1.0f - signedPlaneDistance ) / normalDotVelocity;
  118.  
  119.         // Ensure time0 is less than time1.
  120.         if( time0 > time1 )
  121.         {
  122.             float swap = time1;
  123.             time1 = time0;
  124.             time0 = swap;
  125.         }
  126.  
  127.         // If the intersection time frame is out of range, then it cannot collide.
  128.         if( time0 > 1.0f || time1 < 0.0f )
  129.             return;
  130.  
  131.         // Normalize the time frame.
  132.         if( time0 < 0.0f ) time0 = 0.0f;
  133.         if( time1 < 0.0f ) time1 = 0.0f;
  134.         if( time0 > 1.0f ) time0 = 1.0f;
  135.         if( time1 > 1.0f ) time1 = 1.0f;
  136.     }
  137.  
  138.     // Variables used for tracking if an intersection occured, where it happened, and when.
  139.     bool intersectFound = false;
  140.     D3DXVECTOR3 intersection;
  141.     float intersectTime = 1.0f;
  142.  
  143.     // Check if the sphere is embedded in the plane.
  144.     if( embedded == false )
  145.     {
  146.         // Get the plane intersection point at time0.
  147.         D3DXVECTOR3 planeIntersectionPoint = ( data->translation - planeNormal ) + data->velocity * time0;
  148.  
  149.         // Get the vectors of two of the face's edges.
  150.         D3DXVECTOR3 edge0 = vertex1 - vertex0;
  151.         D3DXVECTOR3 edge1 = vertex2 - vertex0;
  152.  
  153.         // Get the angles of the edges and combine them.
  154.         float angle0 = D3DXVec3Dot( &edge0, &edge0 );
  155.         float angle1 = D3DXVec3Dot( &edge0, &edge1 );
  156.         float angle2 = D3DXVec3Dot( &edge1, &edge1 );
  157.         float combined = ( angle0 * angle2 ) - ( angle1 * angle1 );
  158.  
  159.         // Get the split angles between the two edges.
  160.         D3DXVECTOR3 split = planeIntersectionPoint - vertex0;
  161.         float splitAngle0 = D3DXVec3Dot( &split, &edge0 );
  162.         float splitAngle1 = D3DXVec3Dot( &split, &edge1 );
  163.  
  164.         float x = ( splitAngle0 * angle2 ) - ( splitAngle1 * angle1 );
  165.         float y = ( splitAngle1 * angle0 ) - ( splitAngle0 * angle1 );
  166.         float z = x + y - combined;
  167.  
  168.         // Take the bitwise AND of z and the complement of the inclusive OR of x and y,
  169.         // then bitwise AND the result with 0x80000000 and return it. A bitwise result
  170.         // of zero equals false, while any other value equals true.
  171.         if( ( ( (unsigned int&)z & ~( (unsigned int&)x | (unsigned int&)y ) ) & 0x80000000 ) != 0 )
  172.         {
  173.             intersectFound = true;
  174.             intersection = planeIntersectionPoint;
  175.             intersectTime = time0;
  176.         }
  177.     }
  178.  
  179.     // Check if a collision has been found yet.
  180.     if( intersectFound == false )
  181.     {
  182.         // Get the squared length of the velocity vector.
  183.         float squaredVelocityLength = D3DXVec3LengthSq( &data->velocity );
  184.  
  185.         // A quadratic equation has to be solved for each vertex and edge in the face.
  186.         // The following variables are used to build each quadratic equation.
  187.         float a, b, c;
  188.  
  189.         // Used for storing the result of each quadratic equation.
  190.         float newTime;
  191.  
  192.         // First check againts the vertices.
  193.         a = squaredVelocityLength;
  194.  
  195.         // Check vertex 0.
  196.         b = 2.0f * D3DXVec3Dot( &data->velocity, &( data->translation - vertex0 ) );
  197.         c = D3DXVec3LengthSq( &( vertex0 - data->translation ) ) - 1.0f;
  198.         if( newTime = GetLowestRoot( a, b, c, intersectTime ) > 0.0f )
  199.         {
  200.             intersectFound = true;
  201.             intersection = vertex0;
  202.             intersectTime = newTime;
  203.         }
  204.  
  205.         // Check vertex 1.
  206.         b = 2.0f * D3DXVec3Dot( &data->velocity, &( data->translation - vertex1 ) );
  207.         c = D3DXVec3LengthSq( &( vertex1 - data->translation ) ) - 1.0f;
  208.         if( newTime = GetLowestRoot( a, b, c, intersectTime ) > 0.0f )
  209.         {
  210.             intersectFound = true;
  211.             intersection = vertex1;
  212.             intersectTime = newTime;
  213.         }
  214.  
  215.         // Check vertex 2.
  216.         b = 2.0f * D3DXVec3Dot( &data->velocity, &( data->translation - vertex2 ) );
  217.         c = D3DXVec3LengthSq( &( vertex2 - data->translation ) ) - 1.0f;
  218.         if( newTime = GetLowestRoot( a, b, c, intersectTime ) > 0.0f )
  219.         {
  220.             intersectFound = true;
  221.             intersection = vertex2;
  222.             intersectTime = newTime;
  223.         }
  224.  
  225.         // Check the edge from vertex0 to vertex1.
  226.         D3DXVECTOR3 edge = vertex1 - vertex0;
  227.         D3DXVECTOR3 vectorSphereVertex = vertex0 - data->translation;
  228.         float squaredEdgeLength = D3DXVec3LengthSq( &edge );
  229.         float angleEdgeVelocity = D3DXVec3Dot( &edge, &data->velocity );
  230.         float angleEdgeSphereVertex = D3DXVec3Dot( &edge, &vectorSphereVertex );
  231.  
  232.         // Get the parameters for the quadratic equation.
  233.         a = squaredEdgeLength * -squaredVelocityLength + angleEdgeVelocity * angleEdgeVelocity;
  234.         b = squaredEdgeLength * ( 2.0f * D3DXVec3Dot( &data->velocity, &vectorSphereVertex ) ) - 2.0f * angleEdgeVelocity * angleEdgeSphereVertex;
  235.         c = squaredEdgeLength * ( 1.0f - D3DXVec3LengthSq( &vectorSphereVertex ) ) + angleEdgeSphereVertex * angleEdgeSphereVertex;
  236.  
  237.         // Check if the sphere intersects the edge.
  238.         if( newTime = GetLowestRoot( a, b, c, intersectTime ) > 0.0f )
  239.         {
  240.             // Ensure the intersection occured within the edges bounds.
  241.             float point = ( angleEdgeVelocity * newTime - angleEdgeSphereVertex ) / squaredEdgeLength;
  242.             if( point >= 0.0f && point <= 1.0f )
  243.             {
  244.                 intersectFound = true;
  245.                 intersection = vertex0 + edge * point;
  246.                 intersectTime = newTime;
  247.             }
  248.         }
  249.  
  250.         // Check the edge from vertex1 to vertex2.
  251.         edge = vertex2 - vertex1;
  252.         vectorSphereVertex = vertex1 - data->translation;
  253.         squaredEdgeLength = D3DXVec3LengthSq( &edge );
  254.         angleEdgeVelocity = D3DXVec3Dot( &edge, &data->velocity );
  255.         angleEdgeSphereVertex = D3DXVec3Dot( &edge, &vectorSphereVertex );
  256.  
  257.         // Get the parameters for the quadratic equation.
  258.         a = squaredEdgeLength * -squaredVelocityLength + angleEdgeVelocity * angleEdgeVelocity;
  259.         b = squaredEdgeLength * ( 2.0f * D3DXVec3Dot( &data->velocity, &vectorSphereVertex ) ) - 2.0f * angleEdgeVelocity * angleEdgeSphereVertex;
  260.         c = squaredEdgeLength * ( 1.0f - D3DXVec3LengthSq( &vectorSphereVertex ) ) + angleEdgeSphereVertex * angleEdgeSphereVertex;
  261.  
  262.         // Check if the sphere intersects the edge.
  263.         if( newTime = GetLowestRoot( a, b, c, intersectTime ) > 0.0f )
  264.         {
  265.             // Ensure the intersection occured within the edges bounds.
  266.             float point = ( angleEdgeVelocity * newTime - angleEdgeSphereVertex ) / squaredEdgeLength;
  267.             if( point >= 0.0f && point <= 1.0f )
  268.             {
  269.                 intersectFound = true;
  270.                 intersection = vertex1 + edge * point;
  271.                 intersectTime = newTime;
  272.             }
  273.         }
  274.  
  275.         // Check the edge from vertex2 to vertex0.
  276.         edge = vertex0 - vertex2;
  277.         vectorSphereVertex = vertex2 - data->translation;
  278.         squaredEdgeLength = D3DXVec3LengthSq( &edge );
  279.         angleEdgeVelocity = D3DXVec3Dot( &edge, &data->velocity );
  280.         angleEdgeSphereVertex = D3DXVec3Dot( &edge, &vectorSphereVertex );
  281.  
  282.         // Get the parameters for the quadratic equation.
  283.         a = squaredEdgeLength * -squaredVelocityLength + angleEdgeVelocity * angleEdgeVelocity;
  284.         b = squaredEdgeLength * ( 2.0f * D3DXVec3Dot( &data->velocity, &vectorSphereVertex ) ) - 2.0f * angleEdgeVelocity * angleEdgeSphereVertex;
  285.         c = squaredEdgeLength * ( 1.0f - D3DXVec3LengthSq( &vectorSphereVertex ) ) + angleEdgeSphereVertex * angleEdgeSphereVertex;
  286.  
  287.         // Check if the sphere intersects the edge.
  288.         if( newTime = GetLowestRoot( a, b, c, intersectTime ) > 0.0f )
  289.         {
  290.             // Ensure the intersection occured within the edges bounds.
  291.             float point = ( angleEdgeVelocity * newTime - angleEdgeSphereVertex ) / squaredEdgeLength;
  292.             if( point >= 0.0f && point <= 1.0f )
  293.             {
  294.                 intersectFound = true;
  295.                 intersection = vertex2 + edge * point;
  296.                 intersectTime = newTime;
  297.             }
  298.         }
  299.     }
  300.  
  301.     // Check if an intersection occured.
  302.     if( intersectFound == true )
  303.     {
  304.         // Get the distance to the collision (i.e. time along the velocity vector).
  305.         float collisionDistance = intersectTime * D3DXVec3Length( &data->velocity );
  306.  
  307.         // Store the collision details, if necessary.
  308.         if( data->collisionFound == false || collisionDistance < data->distance )
  309.         {
  310.             data->distance = collisionDistance;
  311.             data->intersection = intersection;
  312.             data->collisionFound = true;
  313.         }
  314.     }
  315. }
  316.  
  317. //-----------------------------------------------------------------------------
  318. // Perfrom collision detection between the give object and the scene.
  319. //-----------------------------------------------------------------------------
  320. inline void CollideWithScene( CollisionData *data, Vertex *vertices, SceneFace *faces, unsigned long totalFaces, LinkedList< SceneObject > *objects, unsigned long recursion = 5 )
  321. {
  322.     // Calculate the epsilon distance (taking scale into account).
  323.     // The epsilon distance is a very short distance that is considered negligable.
  324.     float epsilon = 0.5f * data->scale;
  325.  
  326.     // Indicate that a collision has not been found.
  327.     data->collisionFound = false;
  328.  
  329.     // Get the normalized velocity vector.
  330.     D3DXVec3Normalize( &data->normalizedVelocity, &data->velocity );
  331.  
  332.     // Go through all of the faces.
  333.     D3DXVECTOR3 vertex0, vertex1, vertex2;
  334.     for( unsigned long f = 0; f < totalFaces; f++ )
  335.     {
  336.         // Skip this face if its material is set to ignore rays.
  337.         if( faces[f].renderCache->GetMaterial()->GetIgnoreRay() == true )
  338.             continue;
  339.  
  340.         // Get a copy of this face's vertices in ellipsoid space.
  341.         vertex0.x = vertices[faces[f].vertex0].translation.x / data->object->GetEllipsoidRadius().x;
  342.         vertex0.y = vertices[faces[f].vertex0].translation.y / data->object->GetEllipsoidRadius().y;
  343.         vertex0.z = vertices[faces[f].vertex0].translation.z / data->object->GetEllipsoidRadius().z;
  344.         vertex1.x = vertices[faces[f].vertex1].translation.x / data->object->GetEllipsoidRadius().x;
  345.         vertex1.y = vertices[faces[f].vertex1].translation.y / data->object->GetEllipsoidRadius().y;
  346.         vertex1.z = vertices[faces[f].vertex1].translation.z / data->object->GetEllipsoidRadius().z;
  347.         vertex2.x = vertices[faces[f].vertex2].translation.x / data->object->GetEllipsoidRadius().x;
  348.         vertex2.y = vertices[faces[f].vertex2].translation.y / data->object->GetEllipsoidRadius().y;
  349.         vertex2.z = vertices[faces[f].vertex2].translation.z / data->object->GetEllipsoidRadius().z;
  350.  
  351.         // Check for collision with this face.
  352.         CheckFace( data, vertex0, vertex1, vertex2 );
  353.     }
  354.  
  355.     // Create a list of hit ghost objects and a list of the distances to them.
  356.     LinkedList< SceneObject > *ghostHits = new LinkedList< SceneObject >;
  357.     LinkedList< float > *ghostDistances = new LinkedList< float >;
  358.  
  359.     // Variables used for the following object collision check.
  360.     D3DXVECTOR3 translation, velocity, vectorColliderObject, vectorObjectCollider, vectorObjectRadius;
  361.     float distToCollision, colliderRadius, objectRadius;
  362.  
  363.     // Go through the list of objects.
  364.     SceneObject *hitObject = NULL;
  365.     SceneObject *nextObject = objects->GetFirst();
  366.     while( nextObject != NULL )
  367.     {
  368.         // Skip this object if it is the collider. It can't check against itself.
  369.         if( nextObject != data->object )
  370.         {
  371.             // Get the translation and velocity of this object in ellipsoid space.
  372.             translation.x = nextObject->GetTranslation().x / data->object->GetEllipsoidRadius().x;
  373.             translation.y = nextObject->GetTranslation().y / data->object->GetEllipsoidRadius().y;
  374.             translation.z = nextObject->GetTranslation().z / data->object->GetEllipsoidRadius().z;
  375.             velocity.x = nextObject->GetVelocity().x / data->object->GetEllipsoidRadius().x;
  376.             velocity.y = nextObject->GetVelocity().y / data->object->GetEllipsoidRadius().y;
  377.             velocity.z = nextObject->GetVelocity().z / data->object->GetEllipsoidRadius().z;
  378.             velocity *= data->elapsed;
  379.  
  380.             // Get the normalized vectors from the collider to this object and vice versa.
  381.             D3DXVec3Normalize( &vectorColliderObject, &( translation - data->translation ) );
  382.             D3DXVec3Normalize( &vectorObjectCollider, &( data->translation - translation ) );
  383.  
  384.             // Calculate the radius of each ellipsoid in the direction to the other.
  385.             colliderRadius = D3DXVec3Length( &vectorColliderObject );
  386.             vectorObjectRadius.x = vectorObjectCollider.x * nextObject->GetEllipsoidRadius().x / data->object->GetEllipsoidRadius().x;
  387.             vectorObjectRadius.y = vectorObjectCollider.y * nextObject->GetEllipsoidRadius().y / data->object->GetEllipsoidRadius().y;
  388.             vectorObjectRadius.z = vectorObjectCollider.z * nextObject->GetEllipsoidRadius().z / data->object->GetEllipsoidRadius().z;
  389.             objectRadius = D3DXVec3Length( &vectorObjectRadius );
  390.  
  391.             // Check for collision between the two spheres.
  392.             if( IsSphereCollidingWithSphere( &distToCollision, data->translation, translation, velocity - data->velocity, colliderRadius + objectRadius ) == true )
  393.             {
  394.                 // Check if the hit object is a ghost.
  395.                 if( nextObject->GetGhost() == true )
  396.                 {
  397.                     // If both object's are allowed to register collisions, then store a pointer to the hit object and the distance to hit it.
  398.                     if( nextObject->GetIgnoreCollisions() == false && data->object->GetIgnoreCollisions() == false )
  399.                     {
  400.                         ghostHits->Add( nextObject );
  401.                         ghostDistances->Add( &distToCollision );
  402.                     }
  403.                 }
  404.                 else
  405.                 {
  406.                     // Store the collision details, if necessary.
  407.                     if( data->collisionFound == false || distToCollision < data->distance )
  408.                     {
  409.                         data->distance = distToCollision;
  410.                         data->intersection = data->normalizedVelocity * distToCollision;
  411.                         data->collisionFound = true;
  412.  
  413.                         // Store a pointer to the hit object.
  414.                         hitObject = nextObject;
  415.                     }
  416.                 }
  417.             }
  418.         }
  419.  
  420.         // Go to the next object.
  421.         nextObject = objects->GetNext( nextObject );
  422.     }
  423.  
  424.     // Iterate through the list of hit ghost objects and their collision distances.
  425.     ghostHits->Iterate( true );
  426.     ghostDistances->Iterate( true );
  427.     while( ghostHits->Iterate() != NULL && ghostDistances->Iterate() != NULL )
  428.     {
  429.         // If the distance to hit the ghost object is less than the distance to the closets real collision, then the ghost object has been hit.
  430.         if( *ghostDistances->GetCurrent() < data->distance )
  431.         {
  432.             // Register the collision between both objects.
  433.             ghostHits->GetCurrent()->CollisionOccurred( data->object, data->frameStamp );
  434.             data->object->CollisionOccurred( ghostHits->GetCurrent(), data->frameStamp );
  435.         }
  436.     }
  437.  
  438.     // Destroy the ghost hits and distances lists.
  439.     ghostHits->ClearPointers();
  440.     SAFE_DELETE( ghostHits );
  441.     ghostDistances->ClearPointers();
  442.     SAFE_DELETE( ghostDistances );
  443.  
  444.     // If no collision occured, then just move the full velocity vector.
  445.     if( data->collisionFound == false )
  446.     {
  447.         data->translation = data->translation + data->velocity;
  448.         return;
  449.     }
  450.  
  451.     // Calculate the destination (i.e. the point the object was trying to get to).
  452.     D3DXVECTOR3 destination = data->translation + data->velocity;
  453.  
  454.     // The new translation will be the point where the object actually ends up.
  455.     D3DXVECTOR3 newTranslation = data->translation;
  456.  
  457.     // Ignore the movement if the object is already very close to its destination.
  458.     if( data->distance >= epsilon )
  459.     {
  460.         // Calculate the new velocity required to move the distance.
  461.         D3DXVECTOR3 newVelocity = data->normalizedVelocity * ( data->distance - epsilon );
  462.  
  463.         // Find the new translation.
  464.         newTranslation = data->translation + newVelocity;
  465.  
  466.         // Adjust the polygon intersection point to taking into account that fact that
  467.         // the object does not move right up to the actual intersection point.
  468.         D3DXVec3Normalize( &newVelocity, &newVelocity );
  469.         data->intersection = data->intersection - newVelocity * epsilon;
  470.     }
  471.  
  472.     // Check if the collision occured with an object.
  473.     if( hitObject != NULL )
  474.     {
  475.         // Set the new translation of the object.
  476.         data->translation = newTranslation;
  477.  
  478.         // Calculate and apply a push velocity so objects can push one another.
  479.         D3DXVECTOR3 push = ( hitObject->GetVelocity() + data->object->GetVelocity() ) / 10.0f;
  480.         hitObject->SetVelocity( push );
  481.         data->object->SetVelocity( push );
  482.  
  483.         // Register the collision between both objects, if thay are allowed.
  484.         if( hitObject->GetIgnoreCollisions() == false && data->object->GetIgnoreCollisions() == false )
  485.         {
  486.             hitObject->CollisionOccurred( data->object, data->frameStamp );
  487.             data->object->CollisionOccurred( hitObject, data->frameStamp );
  488.         }
  489.  
  490.         return;
  491.     }
  492.  
  493.     // Create a plane that wil act as the sliding plane.
  494.     D3DXVECTOR3 slidePlaneOrigin = data->intersection;
  495.     D3DXVECTOR3 slidePlaneNormal;
  496.     D3DXVec3Normalize( &slidePlaneNormal, &( newTranslation - data->intersection ) );
  497.     D3DXPLANE slidingPlane;
  498.     D3DXPlaneFromPointNormal( &slidingPlane, &slidePlaneOrigin, &slidePlaneNormal );
  499.  
  500.     // Calculate the new destination accouting for sliding.
  501.     D3DXVECTOR3 newDestination = destination - slidePlaneNormal * ( D3DXVec3Dot( &destination, &slidePlaneNormal ) + slidingPlane.d );
  502.     newDestination += slidePlaneNormal * epsilon;
  503.  
  504.     // Calculate the new velocity which is the vector of the slide.
  505.     D3DXVECTOR3 newVelocity = newDestination - data->intersection;
  506.  
  507.     // Check if the new velocity is too short.
  508.     if( D3DXVec3Length( &newVelocity ) <= epsilon )
  509.     {
  510.         // Since the velocity is too short, there is no need to continue
  511.         // performing collision detection. So just set the new translation
  512.         // and velocity, then return.
  513.         data->translation = newTranslation;
  514.         data->velocity = D3DXVECTOR3( 0.0f, 0.0f, 0.0f );
  515.  
  516.         return;
  517.     }
  518.  
  519.     // Set the new translation and velocity.
  520.     data->translation = newTranslation;
  521.     data->velocity = newVelocity;
  522.  
  523.     // Perform another collision detection recurison if allowed.
  524.     recursion--;
  525.     if( recursion > 0 )
  526.         CollideWithScene( data, vertices, faces, totalFaces, objects, recursion );
  527. }
  528.  
  529. //-----------------------------------------------------------------------------
  530. // Entry point for collision detection and response.
  531. //-----------------------------------------------------------------------------
  532. inline void PerformCollisionDetection( CollisionData *data, Vertex *vertices, SceneFace *faces, unsigned long totalFaces, LinkedList< SceneObject > *dynamicObjects )
  533. {
  534.     // Calculate the object's translation in ellipsoid space.
  535.     data->translation.x = data->object->GetTranslation().x / data->object->GetEllipsoidRadius().x;
  536.     data->translation.y = data->object->GetTranslation().y / data->object->GetEllipsoidRadius().y;
  537.     data->translation.z = data->object->GetTranslation().z / data->object->GetEllipsoidRadius().z;
  538.  
  539.     // Calculate the object's velocity in ellipsoid space.
  540.     data->velocity = data->object->GetVelocity() * data->elapsed;
  541.     data->velocity.x /= data->object->GetEllipsoidRadius().x;
  542.     data->velocity.y /= data->object->GetEllipsoidRadius().y;
  543.     data->velocity.z /= data->object->GetEllipsoidRadius().z;
  544.  
  545.     // Begin the recursive collision detection.
  546.     CollideWithScene( data, vertices, faces, totalFaces, dynamicObjects );
  547.  
  548.     // Now set the velocity to the gravity vector (in ellipsoid space).
  549.     data->velocity.x = data->gravity.x / data->object->GetEllipsoidRadius().x;
  550.     data->velocity.y = data->gravity.y / data->object->GetEllipsoidRadius().y;
  551.     data->velocity.z = data->gravity.z / data->object->GetEllipsoidRadius().z;
  552.  
  553.     // Perform another recursive collision detection to apply gravity.
  554.     CollideWithScene( data, vertices, faces, totalFaces, dynamicObjects );
  555.  
  556.     // Convert the object's new translation back out of ellipsoid space.
  557.     data->translation.x = data->translation.x * data->object->GetEllipsoidRadius().x;
  558.     data->translation.y = data->translation.y * data->object->GetEllipsoidRadius().y;
  559.     data->translation.z = data->translation.z * data->object->GetEllipsoidRadius().z;
  560.  
  561.     // Go through all the faces in the scene, checking for intersection.
  562.     float hitDistance = -1.0f;
  563.     for( unsigned long f = 0; f < totalFaces; f++ )
  564.     {
  565.         // Skip this face if its material is set to ignore rays.
  566.         if( faces[f].renderCache->GetMaterial()->GetIgnoreRay() == true )
  567.             continue;
  568.  
  569.         // Preform a ray intersection test to see if this face is under the object.
  570.         float distance;
  571.         if( D3DXIntersectTri( (D3DXVECTOR3*)&vertices[faces[f].vertex0], (D3DXVECTOR3*)&vertices[faces[f].vertex1], (D3DXVECTOR3*)&vertices[faces[f].vertex2], &data->translation, &D3DXVECTOR3( 0.0f, -1.0f, 0.0f ), NULL, NULL, &distance ) == TRUE )
  572.             if( distance < hitDistance || hitDistance == -1.0f )
  573.                 hitDistance = distance;
  574.     }
  575.  
  576.     // If the distance to the ray intersection is less than the radius
  577.     // of the object along the y axis, then the object is embedded in
  578.     // the ground. So just push the object up out of the ground.
  579.     if( hitDistance < data->object->GetEllipsoidRadius().y )
  580.         data->translation.y += data->object->GetEllipsoidRadius().y - hitDistance;
  581.  
  582.     // Check if the object is touching the ground.
  583.     if( hitDistance < data->object->GetEllipsoidRadius().y + 0.1f / data->scale )
  584.         data->object->SetTouchingGroundFlag( true );
  585.     else
  586.         data->object->SetTouchingGroundFlag( false );
  587.  
  588.     // Update the object's translation after collision detection.
  589.     data->object->SetTranslation( data->translation );
  590. }
  591.  
  592. #endif