[216] | 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 | } |
---|