Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/ode/ode-0.9/OPCODE/OPC_RayCollider.cpp @ 216

Last change on this file since 216 was 216, checked in by mathiask, 17 years ago

[Physik] add ode-0.9

File size: 28.5 KB
Line 
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
117using 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///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
205RayCollider::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///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
226RayCollider::~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///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
236const 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///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
262bool 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///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
337BOOL 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///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
463bool 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///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
493void 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///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
518void 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///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
548void 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///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
574void 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///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
606void 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///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
631void 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///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
656void 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///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
686void 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///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
712void 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///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
744void 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}
Note: See TracBrowser for help on using the repository browser.