Created
October 2, 2022 15:56
-
-
Save osdeving/dabee8104968954b50d08764bce363f8 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//----------------------------------------------------------------------------- | |
// Provides basic collision detection in a 3D environment that includes both | |
// static geometry and dynamic objects. | |
// | |
// Note: This uses an adaptation of the algorithm from the Improved Collision | |
// Detection and Response article written by Kasper Fauerby. | |
// | |
// Programming a Multiplayer First Person Shooter in DirectX | |
// Copyright (c) 2004 Vaughan Young | |
//----------------------------------------------------------------------------- | |
#ifndef COLLISION_H | |
#define COLLISION_H | |
//----------------------------------------------------------------------------- | |
// Collision Data Structure | |
//----------------------------------------------------------------------------- | |
struct CollisionData | |
{ | |
float scale; // Scale used by thge calling scene manager. | |
float elapsed; // Elapsed time for the current frame. | |
unsigned long frameStamp; // Current frame stamp according to the scene manager. | |
SceneObject *object; // Pointer to the object to perform collision detection with. | |
D3DXVECTOR3 translation; // Translation in ellipsoid space. | |
D3DXVECTOR3 velocity; // Velocity in ellipsoid space. | |
D3DXVECTOR3 normalizedVelocity; // Normalized velocity in ellipsoid space. | |
D3DXVECTOR3 gravity; // Gravity vector, which will be converted to ellipsoid space. | |
bool collisionFound; // Indicates if a collision has been found. | |
float distance; // Distance to the point of collision. | |
D3DXVECTOR3 intersection; // Actual intersection point where the collision occured. | |
}; | |
//----------------------------------------------------------------------------- | |
// Returns the lowest root of a quadratic equation. | |
//----------------------------------------------------------------------------- | |
inline float GetLowestRoot( float a, float b, float c, float max ) | |
{ | |
// Calculate the determinant, then get the square root of it if it's valid. | |
float determinant = b * b - a * c; | |
if( determinant < 0.0f ) | |
return 0.0f; | |
determinant = (float)sqrt( determinant ); | |
// Calculate the first root and ensure it is within the bounds. | |
float root1 = ( b + determinant ) / a; | |
if( root1 <= 0.0f || root1 > max ) | |
root1 = max + 1.0f; | |
// Calculate the second root and ensure it is within the bounds. | |
float root2 = ( b - determinant ) / a; | |
if( root2 <= 0.0f || root2 > max ) | |
root2 = max + 1.0f; | |
// Get the lowest of the two roots. | |
float root = min( root1, root2 ); | |
// Ensure the root is valid. | |
if( root == max + 1.0f ) | |
return 0.0f; | |
return root; | |
} | |
//----------------------------------------------------------------------------- | |
// Checks a single face for intersection. | |
//----------------------------------------------------------------------------- | |
inline void CheckFace( CollisionData *data, D3DXVECTOR3 vertex0, D3DXVECTOR3 vertex1, D3DXVECTOR3 vertex2 ) | |
{ | |
// Create a plane from the face's vertices. | |
D3DXPLANE plane; | |
D3DXPlaneFromPoints( &plane, &vertex0, &vertex1, &vertex2 ); | |
// Get the angle between the plane's normal and the velocity vector. | |
float angle = D3DXPlaneDotNormal( &plane, &data->normalizedVelocity ); | |
// Ensure the plane is facing the velocity vector (i.e. ignore back faces). | |
if( angle > 0.0f ) | |
return; | |
// Get the plane's normal vector. | |
D3DXVECTOR3 planeNormal; | |
D3DXVec3Cross( &planeNormal, &( vertex0 - vertex1 ), &( vertex1 - vertex2 ) ); | |
D3DXVec3Normalize( &planeNormal, &planeNormal ); | |
// Calculate the signed distance from sphere's translation to plane. | |
float signedPlaneDistance = D3DXVec3Dot( &data->translation, &planeNormal ) + plane.d; | |
// Get interval of plane intersection | |
float time0, time1; | |
bool embedded = false; | |
// Cache this as we're going to use it a few times below | |
float normalDotVelocity = D3DXVec3Dot( &planeNormal, &data->velocity ); | |
// Check if the sphere is travelling parallel to the plane. | |
if( normalDotVelocity == 0.0f ) | |
{ | |
// If the sphere is not embedded in the plane, then it cannot collide. | |
if( fabs( signedPlaneDistance ) >= 1.0f ) | |
return; | |
else | |
{ | |
// The sphere is embedded in plane, therefore it will collide | |
// for the entire time frame. | |
embedded = true; | |
time0 = 0.0f; | |
time1 = 1.0f; | |
} | |
} | |
else | |
{ | |
// Calculate the time frame of intersection. | |
time0 = ( -1.0f - signedPlaneDistance ) / normalDotVelocity; | |
time1 = ( 1.0f - signedPlaneDistance ) / normalDotVelocity; | |
// Ensure time0 is less than time1. | |
if( time0 > time1 ) | |
{ | |
float swap = time1; | |
time1 = time0; | |
time0 = swap; | |
} | |
// If the intersection time frame is out of range, then it cannot collide. | |
if( time0 > 1.0f || time1 < 0.0f ) | |
return; | |
// Normalize the time frame. | |
if( time0 < 0.0f ) time0 = 0.0f; | |
if( time1 < 0.0f ) time1 = 0.0f; | |
if( time0 > 1.0f ) time0 = 1.0f; | |
if( time1 > 1.0f ) time1 = 1.0f; | |
} | |
// Variables used for tracking if an intersection occured, where it happened, and when. | |
bool intersectFound = false; | |
D3DXVECTOR3 intersection; | |
float intersectTime = 1.0f; | |
// Check if the sphere is embedded in the plane. | |
if( embedded == false ) | |
{ | |
// Get the plane intersection point at time0. | |
D3DXVECTOR3 planeIntersectionPoint = ( data->translation - planeNormal ) + data->velocity * time0; | |
// Get the vectors of two of the face's edges. | |
D3DXVECTOR3 edge0 = vertex1 - vertex0; | |
D3DXVECTOR3 edge1 = vertex2 - vertex0; | |
// Get the angles of the edges and combine them. | |
float angle0 = D3DXVec3Dot( &edge0, &edge0 ); | |
float angle1 = D3DXVec3Dot( &edge0, &edge1 ); | |
float angle2 = D3DXVec3Dot( &edge1, &edge1 ); | |
float combined = ( angle0 * angle2 ) - ( angle1 * angle1 ); | |
// Get the split angles between the two edges. | |
D3DXVECTOR3 split = planeIntersectionPoint - vertex0; | |
float splitAngle0 = D3DXVec3Dot( &split, &edge0 ); | |
float splitAngle1 = D3DXVec3Dot( &split, &edge1 ); | |
float x = ( splitAngle0 * angle2 ) - ( splitAngle1 * angle1 ); | |
float y = ( splitAngle1 * angle0 ) - ( splitAngle0 * angle1 ); | |
float z = x + y - combined; | |
// Take the bitwise AND of z and the complement of the inclusive OR of x and y, | |
// then bitwise AND the result with 0x80000000 and return it. A bitwise result | |
// of zero equals false, while any other value equals true. | |
if( ( ( (unsigned int&)z & ~( (unsigned int&)x | (unsigned int&)y ) ) & 0x80000000 ) != 0 ) | |
{ | |
intersectFound = true; | |
intersection = planeIntersectionPoint; | |
intersectTime = time0; | |
} | |
} | |
// Check if a collision has been found yet. | |
if( intersectFound == false ) | |
{ | |
// Get the squared length of the velocity vector. | |
float squaredVelocityLength = D3DXVec3LengthSq( &data->velocity ); | |
// A quadratic equation has to be solved for each vertex and edge in the face. | |
// The following variables are used to build each quadratic equation. | |
float a, b, c; | |
// Used for storing the result of each quadratic equation. | |
float newTime; | |
// First check againts the vertices. | |
a = squaredVelocityLength; | |
// Check vertex 0. | |
b = 2.0f * D3DXVec3Dot( &data->velocity, &( data->translation - vertex0 ) ); | |
c = D3DXVec3LengthSq( &( vertex0 - data->translation ) ) - 1.0f; | |
if( newTime = GetLowestRoot( a, b, c, intersectTime ) > 0.0f ) | |
{ | |
intersectFound = true; | |
intersection = vertex0; | |
intersectTime = newTime; | |
} | |
// Check vertex 1. | |
b = 2.0f * D3DXVec3Dot( &data->velocity, &( data->translation - vertex1 ) ); | |
c = D3DXVec3LengthSq( &( vertex1 - data->translation ) ) - 1.0f; | |
if( newTime = GetLowestRoot( a, b, c, intersectTime ) > 0.0f ) | |
{ | |
intersectFound = true; | |
intersection = vertex1; | |
intersectTime = newTime; | |
} | |
// Check vertex 2. | |
b = 2.0f * D3DXVec3Dot( &data->velocity, &( data->translation - vertex2 ) ); | |
c = D3DXVec3LengthSq( &( vertex2 - data->translation ) ) - 1.0f; | |
if( newTime = GetLowestRoot( a, b, c, intersectTime ) > 0.0f ) | |
{ | |
intersectFound = true; | |
intersection = vertex2; | |
intersectTime = newTime; | |
} | |
// Check the edge from vertex0 to vertex1. | |
D3DXVECTOR3 edge = vertex1 - vertex0; | |
D3DXVECTOR3 vectorSphereVertex = vertex0 - data->translation; | |
float squaredEdgeLength = D3DXVec3LengthSq( &edge ); | |
float angleEdgeVelocity = D3DXVec3Dot( &edge, &data->velocity ); | |
float angleEdgeSphereVertex = D3DXVec3Dot( &edge, &vectorSphereVertex ); | |
// Get the parameters for the quadratic equation. | |
a = squaredEdgeLength * -squaredVelocityLength + angleEdgeVelocity * angleEdgeVelocity; | |
b = squaredEdgeLength * ( 2.0f * D3DXVec3Dot( &data->velocity, &vectorSphereVertex ) ) - 2.0f * angleEdgeVelocity * angleEdgeSphereVertex; | |
c = squaredEdgeLength * ( 1.0f - D3DXVec3LengthSq( &vectorSphereVertex ) ) + angleEdgeSphereVertex * angleEdgeSphereVertex; | |
// Check if the sphere intersects the edge. | |
if( newTime = GetLowestRoot( a, b, c, intersectTime ) > 0.0f ) | |
{ | |
// Ensure the intersection occured within the edges bounds. | |
float point = ( angleEdgeVelocity * newTime - angleEdgeSphereVertex ) / squaredEdgeLength; | |
if( point >= 0.0f && point <= 1.0f ) | |
{ | |
intersectFound = true; | |
intersection = vertex0 + edge * point; | |
intersectTime = newTime; | |
} | |
} | |
// Check the edge from vertex1 to vertex2. | |
edge = vertex2 - vertex1; | |
vectorSphereVertex = vertex1 - data->translation; | |
squaredEdgeLength = D3DXVec3LengthSq( &edge ); | |
angleEdgeVelocity = D3DXVec3Dot( &edge, &data->velocity ); | |
angleEdgeSphereVertex = D3DXVec3Dot( &edge, &vectorSphereVertex ); | |
// Get the parameters for the quadratic equation. | |
a = squaredEdgeLength * -squaredVelocityLength + angleEdgeVelocity * angleEdgeVelocity; | |
b = squaredEdgeLength * ( 2.0f * D3DXVec3Dot( &data->velocity, &vectorSphereVertex ) ) - 2.0f * angleEdgeVelocity * angleEdgeSphereVertex; | |
c = squaredEdgeLength * ( 1.0f - D3DXVec3LengthSq( &vectorSphereVertex ) ) + angleEdgeSphereVertex * angleEdgeSphereVertex; | |
// Check if the sphere intersects the edge. | |
if( newTime = GetLowestRoot( a, b, c, intersectTime ) > 0.0f ) | |
{ | |
// Ensure the intersection occured within the edges bounds. | |
float point = ( angleEdgeVelocity * newTime - angleEdgeSphereVertex ) / squaredEdgeLength; | |
if( point >= 0.0f && point <= 1.0f ) | |
{ | |
intersectFound = true; | |
intersection = vertex1 + edge * point; | |
intersectTime = newTime; | |
} | |
} | |
// Check the edge from vertex2 to vertex0. | |
edge = vertex0 - vertex2; | |
vectorSphereVertex = vertex2 - data->translation; | |
squaredEdgeLength = D3DXVec3LengthSq( &edge ); | |
angleEdgeVelocity = D3DXVec3Dot( &edge, &data->velocity ); | |
angleEdgeSphereVertex = D3DXVec3Dot( &edge, &vectorSphereVertex ); | |
// Get the parameters for the quadratic equation. | |
a = squaredEdgeLength * -squaredVelocityLength + angleEdgeVelocity * angleEdgeVelocity; | |
b = squaredEdgeLength * ( 2.0f * D3DXVec3Dot( &data->velocity, &vectorSphereVertex ) ) - 2.0f * angleEdgeVelocity * angleEdgeSphereVertex; | |
c = squaredEdgeLength * ( 1.0f - D3DXVec3LengthSq( &vectorSphereVertex ) ) + angleEdgeSphereVertex * angleEdgeSphereVertex; | |
// Check if the sphere intersects the edge. | |
if( newTime = GetLowestRoot( a, b, c, intersectTime ) > 0.0f ) | |
{ | |
// Ensure the intersection occured within the edges bounds. | |
float point = ( angleEdgeVelocity * newTime - angleEdgeSphereVertex ) / squaredEdgeLength; | |
if( point >= 0.0f && point <= 1.0f ) | |
{ | |
intersectFound = true; | |
intersection = vertex2 + edge * point; | |
intersectTime = newTime; | |
} | |
} | |
} | |
// Check if an intersection occured. | |
if( intersectFound == true ) | |
{ | |
// Get the distance to the collision (i.e. time along the velocity vector). | |
float collisionDistance = intersectTime * D3DXVec3Length( &data->velocity ); | |
// Store the collision details, if necessary. | |
if( data->collisionFound == false || collisionDistance < data->distance ) | |
{ | |
data->distance = collisionDistance; | |
data->intersection = intersection; | |
data->collisionFound = true; | |
} | |
} | |
} | |
//----------------------------------------------------------------------------- | |
// Perfrom collision detection between the give object and the scene. | |
//----------------------------------------------------------------------------- | |
inline void CollideWithScene( CollisionData *data, Vertex *vertices, SceneFace *faces, unsigned long totalFaces, LinkedList< SceneObject > *objects, unsigned long recursion = 5 ) | |
{ | |
// Calculate the epsilon distance (taking scale into account). | |
// The epsilon distance is a very short distance that is considered negligable. | |
float epsilon = 0.5f * data->scale; | |
// Indicate that a collision has not been found. | |
data->collisionFound = false; | |
// Get the normalized velocity vector. | |
D3DXVec3Normalize( &data->normalizedVelocity, &data->velocity ); | |
// Go through all of the faces. | |
D3DXVECTOR3 vertex0, vertex1, vertex2; | |
for( unsigned long f = 0; f < totalFaces; f++ ) | |
{ | |
// Skip this face if its material is set to ignore rays. | |
if( faces[f].renderCache->GetMaterial()->GetIgnoreRay() == true ) | |
continue; | |
// Get a copy of this face's vertices in ellipsoid space. | |
vertex0.x = vertices[faces[f].vertex0].translation.x / data->object->GetEllipsoidRadius().x; | |
vertex0.y = vertices[faces[f].vertex0].translation.y / data->object->GetEllipsoidRadius().y; | |
vertex0.z = vertices[faces[f].vertex0].translation.z / data->object->GetEllipsoidRadius().z; | |
vertex1.x = vertices[faces[f].vertex1].translation.x / data->object->GetEllipsoidRadius().x; | |
vertex1.y = vertices[faces[f].vertex1].translation.y / data->object->GetEllipsoidRadius().y; | |
vertex1.z = vertices[faces[f].vertex1].translation.z / data->object->GetEllipsoidRadius().z; | |
vertex2.x = vertices[faces[f].vertex2].translation.x / data->object->GetEllipsoidRadius().x; | |
vertex2.y = vertices[faces[f].vertex2].translation.y / data->object->GetEllipsoidRadius().y; | |
vertex2.z = vertices[faces[f].vertex2].translation.z / data->object->GetEllipsoidRadius().z; | |
// Check for collision with this face. | |
CheckFace( data, vertex0, vertex1, vertex2 ); | |
} | |
// Create a list of hit ghost objects and a list of the distances to them. | |
LinkedList< SceneObject > *ghostHits = new LinkedList< SceneObject >; | |
LinkedList< float > *ghostDistances = new LinkedList< float >; | |
// Variables used for the following object collision check. | |
D3DXVECTOR3 translation, velocity, vectorColliderObject, vectorObjectCollider, vectorObjectRadius; | |
float distToCollision, colliderRadius, objectRadius; | |
// Go through the list of objects. | |
SceneObject *hitObject = NULL; | |
SceneObject *nextObject = objects->GetFirst(); | |
while( nextObject != NULL ) | |
{ | |
// Skip this object if it is the collider. It can't check against itself. | |
if( nextObject != data->object ) | |
{ | |
// Get the translation and velocity of this object in ellipsoid space. | |
translation.x = nextObject->GetTranslation().x / data->object->GetEllipsoidRadius().x; | |
translation.y = nextObject->GetTranslation().y / data->object->GetEllipsoidRadius().y; | |
translation.z = nextObject->GetTranslation().z / data->object->GetEllipsoidRadius().z; | |
velocity.x = nextObject->GetVelocity().x / data->object->GetEllipsoidRadius().x; | |
velocity.y = nextObject->GetVelocity().y / data->object->GetEllipsoidRadius().y; | |
velocity.z = nextObject->GetVelocity().z / data->object->GetEllipsoidRadius().z; | |
velocity *= data->elapsed; | |
// Get the normalized vectors from the collider to this object and vice versa. | |
D3DXVec3Normalize( &vectorColliderObject, &( translation - data->translation ) ); | |
D3DXVec3Normalize( &vectorObjectCollider, &( data->translation - translation ) ); | |
// Calculate the radius of each ellipsoid in the direction to the other. | |
colliderRadius = D3DXVec3Length( &vectorColliderObject ); | |
vectorObjectRadius.x = vectorObjectCollider.x * nextObject->GetEllipsoidRadius().x / data->object->GetEllipsoidRadius().x; | |
vectorObjectRadius.y = vectorObjectCollider.y * nextObject->GetEllipsoidRadius().y / data->object->GetEllipsoidRadius().y; | |
vectorObjectRadius.z = vectorObjectCollider.z * nextObject->GetEllipsoidRadius().z / data->object->GetEllipsoidRadius().z; | |
objectRadius = D3DXVec3Length( &vectorObjectRadius ); | |
// Check for collision between the two spheres. | |
if( IsSphereCollidingWithSphere( &distToCollision, data->translation, translation, velocity - data->velocity, colliderRadius + objectRadius ) == true ) | |
{ | |
// Check if the hit object is a ghost. | |
if( nextObject->GetGhost() == true ) | |
{ | |
// If both object's are allowed to register collisions, then store a pointer to the hit object and the distance to hit it. | |
if( nextObject->GetIgnoreCollisions() == false && data->object->GetIgnoreCollisions() == false ) | |
{ | |
ghostHits->Add( nextObject ); | |
ghostDistances->Add( &distToCollision ); | |
} | |
} | |
else | |
{ | |
// Store the collision details, if necessary. | |
if( data->collisionFound == false || distToCollision < data->distance ) | |
{ | |
data->distance = distToCollision; | |
data->intersection = data->normalizedVelocity * distToCollision; | |
data->collisionFound = true; | |
// Store a pointer to the hit object. | |
hitObject = nextObject; | |
} | |
} | |
} | |
} | |
// Go to the next object. | |
nextObject = objects->GetNext( nextObject ); | |
} | |
// Iterate through the list of hit ghost objects and their collision distances. | |
ghostHits->Iterate( true ); | |
ghostDistances->Iterate( true ); | |
while( ghostHits->Iterate() != NULL && ghostDistances->Iterate() != NULL ) | |
{ | |
// 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. | |
if( *ghostDistances->GetCurrent() < data->distance ) | |
{ | |
// Register the collision between both objects. | |
ghostHits->GetCurrent()->CollisionOccurred( data->object, data->frameStamp ); | |
data->object->CollisionOccurred( ghostHits->GetCurrent(), data->frameStamp ); | |
} | |
} | |
// Destroy the ghost hits and distances lists. | |
ghostHits->ClearPointers(); | |
SAFE_DELETE( ghostHits ); | |
ghostDistances->ClearPointers(); | |
SAFE_DELETE( ghostDistances ); | |
// If no collision occured, then just move the full velocity vector. | |
if( data->collisionFound == false ) | |
{ | |
data->translation = data->translation + data->velocity; | |
return; | |
} | |
// Calculate the destination (i.e. the point the object was trying to get to). | |
D3DXVECTOR3 destination = data->translation + data->velocity; | |
// The new translation will be the point where the object actually ends up. | |
D3DXVECTOR3 newTranslation = data->translation; | |
// Ignore the movement if the object is already very close to its destination. | |
if( data->distance >= epsilon ) | |
{ | |
// Calculate the new velocity required to move the distance. | |
D3DXVECTOR3 newVelocity = data->normalizedVelocity * ( data->distance - epsilon ); | |
// Find the new translation. | |
newTranslation = data->translation + newVelocity; | |
// Adjust the polygon intersection point to taking into account that fact that | |
// the object does not move right up to the actual intersection point. | |
D3DXVec3Normalize( &newVelocity, &newVelocity ); | |
data->intersection = data->intersection - newVelocity * epsilon; | |
} | |
// Check if the collision occured with an object. | |
if( hitObject != NULL ) | |
{ | |
// Set the new translation of the object. | |
data->translation = newTranslation; | |
// Calculate and apply a push velocity so objects can push one another. | |
D3DXVECTOR3 push = ( hitObject->GetVelocity() + data->object->GetVelocity() ) / 10.0f; | |
hitObject->SetVelocity( push ); | |
data->object->SetVelocity( push ); | |
// Register the collision between both objects, if thay are allowed. | |
if( hitObject->GetIgnoreCollisions() == false && data->object->GetIgnoreCollisions() == false ) | |
{ | |
hitObject->CollisionOccurred( data->object, data->frameStamp ); | |
data->object->CollisionOccurred( hitObject, data->frameStamp ); | |
} | |
return; | |
} | |
// Create a plane that wil act as the sliding plane. | |
D3DXVECTOR3 slidePlaneOrigin = data->intersection; | |
D3DXVECTOR3 slidePlaneNormal; | |
D3DXVec3Normalize( &slidePlaneNormal, &( newTranslation - data->intersection ) ); | |
D3DXPLANE slidingPlane; | |
D3DXPlaneFromPointNormal( &slidingPlane, &slidePlaneOrigin, &slidePlaneNormal ); | |
// Calculate the new destination accouting for sliding. | |
D3DXVECTOR3 newDestination = destination - slidePlaneNormal * ( D3DXVec3Dot( &destination, &slidePlaneNormal ) + slidingPlane.d ); | |
newDestination += slidePlaneNormal * epsilon; | |
// Calculate the new velocity which is the vector of the slide. | |
D3DXVECTOR3 newVelocity = newDestination - data->intersection; | |
// Check if the new velocity is too short. | |
if( D3DXVec3Length( &newVelocity ) <= epsilon ) | |
{ | |
// Since the velocity is too short, there is no need to continue | |
// performing collision detection. So just set the new translation | |
// and velocity, then return. | |
data->translation = newTranslation; | |
data->velocity = D3DXVECTOR3( 0.0f, 0.0f, 0.0f ); | |
return; | |
} | |
// Set the new translation and velocity. | |
data->translation = newTranslation; | |
data->velocity = newVelocity; | |
// Perform another collision detection recurison if allowed. | |
recursion--; | |
if( recursion > 0 ) | |
CollideWithScene( data, vertices, faces, totalFaces, objects, recursion ); | |
} | |
//----------------------------------------------------------------------------- | |
// Entry point for collision detection and response. | |
//----------------------------------------------------------------------------- | |
inline void PerformCollisionDetection( CollisionData *data, Vertex *vertices, SceneFace *faces, unsigned long totalFaces, LinkedList< SceneObject > *dynamicObjects ) | |
{ | |
// Calculate the object's translation in ellipsoid space. | |
data->translation.x = data->object->GetTranslation().x / data->object->GetEllipsoidRadius().x; | |
data->translation.y = data->object->GetTranslation().y / data->object->GetEllipsoidRadius().y; | |
data->translation.z = data->object->GetTranslation().z / data->object->GetEllipsoidRadius().z; | |
// Calculate the object's velocity in ellipsoid space. | |
data->velocity = data->object->GetVelocity() * data->elapsed; | |
data->velocity.x /= data->object->GetEllipsoidRadius().x; | |
data->velocity.y /= data->object->GetEllipsoidRadius().y; | |
data->velocity.z /= data->object->GetEllipsoidRadius().z; | |
// Begin the recursive collision detection. | |
CollideWithScene( data, vertices, faces, totalFaces, dynamicObjects ); | |
// Now set the velocity to the gravity vector (in ellipsoid space). | |
data->velocity.x = data->gravity.x / data->object->GetEllipsoidRadius().x; | |
data->velocity.y = data->gravity.y / data->object->GetEllipsoidRadius().y; | |
data->velocity.z = data->gravity.z / data->object->GetEllipsoidRadius().z; | |
// Perform another recursive collision detection to apply gravity. | |
CollideWithScene( data, vertices, faces, totalFaces, dynamicObjects ); | |
// Convert the object's new translation back out of ellipsoid space. | |
data->translation.x = data->translation.x * data->object->GetEllipsoidRadius().x; | |
data->translation.y = data->translation.y * data->object->GetEllipsoidRadius().y; | |
data->translation.z = data->translation.z * data->object->GetEllipsoidRadius().z; | |
// Go through all the faces in the scene, checking for intersection. | |
float hitDistance = -1.0f; | |
for( unsigned long f = 0; f < totalFaces; f++ ) | |
{ | |
// Skip this face if its material is set to ignore rays. | |
if( faces[f].renderCache->GetMaterial()->GetIgnoreRay() == true ) | |
continue; | |
// Preform a ray intersection test to see if this face is under the object. | |
float distance; | |
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 ) | |
if( distance < hitDistance || hitDistance == -1.0f ) | |
hitDistance = distance; | |
} | |
// If the distance to the ray intersection is less than the radius | |
// of the object along the y axis, then the object is embedded in | |
// the ground. So just push the object up out of the ground. | |
if( hitDistance < data->object->GetEllipsoidRadius().y ) | |
data->translation.y += data->object->GetEllipsoidRadius().y - hitDistance; | |
// Check if the object is touching the ground. | |
if( hitDistance < data->object->GetEllipsoidRadius().y + 0.1f / data->scale ) | |
data->object->SetTouchingGroundFlag( true ); | |
else | |
data->object->SetTouchingGroundFlag( false ); | |
// Update the object's translation after collision detection. | |
data->object->SetTranslation( data->translation ); | |
} | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment