a few more changes to ubode

This commit is contained in:
UbitUmarov
2022-07-16 08:17:54 +01:00
parent 164eca8ac2
commit 9f781b94ca
11 changed files with 129 additions and 636 deletions
@@ -21,7 +21,6 @@ libOPCODE_la_SOURCES = OPC_AABBCollider.cpp OPC_AABBCollider.h \
OPC_OBBCollider.cpp OPC_OBBCollider.h \
Opcode.cpp Opcode.h \
OPC_OptimizedTree.cpp OPC_OptimizedTree.h \
OPC_Picking.cpp OPC_Picking.h \
OPC_PlanesCollider.cpp OPC_PlanesCollider.h \
OPC_RayCollider.cpp OPC_RayCollider.h \
OPC_SphereCollider.cpp OPC_SphereCollider.h \
@@ -320,70 +320,6 @@ void AABBCollider::_CollideNoPrimitiveTest(const AABBCollisionNode* node)
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Recursive collision query for quantized AABB trees.
* \param node [in] current collision node
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void AABBCollider::_Collide(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 AABB-AABB overlap test
if(!AABBAABBOverlap(Extents, Center)) return;
TEST_BOX_IN_AABB(Center, Extents)
if(node->IsLeaf())
{
AABB_PRIM(node->GetPrimitive(), OPC_CONTACT)
}
else
{
_Collide(node->GetPos());
if(ContactFound()) return;
_Collide(node->GetNeg());
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Recursive collision query for quantized AABB trees, without primitive tests.
* \param node [in] current collision node
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void AABBCollider::_CollideNoPrimitiveTest(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 AABB-AABB overlap test
if(!AABBAABBOverlap(Extents, Center)) return;
TEST_BOX_IN_AABB(Center, Extents)
if(node->IsLeaf())
{
SET_CONTACT(node->GetPrimitive(), OPC_CONTACT)
}
else
{
_CollideNoPrimitiveTest(node->GetPos());
if(ContactFound()) return;
_CollideNoPrimitiveTest(node->GetNeg());
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Recursive collision query for no-leaf AABB trees.
@@ -393,17 +329,27 @@ void AABBCollider::_CollideNoPrimitiveTest(const AABBQuantizedNode* node)
void AABBCollider::_Collide(const AABBNoLeafNode* node)
{
// Perform AABB-AABB overlap test
if(!AABBAABBOverlap(node->mAABB.mExtents, node->mAABB.mCenter)) return;
if(!AABBAABBOverlap(node->mAABB.mExtents, node->mAABB.mCenter))
return;
TEST_BOX_IN_AABB(node->mAABB.mCenter, node->mAABB.mExtents)
if(node->HasPosLeaf()) { AABB_PRIM(node->GetPosPrimitive(), OPC_CONTACT) }
else _Collide(node->GetPos());
if(node->HasPosLeaf())
{
AABB_PRIM(node->GetPosPrimitive(), OPC_CONTACT)
}
else
_Collide(node->GetPos());
if(ContactFound()) return;
if(ContactFound())
return;
if(node->HasNegLeaf()) { AABB_PRIM(node->GetNegPrimitive(), OPC_CONTACT) }
else _Collide(node->GetNeg());
if(node->HasNegLeaf())
{
AABB_PRIM(node->GetNegPrimitive(), OPC_CONTACT)
}
else
_Collide(node->GetNeg());
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -428,60 +374,6 @@ void AABBCollider::_CollideNoPrimitiveTest(const AABBNoLeafNode* node)
else _CollideNoPrimitiveTest(node->GetNeg());
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Recursive collision query for quantized no-leaf AABB trees.
* \param node [in] current collision node
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void AABBCollider::_Collide(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 AABB-AABB overlap test
if(!AABBAABBOverlap(Extents, Center)) return;
TEST_BOX_IN_AABB(Center, Extents)
if(node->HasPosLeaf()) { AABB_PRIM(node->GetPosPrimitive(), OPC_CONTACT) }
else _Collide(node->GetPos());
if(ContactFound()) return;
if(node->HasNegLeaf()) { AABB_PRIM(node->GetNegPrimitive(), OPC_CONTACT) }
else _Collide(node->GetNeg());
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Recursive collision query for quantized no-leaf AABB trees, without primitive tests.
* \param node [in] current collision node
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void AABBCollider::_CollideNoPrimitiveTest(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 AABB-AABB overlap test
if(!AABBAABBOverlap(Extents, Center)) return;
TEST_BOX_IN_AABB(Center, Extents)
if(node->HasPosLeaf()) { SET_CONTACT(node->GetPosPrimitive(), OPC_CONTACT) }
else _CollideNoPrimitiveTest(node->GetPos());
if(ContactFound()) return;
if(node->HasNegLeaf()) { SET_CONTACT(node->GetNegPrimitive(), OPC_CONTACT) }
else _CollideNoPrimitiveTest(node->GetNeg());
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Recursive collision query for vanilla AABB trees.
@@ -509,8 +401,6 @@ void AABBCollider::_Collide(const AABBTreeNode* node)
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Constructor.
@@ -191,17 +191,20 @@ inline_ BOOL AABBCollider::AABBAABBOverlap(const Point& extents, const Point& ce
return ((_mm_movemask_ps(ma) & 0x07) == 0);
#else
float tx = mBox.mCenter.x - center.x;
float ex = extents.x + mBox.mExtents.x;
if (fabs(tx) > ex) return FALSE;
float t = mBox.mCenter.x - center.x;
float e = extents.x + mBox.mExtents.x;
if (fabs(t) > e)
return FALSE;
float ty = mBox.mCenter.y - center.y;
float ey = extents.y + mBox.mExtents.y;
if (fabs(ty) > ey) return FALSE;
t = mBox.mCenter.y - center.y;
e = extents.y + mBox.mExtents.y;
if (fabs(t) > e)
return FALSE;
float tz = mBox.mCenter.z - center.z;
float ez = extents.z + mBox.mExtents.z;
if (fabs(tz) > ez) return FALSE;
t = mBox.mCenter.z - center.z;
e = extents.z + mBox.mExtents.z;
if (fabs(t) > e)
return FALSE;
return TRUE;
#endif
}
@@ -1,183 +0,0 @@
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*
* OPCODE - Optimized Collision Detection
* Copyright (C) 2001 Pierre Terdiman
* Homepage: http://www.codercorner.com/Opcode.htm
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains code to perform "picking".
* \file OPC_Picking.cpp
* \author Pierre Terdiman
* \date March, 20, 2001
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Precompiled Header
#include "Stdafx.h"
using namespace Opcode;
#ifdef OPC_RAYHIT_CALLBACK
/*
Possible RayCollider usages:
- boolean query (shadow feeler)
- closest hit
- all hits
- number of intersection (boolean)
*/
bool Opcode::SetupAllHits(RayCollider& collider, CollisionFaces& contacts)
{
struct Local
{
static void AllContacts(const CollisionFace& hit, void* user_data)
{
CollisionFaces* CF = (CollisionFaces*)user_data;
CF->AddFace(hit);
}
};
collider.SetFirstContact(false);
collider.SetHitCallback(Local::AllContacts);
collider.SetUserData(&contacts);
return true;
}
bool Opcode::SetupClosestHit(RayCollider& collider, CollisionFace& closest_contact)
{
struct Local
{
static void ClosestContact(const CollisionFace& hit, void* user_data)
{
CollisionFace* CF = (CollisionFace*)user_data;
if(hit.mDistance<CF->mDistance) *CF = hit;
}
};
collider.SetFirstContact(false);
collider.SetHitCallback(Local::ClosestContact);
collider.SetUserData(&closest_contact);
closest_contact.mDistance = MAX_FLOAT;
return true;
}
bool Opcode::SetupShadowFeeler(RayCollider& collider)
{
collider.SetFirstContact(true);
collider.SetHitCallback(null);
return true;
}
bool Opcode::SetupInOutTest(RayCollider& collider)
{
collider.SetFirstContact(false);
collider.SetHitCallback(null);
// Results with collider.GetNbIntersections()
return true;
}
bool Opcode::Picking(
CollisionFace& picked_face,
const Ray& world_ray, const Model& model, const Matrix4x4* world,
float min_dist, float max_dist, const Point& view_point, CullModeCallback callback, void* user_data)
{
struct Local
{
struct CullData
{
CollisionFace* Closest;
float MinLimit;
CullModeCallback Callback;
void* UserData;
Point ViewPoint;
const MeshInterface* IMesh;
};
// Called for each stabbed face
static void RenderCullingCallback(const CollisionFace& hit, void* user_data)
{
CullData* Data = (CullData*)user_data;
// Discard face if we already have a closer hit
if(hit.mDistance>=Data->Closest->mDistance) return;
// Discard face if hit point is smaller than min limit. This mainly happens when the face is in front
// of the near clip plane (or straddles it). If we keep the face nonetheless, the user can select an
// object that he may not even be able to see, which is very annoying.
if(hit.mDistance<=Data->MinLimit) return;
// This is the index of currently stabbed triangle.
udword StabbedFaceIndex = hit.mFaceID;
// We may keep it or not, depending on backface culling
bool KeepIt = true;
// Catch *render* cull mode for this face
CullMode CM = (Data->Callback)(StabbedFaceIndex, Data->UserData);
if(CM!=CULLMODE_NONE) // Don't even compute culling for double-sided triangles
{
// Compute backface culling for current face
VertexPointers VP;
ConversionArea VC;
Data->IMesh->GetTriangle(VP, StabbedFaceIndex, VC);
if(VP.BackfaceCulling(Data->ViewPoint))
{
if(CM==CULLMODE_CW) KeepIt = false;
}
else
{
if(CM==CULLMODE_CCW) KeepIt = false;
}
}
if(KeepIt) *Data->Closest = hit;
}
};
RayCollider RC;
RC.SetMaxDist(max_dist);
RC.SetTemporalCoherence(false);
RC.SetCulling(false); // We need all faces since some of them can be double-sided
RC.SetFirstContact(false);
RC.SetHitCallback(Local::RenderCullingCallback);
picked_face.mFaceID = INVALID_ID;
picked_face.mDistance = MAX_FLOAT;
picked_face.mU = 0.0f;
picked_face.mV = 0.0f;
Local::CullData Data;
Data.Closest = &picked_face;
Data.MinLimit = min_dist;
Data.Callback = callback;
Data.UserData = user_data;
Data.ViewPoint = view_point;
Data.IMesh = model.GetMeshInterface();
if(world)
{
// Get matrices
Matrix4x4 InvWorld;
InvertPRMatrix(InvWorld, *world);
// Compute camera position in mesh space
Data.ViewPoint *= InvWorld;
}
RC.SetUserData(&Data);
if(RC.Collide(world_ray, model, world))
{
return picked_face.mFaceID!=INVALID_ID;
}
return false;
}
#endif
@@ -1,45 +0,0 @@
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*
* OPCODE - Optimized Collision Detection
* Copyright (C) 2001 Pierre Terdiman
* Homepage: http://www.codercorner.com/Opcode.htm
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Contains code to perform "picking".
* \file OPC_Picking.h
* \author Pierre Terdiman
* \date March, 20, 2001
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Include Guard
#ifndef __OPC_PICKING_H__
#define __OPC_PICKING_H__
#ifdef OPC_RAYHIT_CALLBACK
enum CullMode
{
CULLMODE_NONE = 0,
CULLMODE_CW = 1,
CULLMODE_CCW = 2
};
typedef CullMode (*CullModeCallback)(udword triangle_index, void* user_data);
OPCODE_API bool SetupAllHits (RayCollider& collider, CollisionFaces& contacts);
OPCODE_API bool SetupClosestHit (RayCollider& collider, CollisionFace& closest_contact);
OPCODE_API bool SetupShadowFeeler (RayCollider& collider);
OPCODE_API bool SetupInOutTest (RayCollider& collider);
OPCODE_API bool Picking(
CollisionFace& picked_face,
const Ray& world_ray, const Model& model, const Matrix4x4* world,
float min_dist, float max_dist, const Point& view_point, CullModeCallback callback, void* user_data);
#endif
#endif //__OPC_PICKING_H__
@@ -126,20 +126,6 @@ using namespace Opcode;
/* 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) \
\
@@ -169,7 +155,6 @@ using namespace Opcode;
if(Current) *cache = Current->mFaceID; \
else *cache = INVALID_ID; \
}
#endif
#define SEGMENT_PRIM(prim_index, flag) \
/* Request vertices from the app */ \
@@ -180,7 +165,7 @@ using namespace Opcode;
{ \
/* Intersection point is valid if dist < segment's length */ \
/* We know dist>0 so we can use integers */ \
if(IR(mStabbedFace.mDistance)<IR(mMaxDist)) \
if(mStabbedFace.mDistance < mMaxDist) \
{ \
HANDLE_CONTACT(prim_index, flag) \
} \
@@ -203,13 +188,8 @@ using namespace Opcode;
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
RayCollider::RayCollider() :
#ifdef OPC_RAYHIT_CALLBACK
mHitCallback (null),
mUserData (0),
#else
mStabbedFaces (null),
mClosestHit (false),
#endif
mNbRayBVTests (0),
mNbRayPrimTests (0),
mNbIntersections (0),
@@ -236,12 +216,12 @@ RayCollider::~RayCollider()
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
const char* RayCollider::ValidateSettings()
{
if(mMaxDist<0.0f) return "Higher distance bound must be positive!";
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;
}
@@ -268,18 +248,19 @@ bool RayCollider::Collide(const Ray& world_ray, const Model& model, const Matrix
// Init collision query
if(InitQuery(world_ray, world, cache)) return true;
const AABBNoLeafTree* Tree = (const AABBNoLeafTree*)model.GetTree();
const AABBNoLeafTree* Tree = (const AABBNoLeafTree*)model.GetTree();
// Perform stabbing query
if(IR(mMaxDist)!=IEEE_MAX_FLOAT) _SegmentStab(Tree->GetNodes());
else _RayStab(Tree->GetNodes());
// Perform stabbing query
if(mMaxDist != MAX_FLOAT)
_SegmentStab(Tree->GetNodes());
else
_RayStab(Tree->GetNodes());
// Update cache if needed
UPDATE_CACHE
return true;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Initializes a stabbing query :
@@ -301,9 +282,9 @@ BOOL RayCollider::InitQuery(const Ray& world_ray, const Matrix4x4* world, udword
mNbRayBVTests = 0;
mNbRayPrimTests = 0;
mNbIntersections = 0;
#ifndef OPC_RAYHIT_CALLBACK
if(mStabbedFaces) mStabbedFaces->Reset();
#endif
if(mStabbedFaces)
mStabbedFaces->Reset();
// Compute ray in local space
// The (Origin/Dir) form is needed for the ray-triangle test anyway (even for segment tests)
@@ -341,48 +322,16 @@ BOOL RayCollider::InitQuery(const Ray& world_ray, const Matrix4x4* world, udword
// Test previously colliding primitives first
if(TemporalCoherenceEnabled() && FirstContactEnabled() && face_id && *face_id!=INVALID_ID)
{
#ifdef OLD_CODE
#ifndef OPC_RAYHIT_CALLBACK
if(!mClosestHit)
#endif
{
// Request vertices from the app
VertexPointers VP;
ConversionArea VC;
mIMesh->GetTriangle(VP, *face_id, VC);
// 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
if(GetContactStatus())
return TRUE;
}
// Precompute data (moved after temporal coherence since only needed for ray-AABB)
if(IR(mMaxDist)!=IEEE_MAX_FLOAT)
if(mMaxDist != MAX_FLOAT)
{
// For Segment-AABB overlap
mData = 0.5f * mDir * mMaxDist;
@@ -470,36 +419,6 @@ void RayCollider::_SegmentStab(const AABBCollisionNode* node)
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* 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.
@@ -526,36 +445,6 @@ void RayCollider::_SegmentStab(const AABBNoLeafNode* node)
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());
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
@@ -608,36 +497,6 @@ void RayCollider::_RayStab(const AABBCollisionNode* node)
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* 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.
@@ -664,37 +523,6 @@ void RayCollider::_RayStab(const AABBNoLeafNode* node)
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.
@@ -24,48 +24,49 @@
{
public:
//! Constructor
inline_ CollisionFace() {}
inline_ CollisionFace() {}
//! Destructor
inline_ ~CollisionFace() {}
inline_ ~CollisionFace() {}
udword mFaceID; //!< Index of touched face
float mDistance; //!< Distance from collider to hitpoint
float mU, mV; //!< Impact barycentric coordinates
udword mFaceID; //!< Index of touched face
float mDistance; //!< Distance from collider to hitpoint
float mU, mV; //!< Impact barycentric coordinates
};
class OPCODE_API CollisionFaces : public Container
{
public:
//! Constructor
CollisionFaces() {}
CollisionFaces() {}
//! Destructor
~CollisionFaces() {}
~CollisionFaces() {}
inline_ udword GetNbFaces() const { return GetNbEntries()>>2; }
inline_ const CollisionFace* GetFaces() const { return (const CollisionFace*)GetEntries(); }
inline_ udword GetNbFaces() const
{
return GetNbEntries() >> 2;
}
inline_ const CollisionFace* GetFaces() const
{
return (const CollisionFace*)GetEntries();
}
inline_ void Reset() { Container::Reset(); }
inline_ void Reset()
{
Container::Reset();
}
inline_ void AddFace(const CollisionFace& face) { Add(face.mFaceID).Add(face.mDistance).Add(face.mU).Add(face.mV); }
inline_ void AddFace(const CollisionFace& face)
{
Add(face.mFaceID).Add(face.mDistance).Add(face.mU).Add(face.mV);
}
};
#ifdef OPC_RAYHIT_CALLBACK
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* User-callback, called by OPCODE to record a hit.
* \param hit [in] current hit
* \param user_data [in] user-defined data from SetCallback()
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
typedef void (*HitCallback) (const CollisionFace& hit, void* user_data);
#endif
class OPCODE_API RayCollider : public Collider
{
public:
// Constructor / Destructor
RayCollider();
virtual ~RayCollider();
RayCollider();
virtual ~RayCollider();
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
@@ -81,12 +82,11 @@
* \warning SCALE NOT SUPPORTED. The matrices must contain rotation & translation parts only.
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool Collide(const Ray& world_ray, const Model& model, const Matrix4x4* world=null, udword* cache=null);
bool Collide(const Ray& world_ray, const Model& model, const Matrix4x4* world=null, udword* cache=null);
//
bool Collide(const Ray& world_ray, const AABBTree* tree, Container& box_indices);
bool Collide(const Ray& world_ray, const AABBTree* tree, Container& box_indices);
// Settings
#ifndef OPC_RAYHIT_CALLBACK
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Settings: enable or disable "closest hit" mode.
@@ -96,8 +96,11 @@
* \see SetDestination(StabbedFaces* sf)
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ void SetClosestHit(bool flag) { mClosestHit = flag; }
#endif
inline_ void SetClosestHit(bool flag)
{
mClosestHit = flag;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Settings: enable or disable backface culling.
@@ -107,7 +110,10 @@
* \see SetDestination(StabbedFaces* sf)
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ void SetCulling(bool flag) { mCulling = flag; }
inline_ void SetCulling(bool flag)
{
mCulling = flag;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
@@ -118,12 +124,11 @@
* \see SetDestination(StabbedFaces* sf)
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ void SetMaxDist(float max_dist=MAX_FLOAT) { mMaxDist = max_dist; }
inline_ void SetMaxDist(float max_dist = MAX_FLOAT)
{
mMaxDist = max_dist;
}
#ifdef OPC_RAYHIT_CALLBACK
inline_ void SetHitCallback(HitCallback cb) { mHitCallback = cb; }
inline_ void SetUserData(void* user_data) { mUserData = user_data; }
#else
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Settings: sets the destination array for stabbed faces.
@@ -133,8 +138,10 @@
* \see SetMaxDist(float max_dist)
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ void SetDestination(CollisionFaces* cf) { mStabbedFaces = cf; }
#endif
inline_ void SetDestination(CollisionFaces* cf)
{
mStabbedFaces = cf;
}
// Stats
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
@@ -144,7 +151,10 @@
* \return the number of Ray-BV tests performed during last query
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ udword GetNbRayBVTests() const { return mNbRayBVTests; }
inline_ udword GetNbRayBVTests() const
{
return mNbRayBVTests;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
@@ -154,7 +164,10 @@
* \return the number of Ray-Triangle tests performed during last query
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ udword GetNbRayPrimTests() const { return mNbRayPrimTests; }
inline_ udword GetNbRayPrimTests() const
{
return mNbRayPrimTests;
}
// In-out test
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -165,7 +178,10 @@
* \return the number of valid intersections during last query
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline_ udword GetNbIntersections() const { return mNbIntersections; }
inline_ udword GetNbIntersections() const
{
return mNbIntersections;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
@@ -177,48 +193,38 @@
protected:
// Ray in local space
Point mOrigin; //!< Ray origin
Point mDir; //!< Ray direction (normalized)
Point mFDir; //!< fabsf(mDir)
Point mData, mData2;
Point mOrigin; //!< Ray origin
Point mDir; //!< Ray direction (normalized)
Point mFDir; //!< fabsf(mDir)
Point mData, mData2;
// Stabbed faces
CollisionFace mStabbedFace; //!< Current stabbed face
#ifdef OPC_RAYHIT_CALLBACK
HitCallback mHitCallback; //!< Callback used to record a hit
void* mUserData; //!< User-defined data
#else
CollisionFaces* mStabbedFaces; //!< List of stabbed faces
bool mClosestHit; //!< Report closest hit only
#endif
CollisionFace mStabbedFace; //!< Current stabbed face
CollisionFaces* mStabbedFaces; //!< List of stabbed faces
bool mClosestHit; //!< Report closest hit only
// Stats
udword mNbRayBVTests; //!< Number of Ray-BV tests
udword mNbRayPrimTests; //!< Number of Ray-Primitive tests
udword mNbRayBVTests; //!< Number of Ray-BV tests
udword mNbRayPrimTests; //!< Number of Ray-Primitive tests
// In-out test
udword mNbIntersections; //!< Number of valid intersections
udword mNbIntersections; //!< Number of valid intersections
// Dequantization coeffs
Point mCenterCoeff;
Point mExtentsCoeff;
Point mCenterCoeff;
Point mExtentsCoeff;
// Settings
float mMaxDist; //!< Valid segment on the ray
bool mCulling; //!< Stab culled faces or not
float mMaxDist; //!< Valid segment on the ray
bool mCulling; //!< Stab culled faces or not
// Internal methods
void _SegmentStab(const AABBCollisionNode* node);
void _SegmentStab(const AABBNoLeafNode* node);
void _SegmentStab(const AABBQuantizedNode* node);
void _SegmentStab(const AABBQuantizedNoLeafNode* node);
void _SegmentStab(const AABBTreeNode* node, Container& box_indices);
void _RayStab(const AABBCollisionNode* node);
void _RayStab(const AABBNoLeafNode* node);
void _RayStab(const AABBQuantizedNode* node);
void _RayStab(const AABBQuantizedNoLeafNode* node);
void _RayStab(const AABBTreeNode* node, Container& box_indices);
// Overlap tests
inline_ BOOL RayAABBOverlap(const Point& center, const Point& extents);
inline_ BOOL SegmentAABBOverlap(const Point& center, const Point& extents);
inline_ BOOL RayTriOverlap(const Point& vert0, const Point& vert1, const Point& vert2);
void _SegmentStab(const AABBCollisionNode* node);
void _SegmentStab(const AABBNoLeafNode* node);
void _SegmentStab(const AABBTreeNode* node, Container& box_indices);
void _RayStab(const AABBCollisionNode* node);
void _RayStab(const AABBNoLeafNode* node);
void _RayStab(const AABBTreeNode* node, Container& box_indices);
// Overlap tests
inline_ BOOL RayAABBOverlap(const Point& center, const Point& extents);
inline_ BOOL SegmentAABBOverlap(const Point& center, const Point& extents);
inline_ BOOL RayTriOverlap(const Point& vert0, const Point& vert1, const Point& vert2);
// Init methods
BOOL InitQuery(const Ray& world_ray, const Matrix4x4* world=null, udword* face_id=null);
BOOL InitQuery(const Ray& world_ray, const Matrix4x4* world=null, udword* face_id=null);
};
#endif // __OPC_RAYCOLLIDER_H__
@@ -23,10 +23,10 @@ inline_ BOOL RayCollider::RayTriOverlap(const Point& vert0, const Point& vert1,
Point edge2 = vert2 - vert0;
// Begin calculating determinant - also used to calculate U parameter
Point pvec = mDir^edge2;
Point pvec = mDir ^ edge2;
// If determinant is near zero, ray lies in plane of triangle
float det = edge1|pvec;
float det = edge1 | pvec;
if(mCulling)
{
@@ -62,7 +62,7 @@ inline_ BOOL RayCollider::RayTriOverlap(const Point& vert0, const Point& vert1,
else
{
// the non-culling branch
if(FastFabs(det) <= LOCAL_EPSILON * FCMin2(edge1.SquareMagnitude(), edge2.SquareMagnitude())) return FALSE;
if(fabsf(det) <= LOCAL_EPSILON * FCMin2(edge1.SquareMagnitude(), edge2.SquareMagnitude())) return FALSE;
float OneOverDet = 1.0f / det;
// Calculate distance from vert0 to ray origin
@@ -32,9 +32,6 @@
//! Discard negative pointer in vanilla trees
#define OPC_NO_NEG_VANILLA_TREE
//! Use a callback in the ray collider
//#define OPC_RAYHIT_CALLBACK
// NB: no compilation flag to enable/disable stats since they're actually needed in the box/box overlap test
#endif //__OPC_SETTINGS_H__
@@ -106,8 +106,6 @@
#include "OPC_LSSCollider.h"
#include "OPC_PlanesCollider.h"
// Usages
#include "OPC_Picking.h"
FUNCTION OPCODE_API bool InitOpcode();
FUNCTION OPCODE_API bool CloseOpcode();
@@ -62,7 +62,7 @@ int dCollideTrimeshPlane( dxGeom *o1, dxGeom *o2, int flags, dContactGeom* conta
dReal alpha;
dVector3 vertex;
dVector3 int_vertex; // Intermediate vertex for double precision mode.
//dVector3 int_vertex; // Intermediate vertex for double precision mode.
const unsigned uiTLSKind = trimesh->getParentSpaceTLSKind();
dIASSERT(uiTLSKind == plane->getParentSpaceTLSKind()); // The colliding spaces must use matching cleanup method