diff options
author | dan miller | 2007-10-19 04:28:53 +0000 |
---|---|---|
committer | dan miller | 2007-10-19 04:28:53 +0000 |
commit | 0fc46fc9590912bf6925c899edd02d7a2cdf5f79 (patch) | |
tree | 51bcae7a1b8381a6bf6fd8025a7de1e30fe0045d /libraries/ode-0.9\/OPCODE/OPC_RayCollider.cpp | |
parent | small bit of refactoring (diff) | |
download | opensim-SC-0fc46fc9590912bf6925c899edd02d7a2cdf5f79.zip opensim-SC-0fc46fc9590912bf6925c899edd02d7a2cdf5f79.tar.gz opensim-SC-0fc46fc9590912bf6925c899edd02d7a2cdf5f79.tar.bz2 opensim-SC-0fc46fc9590912bf6925c899edd02d7a2cdf5f79.tar.xz |
adding ode source to /libraries
Diffstat (limited to '')
-rwxr-xr-x | libraries/ode-0.9\/OPCODE/OPC_RayCollider.cpp | 762 |
1 files changed, 762 insertions, 0 deletions
diff --git a/libraries/ode-0.9\/OPCODE/OPC_RayCollider.cpp b/libraries/ode-0.9\/OPCODE/OPC_RayCollider.cpp new file mode 100755 index 0000000..5828ce4 --- /dev/null +++ b/libraries/ode-0.9\/OPCODE/OPC_RayCollider.cpp | |||
@@ -0,0 +1,762 @@ | |||
1 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
2 | /* | ||
3 | * OPCODE - Optimized Collision Detection | ||
4 | * Copyright (C) 2001 Pierre Terdiman | ||
5 | * Homepage: http://www.codercorner.com/Opcode.htm | ||
6 | */ | ||
7 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
8 | |||
9 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
10 | /** | ||
11 | * Contains code for a ray collider. | ||
12 | * \file OPC_RayCollider.cpp | ||
13 | * \author Pierre Terdiman | ||
14 | * \date June, 2, 2001 | ||
15 | */ | ||
16 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
17 | |||
18 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
19 | /** | ||
20 | * Contains a ray-vs-tree collider. | ||
21 | * This class performs a stabbing query on an AABB tree, i.e. does a ray-mesh collision. | ||
22 | * | ||
23 | * HIGHER DISTANCE BOUND: | ||
24 | * | ||
25 | * If P0 and P1 are two 3D points, let's define: | ||
26 | * - d = distance between P0 and P1 | ||
27 | * - Origin = P0 | ||
28 | * - Direction = (P1 - P0) / d = normalized direction vector | ||
29 | * - A parameter t such as a point P on the line (P0,P1) is P = Origin + t * Direction | ||
30 | * - t = 0 --> P = P0 | ||
31 | * - t = d --> P = P1 | ||
32 | * | ||
33 | * Then we can define a general "ray" as: | ||
34 | * | ||
35 | * struct Ray | ||
36 | * { | ||
37 | * Point Origin; | ||
38 | * Point Direction; | ||
39 | * }; | ||
40 | * | ||
41 | * But it actually maps three different things: | ||
42 | * - a segment, when 0 <= t <= d | ||
43 | * - a half-line, when 0 <= t < +infinity, or -infinity < t <= d | ||
44 | * - a line, when -infinity < t < +infinity | ||
45 | * | ||
46 | * In Opcode, we support segment queries, which yield half-line queries by setting d = +infinity. | ||
47 | * We don't support line-queries. If you need them, shift the origin along the ray by an appropriate margin. | ||
48 | * | ||
49 | * In short, the lower bound is always 0, and you can setup the higher bound "d" with RayCollider::SetMaxDist(). | ||
50 | * | ||
51 | * Query |segment |half-line |line | ||
52 | * --------|-------------------|---------------|---------------- | ||
53 | * Usages |-shadow feelers |-raytracing |- | ||
54 | * |-sweep tests |-in/out tests | | ||
55 | * | ||
56 | * FIRST CONTACT: | ||
57 | * | ||
58 | * - You can setup "first contact" mode or "all contacts" mode with RayCollider::SetFirstContact(). | ||
59 | * - In "first contact" mode we return as soon as the ray hits one face. If can be useful e.g. for shadow feelers, where | ||
60 | * you want to know whether the path to the light is free or not (a boolean answer is enough). | ||
61 | * - In "all contacts" mode we return all faces hit by the ray. | ||
62 | * | ||
63 | * TEMPORAL COHERENCE: | ||
64 | * | ||
65 | * - You can enable or disable temporal coherence with RayCollider::SetTemporalCoherence(). | ||
66 | * - It currently only works in "first contact" mode. | ||
67 | * - If temporal coherence is enabled, the previously hit triangle is cached during the first query. Then, next queries | ||
68 | * start by colliding the ray against the cached triangle. If they still collide, we return immediately. | ||
69 | * | ||
70 | * CLOSEST HIT: | ||
71 | * | ||
72 | * - You can enable or disable "closest hit" with RayCollider::SetClosestHit(). | ||
73 | * - It currently only works in "all contacts" mode. | ||
74 | * - If closest hit is enabled, faces are sorted by distance on-the-fly and the closest one only is reported. | ||
75 | * | ||
76 | * BACKFACE CULLING: | ||
77 | * | ||
78 | * - You can enable or disable backface culling with RayCollider::SetCulling(). | ||
79 | * - If culling is enabled, ray will not hit back faces (only front faces). | ||
80 | * | ||
81 | * | ||
82 | * | ||
83 | * \class RayCollider | ||
84 | * \author Pierre Terdiman | ||
85 | * \version 1.3 | ||
86 | * \date June, 2, 2001 | ||
87 | */ | ||
88 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
89 | |||
90 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
91 | /** | ||
92 | * This class describes a face hit by a ray or segment. | ||
93 | * This is a particular class dedicated to stabbing queries. | ||
94 | * | ||
95 | * \class CollisionFace | ||
96 | * \author Pierre Terdiman | ||
97 | * \version 1.3 | ||
98 | * \date March, 20, 2001 | ||
99 | */ | ||
100 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
101 | |||
102 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
103 | /** | ||
104 | * This class is a dedicated collection of CollisionFace. | ||
105 | * | ||
106 | * \class CollisionFaces | ||
107 | * \author Pierre Terdiman | ||
108 | * \version 1.3 | ||
109 | * \date March, 20, 2001 | ||
110 | */ | ||
111 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
112 | |||
113 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
114 | // Precompiled Header | ||
115 | #include "Stdafx.h" | ||
116 | |||
117 | using namespace Opcode; | ||
118 | |||
119 | #include "OPC_RayAABBOverlap.h" | ||
120 | #include "OPC_RayTriOverlap.h" | ||
121 | |||
122 | #define SET_CONTACT(prim_index, flag) \ | ||
123 | mNbIntersections++; \ | ||
124 | /* Set contact status */ \ | ||
125 | mFlags |= flag; \ | ||
126 | /* In any case the contact has been found and recorded in mStabbedFace */ \ | ||
127 | mStabbedFace.mFaceID = prim_index; | ||
128 | |||
129 | #ifdef OPC_RAYHIT_CALLBACK | ||
130 | |||
131 | #define HANDLE_CONTACT(prim_index, flag) \ | ||
132 | SET_CONTACT(prim_index, flag) \ | ||
133 | \ | ||
134 | if(mHitCallback) (mHitCallback)(mStabbedFace, mUserData); | ||
135 | |||
136 | #define UPDATE_CACHE \ | ||
137 | if(cache && GetContactStatus()) \ | ||
138 | { \ | ||
139 | *cache = mStabbedFace.mFaceID; \ | ||
140 | } | ||
141 | #else | ||
142 | |||
143 | #define HANDLE_CONTACT(prim_index, flag) \ | ||
144 | SET_CONTACT(prim_index, flag) \ | ||
145 | \ | ||
146 | /* Now we can also record it in mStabbedFaces if available */ \ | ||
147 | if(mStabbedFaces) \ | ||
148 | { \ | ||
149 | /* If we want all faces or if that's the first one we hit */ \ | ||
150 | if(!mClosestHit || !mStabbedFaces->GetNbFaces()) \ | ||
151 | { \ | ||
152 | mStabbedFaces->AddFace(mStabbedFace); \ | ||
153 | } \ | ||
154 | else \ | ||
155 | { \ | ||
156 | /* We only keep closest hit */ \ | ||
157 | CollisionFace* Current = const_cast<CollisionFace*>(mStabbedFaces->GetFaces()); \ | ||
158 | if(Current && mStabbedFace.mDistance<Current->mDistance) \ | ||
159 | { \ | ||
160 | *Current = mStabbedFace; \ | ||
161 | } \ | ||
162 | } \ | ||
163 | } | ||
164 | |||
165 | #define UPDATE_CACHE \ | ||
166 | if(cache && GetContactStatus() && mStabbedFaces) \ | ||
167 | { \ | ||
168 | const CollisionFace* Current = mStabbedFaces->GetFaces(); \ | ||
169 | if(Current) *cache = Current->mFaceID; \ | ||
170 | else *cache = INVALID_ID; \ | ||
171 | } | ||
172 | #endif | ||
173 | |||
174 | #define SEGMENT_PRIM(prim_index, flag) \ | ||
175 | /* Request vertices from the app */ \ | ||
176 | VertexPointers VP; mIMesh->GetTriangle(VP, prim_index); \ | ||
177 | \ | ||
178 | /* Perform ray-tri overlap test and return */ \ | ||
179 | if(RayTriOverlap(*VP.Vertex[0], *VP.Vertex[1], *VP.Vertex[2])) \ | ||
180 | { \ | ||
181 | /* Intersection point is valid if dist < segment's length */ \ | ||
182 | /* We know dist>0 so we can use integers */ \ | ||
183 | if(IR(mStabbedFace.mDistance)<IR(mMaxDist)) \ | ||
184 | { \ | ||
185 | HANDLE_CONTACT(prim_index, flag) \ | ||
186 | } \ | ||
187 | } | ||
188 | |||
189 | #define RAY_PRIM(prim_index, flag) \ | ||
190 | /* Request vertices from the app */ \ | ||
191 | VertexPointers VP; mIMesh->GetTriangle(VP, prim_index); \ | ||
192 | \ | ||
193 | /* Perform ray-tri overlap test and return */ \ | ||
194 | if(RayTriOverlap(*VP.Vertex[0], *VP.Vertex[1], *VP.Vertex[2])) \ | ||
195 | { \ | ||
196 | HANDLE_CONTACT(prim_index, flag) \ | ||
197 | } | ||
198 | |||
199 | |||
200 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
201 | /** | ||
202 | * Constructor. | ||
203 | */ | ||
204 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
205 | RayCollider::RayCollider() : | ||
206 | mNbRayBVTests (0), | ||
207 | mNbRayPrimTests (0), | ||
208 | mNbIntersections (0), | ||
209 | mCulling (true), | ||
210 | #ifdef OPC_RAYHIT_CALLBACK | ||
211 | mHitCallback (null), | ||
212 | mUserData (0), | ||
213 | #else | ||
214 | mClosestHit (false), | ||
215 | mStabbedFaces (null), | ||
216 | #endif | ||
217 | mMaxDist (MAX_FLOAT) | ||
218 | { | ||
219 | } | ||
220 | |||
221 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
222 | /** | ||
223 | * Destructor. | ||
224 | */ | ||
225 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
226 | RayCollider::~RayCollider() | ||
227 | { | ||
228 | } | ||
229 | |||
230 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
231 | /** | ||
232 | * Validates current settings. You should call this method after all the settings and callbacks have been defined. | ||
233 | * \return null if everything is ok, else a string describing the problem | ||
234 | */ | ||
235 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
236 | const char* RayCollider::ValidateSettings() | ||
237 | { | ||
238 | if(mMaxDist<0.0f) return "Higher distance bound must be positive!"; | ||
239 | if(TemporalCoherenceEnabled() && !FirstContactEnabled()) return "Temporal coherence only works with ""First contact"" mode!"; | ||
240 | #ifndef OPC_RAYHIT_CALLBACK | ||
241 | if(mClosestHit && FirstContactEnabled()) return "Closest hit doesn't work with ""First contact"" mode!"; | ||
242 | if(TemporalCoherenceEnabled() && mClosestHit) return "Temporal coherence can't guarantee to report closest hit!"; | ||
243 | #endif | ||
244 | if(SkipPrimitiveTests()) return "SkipPrimitiveTests not possible for RayCollider ! (not implemented)"; | ||
245 | return null; | ||
246 | } | ||
247 | |||
248 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
249 | /** | ||
250 | * Generic stabbing query for generic OPCODE models. After the call, access the results: | ||
251 | * - with GetContactStatus() | ||
252 | * - in the user-provided destination array | ||
253 | * | ||
254 | * \param world_ray [in] stabbing ray in world space | ||
255 | * \param model [in] Opcode model to collide with | ||
256 | * \param world [in] model's world matrix, or null | ||
257 | * \param cache [in] a possibly cached face index, or null | ||
258 | * \return true if success | ||
259 | * \warning SCALE NOT SUPPORTED. The matrices must contain rotation & translation parts only. | ||
260 | */ | ||
261 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
262 | bool RayCollider::Collide(const Ray& world_ray, const Model& model, const Matrix4x4* world, udword* cache) | ||
263 | { | ||
264 | // Checkings | ||
265 | if(!Setup(&model)) return false; | ||
266 | |||
267 | // Init collision query | ||
268 | if(InitQuery(world_ray, world, cache)) return true; | ||
269 | |||
270 | if(!model.HasLeafNodes()) | ||
271 | { | ||
272 | if(model.IsQuantized()) | ||
273 | { | ||
274 | const AABBQuantizedNoLeafTree* Tree = (const AABBQuantizedNoLeafTree*)model.GetTree(); | ||
275 | |||
276 | // Setup dequantization coeffs | ||
277 | mCenterCoeff = Tree->mCenterCoeff; | ||
278 | mExtentsCoeff = Tree->mExtentsCoeff; | ||
279 | |||
280 | // Perform stabbing query | ||
281 | if(IR(mMaxDist)!=IEEE_MAX_FLOAT) _SegmentStab(Tree->GetNodes()); | ||
282 | else _RayStab(Tree->GetNodes()); | ||
283 | } | ||
284 | else | ||
285 | { | ||
286 | const AABBNoLeafTree* Tree = (const AABBNoLeafTree*)model.GetTree(); | ||
287 | |||
288 | // Perform stabbing query | ||
289 | if(IR(mMaxDist)!=IEEE_MAX_FLOAT) _SegmentStab(Tree->GetNodes()); | ||
290 | else _RayStab(Tree->GetNodes()); | ||
291 | } | ||
292 | } | ||
293 | else | ||
294 | { | ||
295 | if(model.IsQuantized()) | ||
296 | { | ||
297 | const AABBQuantizedTree* Tree = (const AABBQuantizedTree*)model.GetTree(); | ||
298 | |||
299 | // Setup dequantization coeffs | ||
300 | mCenterCoeff = Tree->mCenterCoeff; | ||
301 | mExtentsCoeff = Tree->mExtentsCoeff; | ||
302 | |||
303 | // Perform stabbing query | ||
304 | if(IR(mMaxDist)!=IEEE_MAX_FLOAT) _SegmentStab(Tree->GetNodes()); | ||
305 | else _RayStab(Tree->GetNodes()); | ||
306 | } | ||
307 | else | ||
308 | { | ||
309 | const AABBCollisionTree* Tree = (const AABBCollisionTree*)model.GetTree(); | ||
310 | |||
311 | // Perform stabbing query | ||
312 | if(IR(mMaxDist)!=IEEE_MAX_FLOAT) _SegmentStab(Tree->GetNodes()); | ||
313 | else _RayStab(Tree->GetNodes()); | ||
314 | } | ||
315 | } | ||
316 | |||
317 | // Update cache if needed | ||
318 | UPDATE_CACHE | ||
319 | return true; | ||
320 | } | ||
321 | |||
322 | |||
323 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
324 | /** | ||
325 | * Initializes a stabbing query : | ||
326 | * - reset stats & contact status | ||
327 | * - compute ray in local space | ||
328 | * - check temporal coherence | ||
329 | * | ||
330 | * \param world_ray [in] stabbing ray in world space | ||
331 | * \param world [in] object's world matrix, or null | ||
332 | * \param face_id [in] index of previously stabbed triangle | ||
333 | * \return TRUE if we can return immediately | ||
334 | * \warning SCALE NOT SUPPORTED. The matrix must contain rotation & translation parts only. | ||
335 | */ | ||
336 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
337 | BOOL RayCollider::InitQuery(const Ray& world_ray, const Matrix4x4* world, udword* face_id) | ||
338 | { | ||
339 | // Reset stats & contact status | ||
340 | Collider::InitQuery(); | ||
341 | mNbRayBVTests = 0; | ||
342 | mNbRayPrimTests = 0; | ||
343 | mNbIntersections = 0; | ||
344 | #ifndef OPC_RAYHIT_CALLBACK | ||
345 | if(mStabbedFaces) mStabbedFaces->Reset(); | ||
346 | #endif | ||
347 | |||
348 | // Compute ray in local space | ||
349 | // The (Origin/Dir) form is needed for the ray-triangle test anyway (even for segment tests) | ||
350 | if(world) | ||
351 | { | ||
352 | Matrix3x3 InvWorld = *world; | ||
353 | mDir = InvWorld * world_ray.mDir; | ||
354 | |||
355 | Matrix4x4 World; | ||
356 | InvertPRMatrix(World, *world); | ||
357 | mOrigin = world_ray.mOrig * World; | ||
358 | } | ||
359 | else | ||
360 | { | ||
361 | mDir = world_ray.mDir; | ||
362 | mOrigin = world_ray.mOrig; | ||
363 | } | ||
364 | |||
365 | // 4) Special case: 1-triangle meshes [Opcode 1.3] | ||
366 | if(mCurrentModel && mCurrentModel->HasSingleNode()) | ||
367 | { | ||
368 | // We simply perform the BV-Prim overlap test each time. We assume single triangle has index 0. | ||
369 | if(!SkipPrimitiveTests()) | ||
370 | { | ||
371 | // Perform overlap test between the unique triangle and the ray (and set contact status if needed) | ||
372 | SEGMENT_PRIM(udword(0), OPC_CONTACT) | ||
373 | |||
374 | // Return immediately regardless of status | ||
375 | return TRUE; | ||
376 | } | ||
377 | } | ||
378 | |||
379 | // Check temporal coherence : | ||
380 | |||
381 | // Test previously colliding primitives first | ||
382 | if(TemporalCoherenceEnabled() && FirstContactEnabled() && face_id && *face_id!=INVALID_ID) | ||
383 | { | ||
384 | #ifdef OLD_CODE | ||
385 | #ifndef OPC_RAYHIT_CALLBACK | ||
386 | if(!mClosestHit) | ||
387 | #endif | ||
388 | { | ||
389 | // Request vertices from the app | ||
390 | VertexPointers VP; | ||
391 | mIMesh->GetTriangle(VP, *face_id); | ||
392 | // Perform ray-cached tri overlap test | ||
393 | if(RayTriOverlap(*VP.Vertex[0], *VP.Vertex[1], *VP.Vertex[2])) | ||
394 | { | ||
395 | // Intersection point is valid if: | ||
396 | // - distance is positive (else it can just be a face behind the orig point) | ||
397 | // - distance is smaller than a given max distance (useful for shadow feelers) | ||
398 | // if(mStabbedFace.mDistance>0.0f && mStabbedFace.mDistance<mMaxDist) | ||
399 | if(IR(mStabbedFace.mDistance)<IR(mMaxDist)) // The other test is already performed in RayTriOverlap | ||
400 | { | ||
401 | // Set contact status | ||
402 | mFlags |= OPC_TEMPORAL_CONTACT; | ||
403 | |||
404 | mStabbedFace.mFaceID = *face_id; | ||
405 | |||
406 | #ifndef OPC_RAYHIT_CALLBACK | ||
407 | if(mStabbedFaces) mStabbedFaces->AddFace(mStabbedFace); | ||
408 | #endif | ||
409 | return TRUE; | ||
410 | } | ||
411 | } | ||
412 | } | ||
413 | #else | ||
414 | // New code | ||
415 | // We handle both Segment/ray queries with the same segment code, and a possible infinite limit | ||
416 | SEGMENT_PRIM(*face_id, OPC_TEMPORAL_CONTACT) | ||
417 | |||
418 | // Return immediately if possible | ||
419 | if(GetContactStatus()) return TRUE; | ||
420 | #endif | ||
421 | } | ||
422 | |||
423 | // Precompute data (moved after temporal coherence since only needed for ray-AABB) | ||
424 | if(IR(mMaxDist)!=IEEE_MAX_FLOAT) | ||
425 | { | ||
426 | // For Segment-AABB overlap | ||
427 | mData = 0.5f * mDir * mMaxDist; | ||
428 | mData2 = mOrigin + mData; | ||
429 | |||
430 | // Precompute mFDir; | ||
431 | mFDir.x = fabsf(mData.x); | ||
432 | mFDir.y = fabsf(mData.y); | ||
433 | mFDir.z = fabsf(mData.z); | ||
434 | } | ||
435 | else | ||
436 | { | ||
437 | // For Ray-AABB overlap | ||
438 | // udword x = SIR(mDir.x)-1; | ||
439 | // udword y = SIR(mDir.y)-1; | ||
440 | // udword z = SIR(mDir.z)-1; | ||
441 | // mData.x = FR(x); | ||
442 | // mData.y = FR(y); | ||
443 | // mData.z = FR(z); | ||
444 | |||
445 | // Precompute mFDir; | ||
446 | mFDir.x = fabsf(mDir.x); | ||
447 | mFDir.y = fabsf(mDir.y); | ||
448 | mFDir.z = fabsf(mDir.z); | ||
449 | } | ||
450 | |||
451 | return FALSE; | ||
452 | } | ||
453 | |||
454 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
455 | /** | ||
456 | * Stabbing query for vanilla AABB trees. | ||
457 | * \param world_ray [in] stabbing ray in world space | ||
458 | * \param tree [in] AABB tree | ||
459 | * \param box_indices [out] indices of stabbed boxes | ||
460 | * \return true if success | ||
461 | */ | ||
462 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
463 | bool RayCollider::Collide(const Ray& world_ray, const AABBTree* tree, Container& box_indices) | ||
464 | { | ||
465 | // ### bad design here | ||
466 | |||
467 | // This is typically called for a scene tree, full of -AABBs-, not full of triangles. | ||
468 | // So we don't really have "primitives" to deal with. Hence it doesn't work with | ||
469 | // "FirstContact" + "TemporalCoherence". | ||
470 | ASSERT( !(FirstContactEnabled() && TemporalCoherenceEnabled()) ); | ||
471 | |||
472 | // Checkings | ||
473 | if(!tree) return false; | ||
474 | |||
475 | // Init collision query | ||
476 | // Basically this is only called to initialize precomputed data | ||
477 | if(InitQuery(world_ray)) return true; | ||
478 | |||
479 | // Perform stabbing query | ||
480 | if(IR(mMaxDist)!=IEEE_MAX_FLOAT) _SegmentStab(tree, box_indices); | ||
481 | else _RayStab(tree, box_indices); | ||
482 | |||
483 | return true; | ||
484 | } | ||
485 | |||
486 | |||
487 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
488 | /** | ||
489 | * Recursive stabbing query for normal AABB trees. | ||
490 | * \param node [in] current collision node | ||
491 | */ | ||
492 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
493 | void RayCollider::_SegmentStab(const AABBCollisionNode* node) | ||
494 | { | ||
495 | // Perform Segment-AABB overlap test | ||
496 | if(!SegmentAABBOverlap(node->mAABB.mCenter, node->mAABB.mExtents)) return; | ||
497 | |||
498 | if(node->IsLeaf()) | ||
499 | { | ||
500 | SEGMENT_PRIM(node->GetPrimitive(), OPC_CONTACT) | ||
501 | } | ||
502 | else | ||
503 | { | ||
504 | _SegmentStab(node->GetPos()); | ||
505 | |||
506 | if(ContactFound()) return; | ||
507 | |||
508 | _SegmentStab(node->GetNeg()); | ||
509 | } | ||
510 | } | ||
511 | |||
512 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
513 | /** | ||
514 | * Recursive stabbing query for quantized AABB trees. | ||
515 | * \param node [in] current collision node | ||
516 | */ | ||
517 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
518 | void RayCollider::_SegmentStab(const AABBQuantizedNode* node) | ||
519 | { | ||
520 | // Dequantize box | ||
521 | const QuantizedAABB& Box = node->mAABB; | ||
522 | const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z); | ||
523 | const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z); | ||
524 | |||
525 | // Perform Segment-AABB overlap test | ||
526 | if(!SegmentAABBOverlap(Center, Extents)) return; | ||
527 | |||
528 | if(node->IsLeaf()) | ||
529 | { | ||
530 | SEGMENT_PRIM(node->GetPrimitive(), OPC_CONTACT) | ||
531 | } | ||
532 | else | ||
533 | { | ||
534 | _SegmentStab(node->GetPos()); | ||
535 | |||
536 | if(ContactFound()) return; | ||
537 | |||
538 | _SegmentStab(node->GetNeg()); | ||
539 | } | ||
540 | } | ||
541 | |||
542 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
543 | /** | ||
544 | * Recursive stabbing query for no-leaf AABB trees. | ||
545 | * \param node [in] current collision node | ||
546 | */ | ||
547 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
548 | void RayCollider::_SegmentStab(const AABBNoLeafNode* node) | ||
549 | { | ||
550 | // Perform Segment-AABB overlap test | ||
551 | if(!SegmentAABBOverlap(node->mAABB.mCenter, node->mAABB.mExtents)) return; | ||
552 | |||
553 | if(node->HasPosLeaf()) | ||
554 | { | ||
555 | SEGMENT_PRIM(node->GetPosPrimitive(), OPC_CONTACT) | ||
556 | } | ||
557 | else _SegmentStab(node->GetPos()); | ||
558 | |||
559 | if(ContactFound()) return; | ||
560 | |||
561 | if(node->HasNegLeaf()) | ||
562 | { | ||
563 | SEGMENT_PRIM(node->GetNegPrimitive(), OPC_CONTACT) | ||
564 | } | ||
565 | else _SegmentStab(node->GetNeg()); | ||
566 | } | ||
567 | |||
568 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
569 | /** | ||
570 | * Recursive stabbing query for quantized no-leaf AABB trees. | ||
571 | * \param node [in] current collision node | ||
572 | */ | ||
573 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
574 | void RayCollider::_SegmentStab(const AABBQuantizedNoLeafNode* node) | ||
575 | { | ||
576 | // Dequantize box | ||
577 | const QuantizedAABB& Box = node->mAABB; | ||
578 | const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z); | ||
579 | const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z); | ||
580 | |||
581 | // Perform Segment-AABB overlap test | ||
582 | if(!SegmentAABBOverlap(Center, Extents)) return; | ||
583 | |||
584 | if(node->HasPosLeaf()) | ||
585 | { | ||
586 | SEGMENT_PRIM(node->GetPosPrimitive(), OPC_CONTACT) | ||
587 | } | ||
588 | else _SegmentStab(node->GetPos()); | ||
589 | |||
590 | if(ContactFound()) return; | ||
591 | |||
592 | if(node->HasNegLeaf()) | ||
593 | { | ||
594 | SEGMENT_PRIM(node->GetNegPrimitive(), OPC_CONTACT) | ||
595 | } | ||
596 | else _SegmentStab(node->GetNeg()); | ||
597 | } | ||
598 | |||
599 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
600 | /** | ||
601 | * Recursive stabbing query for vanilla AABB trees. | ||
602 | * \param node [in] current collision node | ||
603 | * \param box_indices [out] indices of stabbed boxes | ||
604 | */ | ||
605 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
606 | void RayCollider::_SegmentStab(const AABBTreeNode* node, Container& box_indices) | ||
607 | { | ||
608 | // Test the box against the segment | ||
609 | Point Center, Extents; | ||
610 | node->GetAABB()->GetCenter(Center); | ||
611 | node->GetAABB()->GetExtents(Extents); | ||
612 | if(!SegmentAABBOverlap(Center, Extents)) return; | ||
613 | |||
614 | if(node->IsLeaf()) | ||
615 | { | ||
616 | box_indices.Add(node->GetPrimitives(), node->GetNbPrimitives()); | ||
617 | } | ||
618 | else | ||
619 | { | ||
620 | _SegmentStab(node->GetPos(), box_indices); | ||
621 | _SegmentStab(node->GetNeg(), box_indices); | ||
622 | } | ||
623 | } | ||
624 | |||
625 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
626 | /** | ||
627 | * Recursive stabbing query for normal AABB trees. | ||
628 | * \param node [in] current collision node | ||
629 | */ | ||
630 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
631 | void RayCollider::_RayStab(const AABBCollisionNode* node) | ||
632 | { | ||
633 | // Perform Ray-AABB overlap test | ||
634 | if(!RayAABBOverlap(node->mAABB.mCenter, node->mAABB.mExtents)) return; | ||
635 | |||
636 | if(node->IsLeaf()) | ||
637 | { | ||
638 | RAY_PRIM(node->GetPrimitive(), OPC_CONTACT) | ||
639 | } | ||
640 | else | ||
641 | { | ||
642 | _RayStab(node->GetPos()); | ||
643 | |||
644 | if(ContactFound()) return; | ||
645 | |||
646 | _RayStab(node->GetNeg()); | ||
647 | } | ||
648 | } | ||
649 | |||
650 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
651 | /** | ||
652 | * Recursive stabbing query for quantized AABB trees. | ||
653 | * \param node [in] current collision node | ||
654 | */ | ||
655 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
656 | void RayCollider::_RayStab(const AABBQuantizedNode* node) | ||
657 | { | ||
658 | // Dequantize box | ||
659 | const QuantizedAABB& Box = node->mAABB; | ||
660 | const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z); | ||
661 | const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z); | ||
662 | |||
663 | // Perform Ray-AABB overlap test | ||
664 | if(!RayAABBOverlap(Center, Extents)) return; | ||
665 | |||
666 | if(node->IsLeaf()) | ||
667 | { | ||
668 | RAY_PRIM(node->GetPrimitive(), OPC_CONTACT) | ||
669 | } | ||
670 | else | ||
671 | { | ||
672 | _RayStab(node->GetPos()); | ||
673 | |||
674 | if(ContactFound()) return; | ||
675 | |||
676 | _RayStab(node->GetNeg()); | ||
677 | } | ||
678 | } | ||
679 | |||
680 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
681 | /** | ||
682 | * Recursive stabbing query for no-leaf AABB trees. | ||
683 | * \param node [in] current collision node | ||
684 | */ | ||
685 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
686 | void RayCollider::_RayStab(const AABBNoLeafNode* node) | ||
687 | { | ||
688 | // Perform Ray-AABB overlap test | ||
689 | if(!RayAABBOverlap(node->mAABB.mCenter, node->mAABB.mExtents)) return; | ||
690 | |||
691 | if(node->HasPosLeaf()) | ||
692 | { | ||
693 | RAY_PRIM(node->GetPosPrimitive(), OPC_CONTACT) | ||
694 | } | ||
695 | else _RayStab(node->GetPos()); | ||
696 | |||
697 | if(ContactFound()) return; | ||
698 | |||
699 | if(node->HasNegLeaf()) | ||
700 | { | ||
701 | RAY_PRIM(node->GetNegPrimitive(), OPC_CONTACT) | ||
702 | } | ||
703 | else _RayStab(node->GetNeg()); | ||
704 | } | ||
705 | |||
706 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
707 | /** | ||
708 | * Recursive stabbing query for quantized no-leaf AABB trees. | ||
709 | * \param node [in] current collision node | ||
710 | */ | ||
711 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
712 | void RayCollider::_RayStab(const AABBQuantizedNoLeafNode* node) | ||
713 | { | ||
714 | // Dequantize box | ||
715 | const QuantizedAABB& Box = node->mAABB; | ||
716 | const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z); | ||
717 | const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z); | ||
718 | |||
719 | // Perform Ray-AABB overlap test | ||
720 | if(!RayAABBOverlap(Center, Extents)) return; | ||
721 | |||
722 | if(node->HasPosLeaf()) | ||
723 | { | ||
724 | RAY_PRIM(node->GetPosPrimitive(), OPC_CONTACT) | ||
725 | } | ||
726 | else _RayStab(node->GetPos()); | ||
727 | |||
728 | if(ContactFound()) return; | ||
729 | |||
730 | if(node->HasNegLeaf()) | ||
731 | { | ||
732 | RAY_PRIM(node->GetNegPrimitive(), OPC_CONTACT) | ||
733 | } | ||
734 | else _RayStab(node->GetNeg()); | ||
735 | } | ||
736 | |||
737 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
738 | /** | ||
739 | * Recursive stabbing query for vanilla AABB trees. | ||
740 | * \param node [in] current collision node | ||
741 | * \param box_indices [out] indices of stabbed boxes | ||
742 | */ | ||
743 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
744 | void RayCollider::_RayStab(const AABBTreeNode* node, Container& box_indices) | ||
745 | { | ||
746 | // Test the box against the ray | ||
747 | Point Center, Extents; | ||
748 | node->GetAABB()->GetCenter(Center); | ||
749 | node->GetAABB()->GetExtents(Extents); | ||
750 | if(!RayAABBOverlap(Center, Extents)) return; | ||
751 | |||
752 | if(node->IsLeaf()) | ||
753 | { | ||
754 | mFlags |= OPC_CONTACT; | ||
755 | box_indices.Add(node->GetPrimitives(), node->GetNbPrimitives()); | ||
756 | } | ||
757 | else | ||
758 | { | ||
759 | _RayStab(node->GetPos(), box_indices); | ||
760 | _RayStab(node->GetNeg(), box_indices); | ||
761 | } | ||
762 | } | ||