Add collision and raycast filtering using bits mask
This commit is contained in:
parent
aae4da54d0
commit
c15b83db4a
|
@ -171,9 +171,12 @@ void CollisionDetection::computeNarrowPhase() {
|
||||||
|
|
||||||
assert(shape1->mBroadPhaseID != shape2->mBroadPhaseID);
|
assert(shape1->mBroadPhaseID != shape2->mBroadPhaseID);
|
||||||
|
|
||||||
// Check that the two shapes are overlapping. If the shapes are not overlapping
|
// Check if the collision filtering allows collision between the two shapes and
|
||||||
// anymore, we remove the overlapping pair.
|
// that the two shapes are still overlapping. Otherwise, we destroy the
|
||||||
if (!mBroadPhaseAlgorithm.testOverlappingShapes(shape1, shape2)) {
|
// overlapping pair
|
||||||
|
if (((shape1->getCollideWithMaskBits() & shape2->getCollisionCategoryBits()) == 0 ||
|
||||||
|
(shape1->getCollisionCategoryBits() & shape2->getCollideWithMaskBits()) == 0) ||
|
||||||
|
!mBroadPhaseAlgorithm.testOverlappingShapes(shape1, shape2)) {
|
||||||
|
|
||||||
std::map<overlappingpairid, OverlappingPair*>::iterator itToRemove = it;
|
std::map<overlappingpairid, OverlappingPair*>::iterator itToRemove = it;
|
||||||
++it;
|
++it;
|
||||||
|
@ -252,12 +255,6 @@ void CollisionDetection::computeNarrowPhaseBetweenShapes(CollisionCallback* call
|
||||||
|
|
||||||
assert(shape1->mBroadPhaseID != shape2->mBroadPhaseID);
|
assert(shape1->mBroadPhaseID != shape2->mBroadPhaseID);
|
||||||
|
|
||||||
bool test1 = shapes1.count(shape1->mBroadPhaseID) == 0;
|
|
||||||
bool test2 = shapes2.count(shape2->mBroadPhaseID) == 0;
|
|
||||||
bool test3 = shapes1.count(shape2->mBroadPhaseID) == 0;
|
|
||||||
bool test4 = shapes2.count(shape1->mBroadPhaseID) == 0;
|
|
||||||
bool test5 = !shapes1.empty() && !shapes2.empty();
|
|
||||||
|
|
||||||
// If both shapes1 and shapes2 sets are non-empty, we check that
|
// If both shapes1 and shapes2 sets are non-empty, we check that
|
||||||
// shape1 is among on set and shape2 is among the other one
|
// shape1 is among on set and shape2 is among the other one
|
||||||
if (!shapes1.empty() && !shapes2.empty() &&
|
if (!shapes1.empty() && !shapes2.empty() &&
|
||||||
|
@ -279,9 +276,12 @@ void CollisionDetection::computeNarrowPhaseBetweenShapes(CollisionCallback* call
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that the two shapes are overlapping. If the shapes are not overlapping
|
// Check if the collision filtering allows collision between the two shapes and
|
||||||
// anymore, we remove the overlapping pair.
|
// that the two shapes are still overlapping. Otherwise, we destroy the
|
||||||
if (!mBroadPhaseAlgorithm.testOverlappingShapes(shape1, shape2)) {
|
// overlapping pair
|
||||||
|
if (((shape1->getCollideWithMaskBits() & shape2->getCollisionCategoryBits()) == 0 ||
|
||||||
|
(shape1->getCollisionCategoryBits() & shape2->getCollideWithMaskBits()) == 0) ||
|
||||||
|
!mBroadPhaseAlgorithm.testOverlappingShapes(shape1, shape2)) {
|
||||||
|
|
||||||
std::map<overlappingpairid, OverlappingPair*>::iterator itToRemove = it;
|
std::map<overlappingpairid, OverlappingPair*>::iterator itToRemove = it;
|
||||||
++it;
|
++it;
|
||||||
|
@ -345,6 +345,10 @@ void CollisionDetection::broadPhaseNotifyOverlappingPair(ProxyShape* shape1, Pro
|
||||||
// If the two proxy collision shapes are from the same body, skip it
|
// If the two proxy collision shapes are from the same body, skip it
|
||||||
if (shape1->getBody()->getID() == shape2->getBody()->getID()) return;
|
if (shape1->getBody()->getID() == shape2->getBody()->getID()) return;
|
||||||
|
|
||||||
|
// Check if the collision filtering allows collision between the two shapes
|
||||||
|
if ((shape1->getCollideWithMaskBits() & shape2->getCollisionCategoryBits()) == 0 ||
|
||||||
|
(shape1->getCollisionCategoryBits() & shape2->getCollideWithMaskBits()) == 0) return;
|
||||||
|
|
||||||
// Compute the overlapping pair ID
|
// Compute the overlapping pair ID
|
||||||
overlappingpairid pairID = OverlappingPair::computeID(shape1, shape2);
|
overlappingpairid pairID = OverlappingPair::computeID(shape1, shape2);
|
||||||
|
|
||||||
|
@ -358,6 +362,10 @@ void CollisionDetection::broadPhaseNotifyOverlappingPair(ProxyShape* shape1, Pro
|
||||||
std::pair<map<overlappingpairid, OverlappingPair*>::iterator, bool> check =
|
std::pair<map<overlappingpairid, OverlappingPair*>::iterator, bool> check =
|
||||||
mOverlappingPairs.insert(make_pair(pairID, newPair));
|
mOverlappingPairs.insert(make_pair(pairID, newPair));
|
||||||
assert(check.second);
|
assert(check.second);
|
||||||
|
|
||||||
|
// Wake up the two bodies
|
||||||
|
shape1->getBody()->setIsSleeping(false);
|
||||||
|
shape2->getBody()->setIsSleeping(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove a body from the collision detection
|
// Remove a body from the collision detection
|
||||||
|
|
|
@ -153,7 +153,8 @@ class CollisionDetection {
|
||||||
const std::set<uint>& shapes2) ;
|
const std::set<uint>& shapes2) ;
|
||||||
|
|
||||||
/// Ray casting method
|
/// Ray casting method
|
||||||
void raycast(RaycastCallback* raycastCallback, const Ray& ray) const;
|
void raycast(RaycastCallback* raycastCallback, const Ray& ray,
|
||||||
|
unsigned short raycastWithCategoryMaskBits) const;
|
||||||
|
|
||||||
/// Test if the AABBs of two bodies overlap
|
/// Test if the AABBs of two bodies overlap
|
||||||
bool testAABBOverlap(const CollisionBody* body1,
|
bool testAABBOverlap(const CollisionBody* body1,
|
||||||
|
@ -228,13 +229,14 @@ inline void CollisionDetection::updateProxyCollisionShape(ProxyShape* shape, con
|
||||||
|
|
||||||
// Ray casting method
|
// Ray casting method
|
||||||
inline void CollisionDetection::raycast(RaycastCallback* raycastCallback,
|
inline void CollisionDetection::raycast(RaycastCallback* raycastCallback,
|
||||||
const Ray& ray) const {
|
const Ray& ray,
|
||||||
|
unsigned short raycastWithCategoryMaskBits) const {
|
||||||
|
|
||||||
RaycastTest rayCastTest(raycastCallback);
|
RaycastTest rayCastTest(raycastCallback);
|
||||||
|
|
||||||
// Ask the broad-phase algorithm to call the testRaycastAgainstShape()
|
// Ask the broad-phase algorithm to call the testRaycastAgainstShape()
|
||||||
// callback method for each proxy shape hit by the ray in the broad-phase
|
// callback method for each proxy shape hit by the ray in the broad-phase
|
||||||
mBroadPhaseAlgorithm.raycast(ray, rayCastTest);
|
mBroadPhaseAlgorithm.raycast(ray, rayCastTest, raycastWithCategoryMaskBits);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test if the AABBs of two proxy shapes overlap
|
// Test if the AABBs of two proxy shapes overlap
|
||||||
|
|
|
@ -8,7 +8,8 @@ using namespace reactphysics3d;
|
||||||
ProxyShape::ProxyShape(CollisionBody* body, CollisionShape* shape, const Transform& transform,
|
ProxyShape::ProxyShape(CollisionBody* body, CollisionShape* shape, const Transform& transform,
|
||||||
decimal mass)
|
decimal mass)
|
||||||
:mBody(body), mCollisionShape(shape), mLocalToBodyTransform(transform), mMass(mass),
|
:mBody(body), mCollisionShape(shape), mLocalToBodyTransform(transform), mMass(mass),
|
||||||
mNext(NULL), mBroadPhaseID(-1), mCachedCollisionData(NULL), mUserData(NULL) {
|
mNext(NULL), mBroadPhaseID(-1), mCachedCollisionData(NULL), mUserData(NULL),
|
||||||
|
mCollisionCategoryBits(0x0001), mCollideWithMaskBits(0xFFFF) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -47,6 +47,19 @@ class ProxyShape {
|
||||||
/// Pointer to user data
|
/// Pointer to user data
|
||||||
void* mUserData;
|
void* mUserData;
|
||||||
|
|
||||||
|
/// Bits used to define the collision category of this shape.
|
||||||
|
/// You can set a single bit to one to define a category value for this
|
||||||
|
/// shape. This value is one (0x0001) by default. This variable can be used
|
||||||
|
/// together with the mCollideWithMaskBits variable so that given
|
||||||
|
/// categories of shapes collide with each other and do not collide with
|
||||||
|
/// other categories.
|
||||||
|
unsigned short mCollisionCategoryBits;
|
||||||
|
|
||||||
|
/// Bits mask used to state which collision categories this shape can
|
||||||
|
/// collide with. This value is 0xFFFF by default. It means that this
|
||||||
|
/// proxy shape will collide with every collision categories by default.
|
||||||
|
unsigned short mCollideWithMaskBits;
|
||||||
|
|
||||||
// -------------------- Methods -------------------- //
|
// -------------------- Methods -------------------- //
|
||||||
|
|
||||||
/// Private copy-constructor
|
/// Private copy-constructor
|
||||||
|
@ -108,6 +121,18 @@ class ProxyShape {
|
||||||
/// Raycast method with feedback information
|
/// Raycast method with feedback information
|
||||||
bool raycast(const Ray& ray, RaycastInfo& raycastInfo);
|
bool raycast(const Ray& ray, RaycastInfo& raycastInfo);
|
||||||
|
|
||||||
|
/// Return the collision category bits
|
||||||
|
unsigned short getCollisionCategoryBits() const;
|
||||||
|
|
||||||
|
/// Set the collision category bits
|
||||||
|
void setCollisionCategoryBits(unsigned short collisionCategoryBits);
|
||||||
|
|
||||||
|
/// Return the collision bits mask
|
||||||
|
unsigned short getCollideWithMaskBits() const;
|
||||||
|
|
||||||
|
/// Set the collision bits mask
|
||||||
|
void setCollideWithMaskBits(unsigned short collideWithMaskBits);
|
||||||
|
|
||||||
// -------------------- Friendship -------------------- //
|
// -------------------- Friendship -------------------- //
|
||||||
|
|
||||||
friend class OverlappingPair;
|
friend class OverlappingPair;
|
||||||
|
@ -192,6 +217,26 @@ inline const ProxyShape* ProxyShape::getNext() const {
|
||||||
return mNext;
|
return mNext;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return the collision category bits
|
||||||
|
inline unsigned short ProxyShape::getCollisionCategoryBits() const {
|
||||||
|
return mCollisionCategoryBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the collision category bits
|
||||||
|
inline void ProxyShape::setCollisionCategoryBits(unsigned short collisionCategoryBits) {
|
||||||
|
mCollisionCategoryBits = collisionCategoryBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the collision bits mask
|
||||||
|
inline unsigned short ProxyShape::getCollideWithMaskBits() const {
|
||||||
|
return mCollideWithMaskBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the collision bits mask
|
||||||
|
inline void ProxyShape::setCollideWithMaskBits(unsigned short collideWithMaskBits) {
|
||||||
|
mCollideWithMaskBits = collideWithMaskBits;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -159,7 +159,8 @@ class BroadPhaseAlgorithm {
|
||||||
bool testOverlappingShapes(const ProxyShape* shape1, const ProxyShape* shape2) const;
|
bool testOverlappingShapes(const ProxyShape* shape1, const ProxyShape* shape2) const;
|
||||||
|
|
||||||
/// Ray casting method
|
/// Ray casting method
|
||||||
void raycast(const Ray& ray, RaycastTest& raycastTest) const;
|
void raycast(const Ray& ray, RaycastTest& raycastTest,
|
||||||
|
unsigned short raycastWithCategoryMaskBits) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Method used to compare two pairs for sorting algorithm
|
// Method used to compare two pairs for sorting algorithm
|
||||||
|
@ -185,8 +186,9 @@ inline bool BroadPhaseAlgorithm::testOverlappingShapes(const ProxyShape* shape1,
|
||||||
|
|
||||||
// Ray casting method
|
// Ray casting method
|
||||||
inline void BroadPhaseAlgorithm::raycast(const Ray& ray,
|
inline void BroadPhaseAlgorithm::raycast(const Ray& ray,
|
||||||
RaycastTest& raycastTest) const {
|
RaycastTest& raycastTest,
|
||||||
mDynamicAABBTree.raycast(ray, raycastTest);
|
unsigned short raycastWithCategoryMaskBits) const {
|
||||||
|
mDynamicAABBTree.raycast(ray, raycastTest, raycastWithCategoryMaskBits);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -606,7 +606,8 @@ void DynamicAABBTree::reportAllShapesOverlappingWith(int nodeID, const AABB& aab
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ray casting method
|
// Ray casting method
|
||||||
void DynamicAABBTree::raycast(const Ray& ray, RaycastTest& raycastTest) const {
|
void DynamicAABBTree::raycast(const Ray& ray, RaycastTest& raycastTest,
|
||||||
|
unsigned short raycastWithCategoryMaskBits) const {
|
||||||
|
|
||||||
decimal maxFraction = ray.maxFraction;
|
decimal maxFraction = ray.maxFraction;
|
||||||
|
|
||||||
|
@ -638,35 +639,39 @@ void DynamicAABBTree::raycast(const Ray& ray, RaycastTest& raycastTest) const {
|
||||||
// If the node is a leaf of the tree
|
// If the node is a leaf of the tree
|
||||||
if (node->isLeaf()) {
|
if (node->isLeaf()) {
|
||||||
|
|
||||||
Ray rayTemp(ray.point1, ray.point2, maxFraction);
|
// Check if the raycast filtering mask allows raycast against this shape
|
||||||
|
if ((raycastWithCategoryMaskBits & node->proxyShape->getCollisionCategoryBits()) != 0) {
|
||||||
|
|
||||||
// Ask the collision detection to perform a ray cast test against
|
Ray rayTemp(ray.point1, ray.point2, maxFraction);
|
||||||
// the proxy shape of this node because the ray is overlapping
|
|
||||||
// with the shape in the broad-phase
|
|
||||||
decimal hitFraction = raycastTest.raycastAgainstShape(node->proxyShape,
|
|
||||||
rayTemp);
|
|
||||||
|
|
||||||
// If the user returned a hitFraction of zero, it means that
|
// Ask the collision detection to perform a ray cast test against
|
||||||
// the raycasting should stop here
|
// the proxy shape of this node because the ray is overlapping
|
||||||
if (hitFraction == decimal(0.0)) {
|
// with the shape in the broad-phase
|
||||||
return;
|
decimal hitFraction = raycastTest.raycastAgainstShape(node->proxyShape,
|
||||||
}
|
rayTemp);
|
||||||
|
|
||||||
// If the user returned a positive fraction
|
// If the user returned a hitFraction of zero, it means that
|
||||||
if (hitFraction > decimal(0.0)) {
|
// the raycasting should stop here
|
||||||
|
if (hitFraction == decimal(0.0)) {
|
||||||
// We update the maxFraction value and the ray
|
return;
|
||||||
// AABB using the new maximum fraction
|
|
||||||
if (hitFraction < maxFraction) {
|
|
||||||
maxFraction = hitFraction;
|
|
||||||
}
|
}
|
||||||
endPoint = ray.point1 + maxFraction * (ray.point2 - ray.point1);
|
|
||||||
rayAABB.mMinCoordinates = Vector3::min(ray.point1, endPoint);
|
|
||||||
rayAABB.mMaxCoordinates = Vector3::max(ray.point1, endPoint);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the user returned a negative fraction, we continue
|
// If the user returned a positive fraction
|
||||||
// the raycasting as if the proxy shape did not exist
|
if (hitFraction > decimal(0.0)) {
|
||||||
|
|
||||||
|
// We update the maxFraction value and the ray
|
||||||
|
// AABB using the new maximum fraction
|
||||||
|
if (hitFraction < maxFraction) {
|
||||||
|
maxFraction = hitFraction;
|
||||||
|
}
|
||||||
|
endPoint = ray.point1 + maxFraction * (ray.point2 - ray.point1);
|
||||||
|
rayAABB.mMinCoordinates = Vector3::min(ray.point1, endPoint);
|
||||||
|
rayAABB.mMaxCoordinates = Vector3::max(ray.point1, endPoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the user returned a negative fraction, we continue
|
||||||
|
// the raycasting as if the proxy shape did not exist
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
else { // If the node has children
|
else { // If the node has children
|
||||||
|
|
|
@ -168,7 +168,8 @@ class DynamicAABBTree {
|
||||||
void reportAllShapesOverlappingWith(int nodeID, const AABB& aabb);
|
void reportAllShapesOverlappingWith(int nodeID, const AABB& aabb);
|
||||||
|
|
||||||
/// Ray casting method
|
/// Ray casting method
|
||||||
void raycast(const Ray& ray, RaycastTest& raycastTest) const;
|
void raycast(const Ray& ray, RaycastTest& raycastTest,
|
||||||
|
unsigned short raycastWithCategoryMaskBits) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Return true if the node is a leaf of the tree
|
// Return true if the node is a leaf of the tree
|
||||||
|
|
|
@ -124,7 +124,8 @@ class CollisionWorld {
|
||||||
void destroyCollisionBody(CollisionBody* collisionBody);
|
void destroyCollisionBody(CollisionBody* collisionBody);
|
||||||
|
|
||||||
/// Ray cast method
|
/// Ray cast method
|
||||||
void raycast(const Ray& ray, RaycastCallback* raycastCallback) const;
|
void raycast(const Ray& ray, RaycastCallback* raycastCallback,
|
||||||
|
unsigned short raycastWithCategoryMaskBits = 0xFFFF) const;
|
||||||
|
|
||||||
/// Test if the AABBs of two bodies overlap
|
/// Test if the AABBs of two bodies overlap
|
||||||
bool testAABBOverlap(const CollisionBody* body1,
|
bool testAABBOverlap(const CollisionBody* body1,
|
||||||
|
@ -177,8 +178,9 @@ inline std::set<CollisionBody*>::iterator CollisionWorld::getBodiesEndIterator()
|
||||||
|
|
||||||
// Ray cast method
|
// Ray cast method
|
||||||
inline void CollisionWorld::raycast(const Ray& ray,
|
inline void CollisionWorld::raycast(const Ray& ray,
|
||||||
RaycastCallback* raycastCallback) const {
|
RaycastCallback* raycastCallback,
|
||||||
mCollisionDetection.raycast(raycastCallback, ray);
|
unsigned short raycastWithCategoryMaskBits) const {
|
||||||
|
mCollisionDetection.raycast(raycastCallback, ray, raycastWithCategoryMaskBits);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test if the AABBs of two proxy shapes overlap
|
// Test if the AABBs of two proxy shapes overlap
|
||||||
|
|
|
@ -32,6 +32,13 @@
|
||||||
/// Reactphysics3D namespace
|
/// Reactphysics3D namespace
|
||||||
namespace reactphysics3d {
|
namespace reactphysics3d {
|
||||||
|
|
||||||
|
// Enumeration for categories
|
||||||
|
enum CollisionCategory {
|
||||||
|
CATEGORY_1 = 0x0001,
|
||||||
|
CATEGORY_2 = 0x0002,
|
||||||
|
CATEGORY_3 = 0x0004
|
||||||
|
};
|
||||||
|
|
||||||
// Class
|
// Class
|
||||||
class WorldCollisionCallback : public CollisionCallback
|
class WorldCollisionCallback : public CollisionCallback
|
||||||
{
|
{
|
||||||
|
@ -60,7 +67,6 @@ class WorldCollisionCallback : public CollisionCallback
|
||||||
sphere1CollideWithSphere2 = false;
|
sphere1CollideWithSphere2 = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// This method will be called for contact
|
// This method will be called for contact
|
||||||
virtual void notifyContact(const ContactPointInfo& contactPointInfo) {
|
virtual void notifyContact(const ContactPointInfo& contactPointInfo) {
|
||||||
|
|
||||||
|
@ -145,6 +151,12 @@ class TestCollisionWorld : public Test {
|
||||||
CylinderShape cylinderShape(2, 5);
|
CylinderShape cylinderShape(2, 5);
|
||||||
mCylinderShape = mCylinderBody->addCollisionShape(cylinderShape, Transform::identity());
|
mCylinderShape = mCylinderBody->addCollisionShape(cylinderShape, Transform::identity());
|
||||||
|
|
||||||
|
// Assign collision categories to proxy shapes
|
||||||
|
mBoxShape->setCollisionCategoryBits(CATEGORY_1);
|
||||||
|
mSphere1Shape->setCollisionCategoryBits(CATEGORY_1);
|
||||||
|
mSphere2Shape->setCollisionCategoryBits(CATEGORY_2);
|
||||||
|
mCylinderShape->setCollisionCategoryBits(CATEGORY_3);
|
||||||
|
|
||||||
mCollisionCallback.boxBody = mBoxBody;
|
mCollisionCallback.boxBody = mBoxBody;
|
||||||
mCollisionCallback.sphere1Body = mSphere1Body;
|
mCollisionCallback.sphere1Body = mSphere1Body;
|
||||||
mCollisionCallback.sphere2Body = mSphere2Body;
|
mCollisionCallback.sphere2Body = mSphere2Body;
|
||||||
|
@ -235,7 +247,11 @@ class TestCollisionWorld : public Test {
|
||||||
test(!mCollisionCallback.sphere1CollideWithCylinder);
|
test(!mCollisionCallback.sphere1CollideWithCylinder);
|
||||||
test(!mCollisionCallback.sphere1CollideWithSphere2);
|
test(!mCollisionCallback.sphere1CollideWithSphere2);
|
||||||
|
|
||||||
// Test collision with inactive bodies
|
// Move sphere 1 to collide with box
|
||||||
|
mSphere1Body->setTransform(Transform(Vector3(10, 5, 0), Quaternion::identity()));
|
||||||
|
|
||||||
|
// --------- Test collision with inactive bodies --------- //
|
||||||
|
|
||||||
mCollisionCallback.reset();
|
mCollisionCallback.reset();
|
||||||
mBoxBody->setIsActive(false);
|
mBoxBody->setIsActive(false);
|
||||||
mCylinderBody->setIsActive(false);
|
mCylinderBody->setIsActive(false);
|
||||||
|
@ -261,6 +277,50 @@ class TestCollisionWorld : public Test {
|
||||||
mCylinderBody->setIsActive(true);
|
mCylinderBody->setIsActive(true);
|
||||||
mSphere1Body->setIsActive(true);
|
mSphere1Body->setIsActive(true);
|
||||||
mSphere2Body->setIsActive(true);
|
mSphere2Body->setIsActive(true);
|
||||||
|
|
||||||
|
// --------- Test collision with collision filtering -------- //
|
||||||
|
|
||||||
|
mBoxShape->setCollideWithMaskBits(CATEGORY_1 | CATEGORY_3);
|
||||||
|
mSphere1Shape->setCollideWithMaskBits(CATEGORY_1 | CATEGORY_2);
|
||||||
|
mSphere2Shape->setCollideWithMaskBits(CATEGORY_1);
|
||||||
|
mCylinderShape->setCollideWithMaskBits(CATEGORY_1);
|
||||||
|
|
||||||
|
mCollisionCallback.reset();
|
||||||
|
mWorld->testCollision(&mCollisionCallback);
|
||||||
|
test(mCollisionCallback.boxCollideWithSphere1);
|
||||||
|
test(mCollisionCallback.boxCollideWithCylinder);
|
||||||
|
test(!mCollisionCallback.sphere1CollideWithCylinder);
|
||||||
|
test(!mCollisionCallback.sphere1CollideWithSphere2);
|
||||||
|
|
||||||
|
// Move sphere 1 to collide with sphere 2
|
||||||
|
mSphere1Body->setTransform(Transform(Vector3(30, 15, 10), Quaternion::identity()));
|
||||||
|
|
||||||
|
mCollisionCallback.reset();
|
||||||
|
mWorld->testCollision(&mCollisionCallback);
|
||||||
|
test(!mCollisionCallback.boxCollideWithSphere1);
|
||||||
|
test(mCollisionCallback.boxCollideWithCylinder);
|
||||||
|
test(!mCollisionCallback.sphere1CollideWithCylinder);
|
||||||
|
test(mCollisionCallback.sphere1CollideWithSphere2);
|
||||||
|
|
||||||
|
mBoxShape->setCollideWithMaskBits(CATEGORY_2);
|
||||||
|
mSphere1Shape->setCollideWithMaskBits(CATEGORY_2);
|
||||||
|
mSphere2Shape->setCollideWithMaskBits(CATEGORY_3);
|
||||||
|
mCylinderShape->setCollideWithMaskBits(CATEGORY_1);
|
||||||
|
|
||||||
|
mCollisionCallback.reset();
|
||||||
|
mWorld->testCollision(&mCollisionCallback);
|
||||||
|
test(!mCollisionCallback.boxCollideWithSphere1);
|
||||||
|
test(!mCollisionCallback.boxCollideWithCylinder);
|
||||||
|
test(!mCollisionCallback.sphere1CollideWithCylinder);
|
||||||
|
test(!mCollisionCallback.sphere1CollideWithSphere2);
|
||||||
|
|
||||||
|
// Move sphere 1 to collide with box
|
||||||
|
mSphere1Body->setTransform(Transform(Vector3(10, 5, 0), Quaternion::identity()));
|
||||||
|
|
||||||
|
mBoxShape->setCollideWithMaskBits(0xFFFF);
|
||||||
|
mSphere1Shape->setCollideWithMaskBits(0xFFFF);
|
||||||
|
mSphere2Shape->setCollideWithMaskBits(0xFFFF);
|
||||||
|
mCylinderShape->setCollideWithMaskBits(0xFFFF);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -40,6 +40,12 @@
|
||||||
/// Reactphysics3D namespace
|
/// Reactphysics3D namespace
|
||||||
namespace reactphysics3d {
|
namespace reactphysics3d {
|
||||||
|
|
||||||
|
// Enumeration for categories
|
||||||
|
enum Category {
|
||||||
|
CATEGORY1 = 0x0001,
|
||||||
|
CATEGORY2 = 0x0002
|
||||||
|
};
|
||||||
|
|
||||||
/// Class WorldRaycastCallback
|
/// Class WorldRaycastCallback
|
||||||
class WorldRaycastCallback : public RaycastCallback {
|
class WorldRaycastCallback : public RaycastCallback {
|
||||||
|
|
||||||
|
@ -220,6 +226,17 @@ class TestRaycast : public Test {
|
||||||
mLocalShape2ToWorld = mBodyTransform * shapeTransform2;
|
mLocalShape2ToWorld = mBodyTransform * shapeTransform2;
|
||||||
mCompoundCylinderShape = mCompoundBody->addCollisionShape(cylinderShape, mShapeTransform);
|
mCompoundCylinderShape = mCompoundBody->addCollisionShape(cylinderShape, mShapeTransform);
|
||||||
mCompoundSphereShape = mCompoundBody->addCollisionShape(sphereShape, shapeTransform2);
|
mCompoundSphereShape = mCompoundBody->addCollisionShape(sphereShape, shapeTransform2);
|
||||||
|
|
||||||
|
// Assign proxy shapes to the different categories
|
||||||
|
mBoxShape->setCollisionCategoryBits(CATEGORY1);
|
||||||
|
mSphereShape->setCollisionCategoryBits(CATEGORY1);
|
||||||
|
mCapsuleShape->setCollisionCategoryBits(CATEGORY1);
|
||||||
|
mConeShape->setCollisionCategoryBits(CATEGORY2);
|
||||||
|
mConvexMeshShape->setCollisionCategoryBits(CATEGORY2);
|
||||||
|
mConvexMeshShapeEdgesInfo->setCollisionCategoryBits(CATEGORY2);
|
||||||
|
mCylinderShape->setCollisionCategoryBits(CATEGORY2);
|
||||||
|
mCompoundSphereShape->setCollisionCategoryBits(CATEGORY2);
|
||||||
|
mCompoundCylinderShape->setCollisionCategoryBits(CATEGORY2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Run the tests
|
/// Run the tests
|
||||||
|
@ -256,6 +273,16 @@ class TestRaycast : public Test {
|
||||||
test(approxEqual(callback.raycastInfo.worldPoint.y, hitPoint.y, epsilon));
|
test(approxEqual(callback.raycastInfo.worldPoint.y, hitPoint.y, epsilon));
|
||||||
test(approxEqual(callback.raycastInfo.worldPoint.z, hitPoint.z, epsilon));
|
test(approxEqual(callback.raycastInfo.worldPoint.z, hitPoint.z, epsilon));
|
||||||
|
|
||||||
|
// Correct category filter mask
|
||||||
|
callback.reset();
|
||||||
|
mWorld->raycast(ray, &callback, CATEGORY1);
|
||||||
|
test(callback.isHit);
|
||||||
|
|
||||||
|
// Wrong category filter mask
|
||||||
|
callback.reset();
|
||||||
|
mWorld->raycast(ray, &callback, CATEGORY2);
|
||||||
|
test(!callback.isHit);
|
||||||
|
|
||||||
// CollisionBody::raycast()
|
// CollisionBody::raycast()
|
||||||
RaycastInfo raycastInfo2;
|
RaycastInfo raycastInfo2;
|
||||||
test(mBoxBody->raycast(ray, raycastInfo2));
|
test(mBoxBody->raycast(ray, raycastInfo2));
|
||||||
|
@ -458,6 +485,16 @@ class TestRaycast : public Test {
|
||||||
test(approxEqual(callback.raycastInfo.worldPoint.y, hitPoint.y, epsilon));
|
test(approxEqual(callback.raycastInfo.worldPoint.y, hitPoint.y, epsilon));
|
||||||
test(approxEqual(callback.raycastInfo.worldPoint.z, hitPoint.z, epsilon));
|
test(approxEqual(callback.raycastInfo.worldPoint.z, hitPoint.z, epsilon));
|
||||||
|
|
||||||
|
// Correct category filter mask
|
||||||
|
callback.reset();
|
||||||
|
mWorld->raycast(ray, &callback, CATEGORY1);
|
||||||
|
test(callback.isHit);
|
||||||
|
|
||||||
|
// Wrong category filter mask
|
||||||
|
callback.reset();
|
||||||
|
mWorld->raycast(ray, &callback, CATEGORY2);
|
||||||
|
test(!callback.isHit);
|
||||||
|
|
||||||
// CollisionBody::raycast()
|
// CollisionBody::raycast()
|
||||||
RaycastInfo raycastInfo2;
|
RaycastInfo raycastInfo2;
|
||||||
test(mSphereBody->raycast(ray, raycastInfo2));
|
test(mSphereBody->raycast(ray, raycastInfo2));
|
||||||
|
@ -668,6 +705,16 @@ class TestRaycast : public Test {
|
||||||
test(approxEqual(callback.raycastInfo.worldPoint.y, hitPoint.y, epsilon));
|
test(approxEqual(callback.raycastInfo.worldPoint.y, hitPoint.y, epsilon));
|
||||||
test(approxEqual(callback.raycastInfo.worldPoint.z, hitPoint.z, epsilon));
|
test(approxEqual(callback.raycastInfo.worldPoint.z, hitPoint.z, epsilon));
|
||||||
|
|
||||||
|
// Correct category filter mask
|
||||||
|
callback.reset();
|
||||||
|
mWorld->raycast(ray, &callback, CATEGORY1);
|
||||||
|
test(callback.isHit);
|
||||||
|
|
||||||
|
// Wrong category filter mask
|
||||||
|
callback.reset();
|
||||||
|
mWorld->raycast(ray, &callback, CATEGORY2);
|
||||||
|
test(!callback.isHit);
|
||||||
|
|
||||||
// CollisionBody::raycast()
|
// CollisionBody::raycast()
|
||||||
RaycastInfo raycastInfo2;
|
RaycastInfo raycastInfo2;
|
||||||
test(mCapsuleBody->raycast(ray, raycastInfo2));
|
test(mCapsuleBody->raycast(ray, raycastInfo2));
|
||||||
|
@ -893,6 +940,16 @@ class TestRaycast : public Test {
|
||||||
test(approxEqual(callback.raycastInfo.worldPoint.y, hitPoint.y));
|
test(approxEqual(callback.raycastInfo.worldPoint.y, hitPoint.y));
|
||||||
test(approxEqual(callback.raycastInfo.worldPoint.z, hitPoint.z));
|
test(approxEqual(callback.raycastInfo.worldPoint.z, hitPoint.z));
|
||||||
|
|
||||||
|
// Correct category filter mask
|
||||||
|
callback.reset();
|
||||||
|
mWorld->raycast(ray, &callback, CATEGORY2);
|
||||||
|
test(callback.isHit);
|
||||||
|
|
||||||
|
// Wrong category filter mask
|
||||||
|
callback.reset();
|
||||||
|
mWorld->raycast(ray, &callback, CATEGORY1);
|
||||||
|
test(!callback.isHit);
|
||||||
|
|
||||||
// CollisionBody::raycast()
|
// CollisionBody::raycast()
|
||||||
RaycastInfo raycastInfo2;
|
RaycastInfo raycastInfo2;
|
||||||
test(mConeBody->raycast(ray, raycastInfo2));
|
test(mConeBody->raycast(ray, raycastInfo2));
|
||||||
|
@ -1125,6 +1182,16 @@ class TestRaycast : public Test {
|
||||||
test(approxEqual(callback.raycastInfo.worldPoint.y, hitPoint.y, epsilon));
|
test(approxEqual(callback.raycastInfo.worldPoint.y, hitPoint.y, epsilon));
|
||||||
test(approxEqual(callback.raycastInfo.worldPoint.z, hitPoint.z, epsilon));
|
test(approxEqual(callback.raycastInfo.worldPoint.z, hitPoint.z, epsilon));
|
||||||
|
|
||||||
|
// Correct category filter mask
|
||||||
|
callback.reset();
|
||||||
|
mWorld->raycast(ray, &callback, CATEGORY2);
|
||||||
|
test(callback.isHit);
|
||||||
|
|
||||||
|
// Wrong category filter mask
|
||||||
|
callback.reset();
|
||||||
|
mWorld->raycast(ray, &callback, CATEGORY1);
|
||||||
|
test(!callback.isHit);
|
||||||
|
|
||||||
// CollisionBody::raycast()
|
// CollisionBody::raycast()
|
||||||
RaycastInfo raycastInfo2;
|
RaycastInfo raycastInfo2;
|
||||||
test(mConvexMeshBody->raycast(ray, raycastInfo2));
|
test(mConvexMeshBody->raycast(ray, raycastInfo2));
|
||||||
|
@ -1389,6 +1456,16 @@ class TestRaycast : public Test {
|
||||||
test(approxEqual(callback.raycastInfo.worldPoint.y, hitPoint.y, epsilon));
|
test(approxEqual(callback.raycastInfo.worldPoint.y, hitPoint.y, epsilon));
|
||||||
test(approxEqual(callback.raycastInfo.worldPoint.z, hitPoint.z, epsilon));
|
test(approxEqual(callback.raycastInfo.worldPoint.z, hitPoint.z, epsilon));
|
||||||
|
|
||||||
|
// Correct category filter mask
|
||||||
|
callback.reset();
|
||||||
|
mWorld->raycast(ray, &callback, CATEGORY2);
|
||||||
|
test(callback.isHit);
|
||||||
|
|
||||||
|
// Wrong category filter mask
|
||||||
|
callback.reset();
|
||||||
|
mWorld->raycast(ray, &callback, CATEGORY1);
|
||||||
|
test(!callback.isHit);
|
||||||
|
|
||||||
// CollisionBody::raycast()
|
// CollisionBody::raycast()
|
||||||
RaycastInfo raycastInfo2;
|
RaycastInfo raycastInfo2;
|
||||||
test(mCylinderBody->raycast(ray, raycastInfo2));
|
test(mCylinderBody->raycast(ray, raycastInfo2));
|
||||||
|
@ -1604,6 +1681,16 @@ class TestRaycast : public Test {
|
||||||
|
|
||||||
callback.shapeToTest = mCompoundSphereShape;
|
callback.shapeToTest = mCompoundSphereShape;
|
||||||
|
|
||||||
|
// Correct category filter mask
|
||||||
|
callback.reset();
|
||||||
|
mWorld->raycast(ray1, &callback, CATEGORY2);
|
||||||
|
test(callback.isHit);
|
||||||
|
|
||||||
|
// Wrong category filter mask
|
||||||
|
callback.reset();
|
||||||
|
mWorld->raycast(ray1, &callback, CATEGORY1);
|
||||||
|
test(!callback.isHit);
|
||||||
|
|
||||||
RaycastInfo raycastInfo;
|
RaycastInfo raycastInfo;
|
||||||
test(mCompoundBody->raycast(ray1, raycastInfo));
|
test(mCompoundBody->raycast(ray1, raycastInfo));
|
||||||
callback.reset();
|
callback.reset();
|
||||||
|
|
Loading…
Reference in New Issue
Block a user