123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761 |
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /*
- * OPCODE - Optimized Collision Detection
- * Copyright (C) 2001 Pierre Terdiman
- * Homepage: http://www.codercorner.com/Opcode.htm
- */
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /**
- * Contains code for a ray collider.
- * \file OPC_RayCollider.cpp
- * \author Pierre Terdiman
- * \date June, 2, 2001
- */
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /**
- * Contains a ray-vs-tree collider.
- * This class performs a stabbing query on an AABB tree, i.e. does a ray-mesh collision.
- *
- * HIGHER DISTANCE BOUND:
- *
- * If P0 and P1 are two 3D points, let's define:
- * - d = distance between P0 and P1
- * - Origin = P0
- * - Direction = (P1 - P0) / d = normalized direction vector
- * - A parameter t such as a point P on the line (P0,P1) is P = Origin + t * Direction
- * - t = 0 --> P = P0
- * - t = d --> P = P1
- *
- * Then we can define a general "ray" as:
- *
- * struct Ray
- * {
- * Point Origin;
- * Point Direction;
- * };
- *
- * But it actually maps three different things:
- * - a segment, when 0 <= t <= d
- * - a half-line, when 0 <= t < +infinity, or -infinity < t <= d
- * - a line, when -infinity < t < +infinity
- *
- * In Opcode, we support segment queries, which yield half-line queries by setting d = +infinity.
- * We don't support line-queries. If you need them, shift the origin along the ray by an appropriate margin.
- *
- * In short, the lower bound is always 0, and you can setup the higher bound "d" with RayCollider::SetMaxDist().
- *
- * Query |segment |half-line |line
- * --------|-------------------|---------------|----------------
- * Usages |-shadow feelers |-raytracing |-
- * |-sweep tests |-in/out tests |
- *
- * FIRST CONTACT:
- *
- * - You can setup "first contact" mode or "all contacts" mode with RayCollider::SetFirstContact().
- * - In "first contact" mode we return as soon as the ray hits one face. If can be useful e.g. for shadow feelers, where
- * you want to know whether the path to the light is free or not (a boolean answer is enough).
- * - In "all contacts" mode we return all faces hit by the ray.
- *
- * TEMPORAL COHERENCE:
- *
- * - You can enable or disable temporal coherence with RayCollider::SetTemporalCoherence().
- * - It currently only works in "first contact" mode.
- * - If temporal coherence is enabled, the previously hit triangle is cached during the first query. Then, next queries
- * start by colliding the ray against the cached triangle. If they still collide, we return immediately.
- *
- * CLOSEST HIT:
- *
- * - You can enable or disable "closest hit" with RayCollider::SetClosestHit().
- * - It currently only works in "all contacts" mode.
- * - If closest hit is enabled, faces are sorted by distance on-the-fly and the closest one only is reported.
- *
- * BACKFACE CULLING:
- *
- * - You can enable or disable backface culling with RayCollider::SetCulling().
- * - If culling is enabled, ray will not hit back faces (only front faces).
- *
- *
- *
- * \class RayCollider
- * \author Pierre Terdiman
- * \version 1.3
- * \date June, 2, 2001
- */
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /**
- * This class describes a face hit by a ray or segment.
- * This is a particular class dedicated to stabbing queries.
- *
- * \class CollisionFace
- * \author Pierre Terdiman
- * \version 1.3
- * \date March, 20, 2001
- */
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /**
- * This class is a dedicated collection of CollisionFace.
- *
- * \class CollisionFaces
- * \author Pierre Terdiman
- * \version 1.3
- * \date March, 20, 2001
- */
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- #include "Opcode.h"
- using namespace Opcode;
- #include "OPC_RayAABBOverlap.h"
- #include "OPC_RayTriOverlap.h"
- #define SET_CONTACT(prim_index, flag) \
- mNbIntersections++; \
- /* Set contact status */ \
- mFlags |= flag; \
- /* In any case the contact has been found and recorded in mStabbedFace */ \
- mStabbedFace.mFaceID = prim_index;
- #ifdef OPC_RAYHIT_CALLBACK
- #define HANDLE_CONTACT(prim_index, flag) \
- SET_CONTACT(prim_index, flag) \
- \
- if(mHitCallback) (mHitCallback)(mStabbedFace, mUserData);
- #define UPDATE_CACHE \
- if(cache && GetContactStatus()) \
- { \
- *cache = mStabbedFace.mFaceID; \
- }
- #else
- #define HANDLE_CONTACT(prim_index, flag) \
- SET_CONTACT(prim_index, flag) \
- \
- /* Now we can also record it in mStabbedFaces if available */ \
- if(mStabbedFaces) \
- { \
- /* If we want all faces or if that's the first one we hit */ \
- if(!mClosestHit || !mStabbedFaces->GetNbFaces()) \
- { \
- mStabbedFaces->AddFace(mStabbedFace); \
- } \
- else \
- { \
- /* We only keep closest hit */ \
- CollisionFace* Current = const_cast<CollisionFace*>(mStabbedFaces->GetFaces()); \
- if(Current && mStabbedFace.mDistance<Current->mDistance) \
- { \
- *Current = mStabbedFace; \
- } \
- } \
- }
- #define UPDATE_CACHE \
- if(cache && GetContactStatus() && mStabbedFaces) \
- { \
- const CollisionFace* Current = mStabbedFaces->GetFaces(); \
- if(Current) *cache = Current->mFaceID; \
- else *cache = INVALID_ID_OPC; \
- }
- #endif
- #define SEGMENT_PRIM(prim_index, flag) \
- /* Request vertices from the app */ \
- VertexPointers VP; mIMesh->GetTriangle(VP, prim_index); \
- \
- /* Perform ray-tri overlap test and return */ \
- if(RayTriOverlap(*VP.Vertex[0], *VP.Vertex[1], *VP.Vertex[2])) \
- { \
- /* Intersection point is valid if dist < segment's length */ \
- /* We know dist>0 so we can use integers */ \
- if(IR(mStabbedFace.mDistance)<IR(mMaxDist)) \
- { \
- HANDLE_CONTACT(prim_index, flag) \
- } \
- }
- #define RAY_PRIM(prim_index, flag) \
- /* Request vertices from the app */ \
- VertexPointers VP; mIMesh->GetTriangle(VP, prim_index); \
- \
- /* Perform ray-tri overlap test and return */ \
- if(RayTriOverlap(*VP.Vertex[0], *VP.Vertex[1], *VP.Vertex[2])) \
- { \
- HANDLE_CONTACT(prim_index, flag) \
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /**
- * Constructor.
- */
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- RayCollider::RayCollider() :
- mNbRayBVTests (0),
- mNbRayPrimTests (0),
- mNbIntersections (0),
- mCulling (true),
- #ifdef OPC_RAYHIT_CALLBACK
- mHitCallback (null),
- mUserData (0),
- #else
- mClosestHit (false),
- mStabbedFaces (null),
- #endif
- mMaxDist (MAX_FLOAT)
- {
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /**
- * Destructor.
- */
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- RayCollider::~RayCollider()
- {
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /**
- * Validates current settings. You should call this method after all the settings and callbacks have been defined.
- * \return null if everything is ok, else a string describing the problem
- */
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- const char* RayCollider::ValidateSettings()
- {
- if(mMaxDist<0.0f) return "Higher distance bound must be positive!";
- if(TemporalCoherenceEnabled() && !FirstContactEnabled()) return "Temporal coherence only works with ""First contact"" mode!";
- #ifndef OPC_RAYHIT_CALLBACK
- if(mClosestHit && FirstContactEnabled()) return "Closest hit doesn't work with ""First contact"" mode!";
- if(TemporalCoherenceEnabled() && mClosestHit) return "Temporal coherence can't guarantee to report closest hit!";
- #endif
- if(SkipPrimitiveTests()) return "SkipPrimitiveTests not possible for RayCollider ! (not implemented)";
- return null;
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /**
- * Generic stabbing query for generic OPCODE models. After the call, access the results:
- * - with GetContactStatus()
- * - in the user-provided destination array
- *
- * \param world_ray [in] stabbing ray in world space
- * \param model [in] Opcode model to collide with
- * \param world [in] model's world matrix, or null
- * \param cache [in] a possibly cached face index, or null
- * \return true if success
- * \warning SCALE NOT SUPPORTED. The matrices must contain rotation & translation parts only.
- */
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- bool RayCollider::Collide(const Ray& world_ray, const Model& model, const Matrix4x4* world, udword* cache)
- {
- // Checkings
- if(!Setup(&model)) return false;
- // Init collision query
- if(InitQuery(world_ray, world, cache)) return true;
- if(!model.HasLeafNodes())
- {
- if(model.IsQuantized())
- {
- const AABBQuantizedNoLeafTree* Tree = (const AABBQuantizedNoLeafTree*)model.GetTree();
- // Setup dequantization coeffs
- mCenterCoeff = Tree->mCenterCoeff;
- mExtentsCoeff = Tree->mExtentsCoeff;
- // Perform stabbing query
- if(IR(mMaxDist)!=IEEE_MAX_FLOAT) _SegmentStab(Tree->GetNodes());
- else _RayStab(Tree->GetNodes());
- }
- else
- {
- const AABBNoLeafTree* Tree = (const AABBNoLeafTree*)model.GetTree();
- // Perform stabbing query
- if(IR(mMaxDist)!=IEEE_MAX_FLOAT) _SegmentStab(Tree->GetNodes());
- else _RayStab(Tree->GetNodes());
- }
- }
- else
- {
- if(model.IsQuantized())
- {
- const AABBQuantizedTree* Tree = (const AABBQuantizedTree*)model.GetTree();
- // Setup dequantization coeffs
- mCenterCoeff = Tree->mCenterCoeff;
- mExtentsCoeff = Tree->mExtentsCoeff;
- // Perform stabbing query
- if(IR(mMaxDist)!=IEEE_MAX_FLOAT) _SegmentStab(Tree->GetNodes());
- else _RayStab(Tree->GetNodes());
- }
- else
- {
- const AABBCollisionTree* Tree = (const AABBCollisionTree*)model.GetTree();
- // Perform stabbing query
- if(IR(mMaxDist)!=IEEE_MAX_FLOAT) _SegmentStab(Tree->GetNodes());
- else _RayStab(Tree->GetNodes());
- }
- }
- // Update cache if needed
- UPDATE_CACHE
- return true;
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /**
- * Initializes a stabbing query :
- * - reset stats & contact status
- * - compute ray in local space
- * - check temporal coherence
- *
- * \param world_ray [in] stabbing ray in world space
- * \param world [in] object's world matrix, or null
- * \param face_id [in] index of previously stabbed triangle
- * \return TRUE if we can return immediately
- * \warning SCALE NOT SUPPORTED. The matrix must contain rotation & translation parts only.
- */
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- BOOL RayCollider::InitQuery(const Ray& world_ray, const Matrix4x4* world, udword* face_id)
- {
- // Reset stats & contact status
- Collider::InitQuery();
- mNbRayBVTests = 0;
- mNbRayPrimTests = 0;
- mNbIntersections = 0;
- #ifndef OPC_RAYHIT_CALLBACK
- if(mStabbedFaces) mStabbedFaces->Reset();
- #endif
- // Compute ray in local space
- // The (Origin/Dir) form is needed for the ray-triangle test anyway (even for segment tests)
- if(world)
- {
- Matrix3x3 InvWorld = *world;
- mDir = InvWorld * world_ray.mDir;
- Matrix4x4 World;
- InvertPRMatrix(World, *world);
- mOrigin = world_ray.mOrig * World;
- }
- else
- {
- mDir = world_ray.mDir;
- mOrigin = world_ray.mOrig;
- }
- // 4) Special case: 1-triangle meshes [Opcode 1.3]
- if(mCurrentModel && mCurrentModel->HasSingleNode())
- {
- // We simply perform the BV-Prim overlap test each time. We assume single triangle has index 0.
- if(!SkipPrimitiveTests())
- {
- // Perform overlap test between the unique triangle and the ray (and set contact status if needed)
- SEGMENT_PRIM(udword(0), OPC_CONTACT)
- // Return immediately regardless of status
- return TRUE;
- }
- }
- // Check temporal coherence :
- // Test previously colliding primitives first
- if(TemporalCoherenceEnabled() && FirstContactEnabled() && face_id && *face_id!=INVALID_ID_OPC)
- {
- #ifdef OLD_CODE
- #ifndef OPC_RAYHIT_CALLBACK
- if(!mClosestHit)
- #endif
- {
- // Request vertices from the app
- VertexPointers VP;
- mIMesh->GetTriangle(VP, *face_id);
- // Perform ray-cached tri overlap test
- if(RayTriOverlap(*VP.Vertex[0], *VP.Vertex[1], *VP.Vertex[2]))
- {
- // Intersection point is valid if:
- // - distance is positive (else it can just be a face behind the orig point)
- // - distance is smaller than a given max distance (useful for shadow feelers)
- // if(mStabbedFace.mDistance>0.0f && mStabbedFace.mDistance<mMaxDist)
- if(IR(mStabbedFace.mDistance)<IR(mMaxDist)) // The other test is already performed in RayTriOverlap
- {
- // Set contact status
- mFlags |= OPC_TEMPORAL_CONTACT;
- mStabbedFace.mFaceID = *face_id;
- #ifndef OPC_RAYHIT_CALLBACK
- if(mStabbedFaces) mStabbedFaces->AddFace(mStabbedFace);
- #endif
- return TRUE;
- }
- }
- }
- #else
- // New code
- // We handle both Segment/ray queries with the same segment code, and a possible infinite limit
- SEGMENT_PRIM(*face_id, OPC_TEMPORAL_CONTACT)
- // Return immediately if possible
- if(GetContactStatus()) return TRUE;
- #endif
- }
- // Precompute data (moved after temporal coherence since only needed for ray-AABB)
- if(IR(mMaxDist)!=IEEE_MAX_FLOAT)
- {
- // For Segment-AABB overlap
- mData = 0.5f * mDir * mMaxDist;
- mData2 = mOrigin + mData;
- // Precompute mFDir;
- mFDir.x = fabsf(mData.x);
- mFDir.y = fabsf(mData.y);
- mFDir.z = fabsf(mData.z);
- }
- else
- {
- // For Ray-AABB overlap
- // udword x = SIR(mDir.x)-1;
- // udword y = SIR(mDir.y)-1;
- // udword z = SIR(mDir.z)-1;
- // mData.x = FR(x);
- // mData.y = FR(y);
- // mData.z = FR(z);
- // Precompute mFDir;
- mFDir.x = fabsf(mDir.x);
- mFDir.y = fabsf(mDir.y);
- mFDir.z = fabsf(mDir.z);
- }
- return FALSE;
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /**
- * Stabbing query for vanilla AABB trees.
- * \param world_ray [in] stabbing ray in world space
- * \param tree [in] AABB tree
- * \param box_indices [out] indices of stabbed boxes
- * \return true if success
- */
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- bool RayCollider::Collide(const Ray& world_ray, const AABBTree* tree, OPC_Container& box_indices)
- {
- // ### bad design here
- // This is typically called for a scene tree, full of -AABBs-, not full of triangles.
- // So we don't really have "primitives" to deal with. Hence it doesn't work with
- // "FirstContact" + "TemporalCoherence".
- ASSERT( !(FirstContactEnabled() && TemporalCoherenceEnabled()) );
- // Checkings
- if(!tree) return false;
- // Init collision query
- // Basically this is only called to initialize precomputed data
- if(InitQuery(world_ray)) return true;
- // Perform stabbing query
- if(IR(mMaxDist)!=IEEE_MAX_FLOAT) _SegmentStab(tree, box_indices);
- else _RayStab(tree, box_indices);
- return true;
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /**
- * Recursive stabbing query for normal AABB trees.
- * \param node [in] current collision node
- */
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- void RayCollider::_SegmentStab(const AABBCollisionNode* node)
- {
- // Perform Segment-AABB overlap test
- if(!SegmentAABBOverlap(node->mAABB.mCenter, node->mAABB.mExtents)) return;
- if(node->IsLeaf())
- {
- SEGMENT_PRIM(node->GetPrimitive(), OPC_CONTACT)
- }
- else
- {
- _SegmentStab(node->GetPos());
- if(ContactFound()) return;
- _SegmentStab(node->GetNeg());
- }
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /**
- * Recursive stabbing query for quantized AABB trees.
- * \param node [in] current collision node
- */
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- void RayCollider::_SegmentStab(const AABBQuantizedNode* node)
- {
- // Dequantize box
- const QuantizedAABB& Box = node->mAABB;
- const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z);
- const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z);
- // Perform Segment-AABB overlap test
- if(!SegmentAABBOverlap(Center, Extents)) return;
- if(node->IsLeaf())
- {
- SEGMENT_PRIM(node->GetPrimitive(), OPC_CONTACT)
- }
- else
- {
- _SegmentStab(node->GetPos());
- if(ContactFound()) return;
- _SegmentStab(node->GetNeg());
- }
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /**
- * Recursive stabbing query for no-leaf AABB trees.
- * \param node [in] current collision node
- */
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- void RayCollider::_SegmentStab(const AABBNoLeafNode* node)
- {
- // Perform Segment-AABB overlap test
- if(!SegmentAABBOverlap(node->mAABB.mCenter, node->mAABB.mExtents)) return;
- if(node->HasPosLeaf())
- {
- SEGMENT_PRIM(node->GetPosPrimitive(), OPC_CONTACT)
- }
- else _SegmentStab(node->GetPos());
- if(ContactFound()) return;
- if(node->HasNegLeaf())
- {
- SEGMENT_PRIM(node->GetNegPrimitive(), OPC_CONTACT)
- }
- else _SegmentStab(node->GetNeg());
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /**
- * Recursive stabbing query for quantized no-leaf AABB trees.
- * \param node [in] current collision node
- */
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- void RayCollider::_SegmentStab(const AABBQuantizedNoLeafNode* node)
- {
- // Dequantize box
- const QuantizedAABB& Box = node->mAABB;
- const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z);
- const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z);
- // Perform Segment-AABB overlap test
- if(!SegmentAABBOverlap(Center, Extents)) return;
- if(node->HasPosLeaf())
- {
- SEGMENT_PRIM(node->GetPosPrimitive(), OPC_CONTACT)
- }
- else _SegmentStab(node->GetPos());
- if(ContactFound()) return;
- if(node->HasNegLeaf())
- {
- SEGMENT_PRIM(node->GetNegPrimitive(), OPC_CONTACT)
- }
- else _SegmentStab(node->GetNeg());
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /**
- * Recursive stabbing query for vanilla AABB trees.
- * \param node [in] current collision node
- * \param box_indices [out] indices of stabbed boxes
- */
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- void RayCollider::_SegmentStab(const AABBTreeNode* node, OPC_Container& box_indices)
- {
- // Test the box against the segment
- Point Center, Extents;
- node->GetAABB()->GetCenter(Center);
- node->GetAABB()->GetExtents(Extents);
- if(!SegmentAABBOverlap(Center, Extents)) return;
- if(node->IsLeaf())
- {
- box_indices.Add(node->GetPrimitives(), node->GetNbPrimitives());
- }
- else
- {
- _SegmentStab(node->GetPos(), box_indices);
- _SegmentStab(node->GetNeg(), box_indices);
- }
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /**
- * Recursive stabbing query for normal AABB trees.
- * \param node [in] current collision node
- */
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- void RayCollider::_RayStab(const AABBCollisionNode* node)
- {
- // Perform Ray-AABB overlap test
- if(!RayAABBOverlap(node->mAABB.mCenter, node->mAABB.mExtents)) return;
- if(node->IsLeaf())
- {
- RAY_PRIM(node->GetPrimitive(), OPC_CONTACT)
- }
- else
- {
- _RayStab(node->GetPos());
- if(ContactFound()) return;
- _RayStab(node->GetNeg());
- }
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /**
- * Recursive stabbing query for quantized AABB trees.
- * \param node [in] current collision node
- */
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- void RayCollider::_RayStab(const AABBQuantizedNode* node)
- {
- // Dequantize box
- const QuantizedAABB& Box = node->mAABB;
- const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z);
- const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z);
- // Perform Ray-AABB overlap test
- if(!RayAABBOverlap(Center, Extents)) return;
- if(node->IsLeaf())
- {
- RAY_PRIM(node->GetPrimitive(), OPC_CONTACT)
- }
- else
- {
- _RayStab(node->GetPos());
- if(ContactFound()) return;
- _RayStab(node->GetNeg());
- }
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /**
- * Recursive stabbing query for no-leaf AABB trees.
- * \param node [in] current collision node
- */
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- void RayCollider::_RayStab(const AABBNoLeafNode* node)
- {
- // Perform Ray-AABB overlap test
- if(!RayAABBOverlap(node->mAABB.mCenter, node->mAABB.mExtents)) return;
- if(node->HasPosLeaf())
- {
- RAY_PRIM(node->GetPosPrimitive(), OPC_CONTACT)
- }
- else _RayStab(node->GetPos());
- if(ContactFound()) return;
- if(node->HasNegLeaf())
- {
- RAY_PRIM(node->GetNegPrimitive(), OPC_CONTACT)
- }
- else _RayStab(node->GetNeg());
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /**
- * Recursive stabbing query for quantized no-leaf AABB trees.
- * \param node [in] current collision node
- */
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- void RayCollider::_RayStab(const AABBQuantizedNoLeafNode* node)
- {
- // Dequantize box
- const QuantizedAABB& Box = node->mAABB;
- const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z);
- const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z);
- // Perform Ray-AABB overlap test
- if(!RayAABBOverlap(Center, Extents)) return;
- if(node->HasPosLeaf())
- {
- RAY_PRIM(node->GetPosPrimitive(), OPC_CONTACT)
- }
- else _RayStab(node->GetPos());
- if(ContactFound()) return;
- if(node->HasNegLeaf())
- {
- RAY_PRIM(node->GetNegPrimitive(), OPC_CONTACT)
- }
- else _RayStab(node->GetNeg());
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- /**
- * Recursive stabbing query for vanilla AABB trees.
- * \param node [in] current collision node
- * \param box_indices [out] indices of stabbed boxes
- */
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- void RayCollider::_RayStab(const AABBTreeNode* node, OPC_Container& box_indices)
- {
- // Test the box against the ray
- Point Center, Extents;
- node->GetAABB()->GetCenter(Center);
- node->GetAABB()->GetExtents(Extents);
- if(!RayAABBOverlap(Center, Extents)) return;
- if(node->IsLeaf())
- {
- mFlags |= OPC_CONTACT;
- box_indices.Add(node->GetPrimitives(), node->GetNbPrimitives());
- }
- else
- {
- _RayStab(node->GetPos(), box_indices);
- _RayStab(node->GetNeg(), box_indices);
- }
- }
|