-
Notifications
You must be signed in to change notification settings - Fork 1
/
CollisionDetection.h
executable file
·604 lines (499 loc) · 23.8 KB
/
CollisionDetection.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
// ***************************************************
//
// File: CollisionDetection.h
// Programmer: T.J. Eason
// Project: Game Engine
// Description: Detect collision between static geometry and dynamic objects
// Reference: Code based on Kasper Fauerby's algorithm in ""Improved Collision Detection and Response"
// Date: 4-16-10
// Revision: 4-19-10
// Revision: 4-20-10
//
// ***************************************************
#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.
};
// Get the lowest root of a quadratic equation.
inline float GetLowestRoot( float a, float b, float c, float max )
{
// Calculate the determinant,
float determinant = b * b - a * c;
// Make sure determinant is valid
if( determinant < 0.0f )
return 0.0f;
determinant = (float)sqrt( determinant );
// Calculate the first root
float root1 = ( b + determinant ) / a;
// Make sure root is within bounds
if( root1 <= 0.0f || root1 > max )
root1 = max + 1.0f;
// Calculate the second root
float root2 = ( b - determinant ) / a;
// Make sure second root is within bounds
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 );
// Make sure plane is facing the velocity vector
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 the normal dot velocity
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;
// Make sure 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;
// Calculate b and c from quadtraic equation for ver tex 0
b = 2.0f * D3DXVec3Dot( &data->velocity, &( data->translation - vertex0 ) );
c = D3DXVec3LengthSq( &( vertex0 - data->translation ) ) - 1.0f;
// Check time for vertex 0
if( newTime = GetLowestRoot( a, b, c, intersectTime ) > 0.0f )
{
intersectFound = true;
intersection = vertex0;
intersectTime = newTime;
}
// Calculate b and c from quadratic equation for vertex 1
b = 2.0f * D3DXVec3Dot( &data->velocity, &( data->translation - vertex1 ) );
c = D3DXVec3LengthSq( &( vertex1 - data->translation ) ) - 1.0f;
// Check time for vertex 1
if( newTime = GetLowestRoot( a, b, c, intersectTime ) > 0.0f )
{
intersectFound = true;
intersection = vertex1;
intersectTime = newTime;
}
// Calclate b and c from quadtratic equation for vertex 2
b = 2.0f * D3DXVec3Dot( &data->velocity, &( data->translation - vertex2 ) );
c = D3DXVec3LengthSq( &( vertex2 - data->translation ) ) - 1.0f;
// Check time for vertex 2
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 )
{
// Make sure 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 )
{
// Make sure 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 given 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;
// Get the scene objects within the list
SceneObject *hitObject = NULL;
SceneObject *nextObject = objects->GetFirst();
// Search through each object within the list
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 destination
D3DXVECTOR3 destination = data->translation + data->velocity;
// 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 );
// 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 != -1.0f )
if( hitDistance < data->object->GetEllipsoidRadius().y )
data->translation.y += data->object->GetEllipsoidRadius().y - hitDistance;
// Check if the object is touching the ground.
if( hitDistance != -1.0f && 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