From 397b03d5d50fec11ed9a84c4e25d63090a317f28 Mon Sep 17 00:00:00 2001 From: sabrina-shanman Date: Mon, 27 Aug 2018 14:12:24 -0700 Subject: [PATCH] Add threshold parameter to collision pick with minimum of 0 --- interface/src/raypick/CollisionPick.cpp | 4 ++-- libraries/physics/src/PhysicsEngine.cpp | 14 ++++++++++---- libraries/physics/src/PhysicsEngine.h | 2 +- libraries/shared/src/RegisteredMetaTypes.h | 19 +++++++++++++++---- 4 files changed, 28 insertions(+), 11 deletions(-) diff --git a/interface/src/raypick/CollisionPick.cpp b/interface/src/raypick/CollisionPick.cpp index 8c3d28fdfd..407595b86a 100644 --- a/interface/src/raypick/CollisionPick.cpp +++ b/interface/src/raypick/CollisionPick.cpp @@ -391,7 +391,7 @@ PickResultPointer CollisionPick::getEntityIntersection(const CollisionRegion& pi return std::make_shared(pick.toVariantMap(), CollisionPickResult::LOAD_STATE_NOT_LOADED, std::vector(), std::vector()); } - auto entityIntersections = _physicsEngine->contactTest(USER_COLLISION_MASK_ENTITIES, *pick.shapeInfo, pick.transform); + auto entityIntersections = _physicsEngine->contactTest(USER_COLLISION_MASK_ENTITIES, *pick.shapeInfo, pick.transform, USER_COLLISION_GROUP_DYNAMIC, pick.threshold); filterIntersections(entityIntersections); return std::make_shared(pick, CollisionPickResult::LOAD_STATE_LOADED, entityIntersections, std::vector()); } @@ -406,7 +406,7 @@ PickResultPointer CollisionPick::getAvatarIntersection(const CollisionRegion& pi return std::make_shared(pick, CollisionPickResult::LOAD_STATE_NOT_LOADED, std::vector(), std::vector()); } - auto avatarIntersections = _physicsEngine->contactTest(USER_COLLISION_MASK_AVATARS, *pick.shapeInfo, pick.transform); + auto avatarIntersections = _physicsEngine->contactTest(USER_COLLISION_MASK_AVATARS, *pick.shapeInfo, pick.transform, USER_COLLISION_GROUP_DYNAMIC, pick.threshold); filterIntersections(avatarIntersections); return std::make_shared(pick, CollisionPickResult::LOAD_STATE_LOADED, std::vector(), avatarIntersections); } diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index d5ce60bef9..58c197d6f4 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -898,11 +898,12 @@ void PhysicsEngine::setShowBulletConstraintLimits(bool value) { } struct AllContactsCallback : public btCollisionWorld::ContactResultCallback { - AllContactsCallback(int32_t mask, int32_t group, const ShapeInfo& shapeInfo, const Transform& transform, btCollisionObject* myAvatarCollisionObject) : + AllContactsCallback(int32_t mask, int32_t group, const ShapeInfo& shapeInfo, const Transform& transform, btCollisionObject* myAvatarCollisionObject, float threshold) : btCollisionWorld::ContactResultCallback(), collisionObject(), contacts(), - myAvatarCollisionObject(myAvatarCollisionObject) { + myAvatarCollisionObject(myAvatarCollisionObject), + threshold(threshold) { const btCollisionShape* collisionShape = ObjectMotionState::getShapeManager()->getShape(shapeInfo); collisionObject.setCollisionShape(const_cast(collisionShape)); @@ -924,8 +925,13 @@ struct AllContactsCallback : public btCollisionWorld::ContactResultCallback { btCollisionObject collisionObject; std::vector contacts; btCollisionObject* myAvatarCollisionObject; + btScalar threshold; btScalar addSingleResult(btManifoldPoint& cp, const btCollisionObjectWrapper* colObj0, int partId0, int index0, const btCollisionObjectWrapper* colObj1, int partId1, int index1) override { + if (cp.m_distance1 > -threshold) { + return 0; + } + const btCollisionObject* otherBody; btVector3 penetrationPoint; btVector3 otherPenetrationPoint; @@ -968,14 +974,14 @@ protected: } }; -std::vector PhysicsEngine::contactTest(uint16_t mask, const ShapeInfo& regionShapeInfo, const Transform& regionTransform, uint16_t group) const { +std::vector PhysicsEngine::contactTest(uint16_t mask, const ShapeInfo& regionShapeInfo, const Transform& regionTransform, uint16_t group, float threshold) const { // TODO: Give MyAvatar a motion state so we don't have to do this btCollisionObject* myAvatarCollisionObject = nullptr; if ((mask & USER_COLLISION_GROUP_MY_AVATAR) && _myAvatarController) { myAvatarCollisionObject = _myAvatarController->getCollisionObject(); } - auto contactCallback = AllContactsCallback((int32_t)mask, (int32_t)group, regionShapeInfo, regionTransform, myAvatarCollisionObject); + auto contactCallback = AllContactsCallback((int32_t)mask, (int32_t)group, regionShapeInfo, regionTransform, myAvatarCollisionObject, threshold); _dynamicsWorld->contactTest(&contactCallback.collisionObject, contactCallback); return contactCallback.contacts; diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index 317f7ef312..09b68d9a8b 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -142,7 +142,7 @@ public: // Function for getting colliding objects in the world of specified type // See PhysicsCollisionGroups.h for mask flags. - std::vector contactTest(uint16_t mask, const ShapeInfo& regionShapeInfo, const Transform& regionTransform, uint16_t group = USER_COLLISION_GROUP_DYNAMIC) const; + std::vector contactTest(uint16_t mask, const ShapeInfo& regionShapeInfo, const Transform& regionTransform, uint16_t group = USER_COLLISION_GROUP_DYNAMIC, float threshold = 0.0f) const; private: QList removeDynamicsForBody(btRigidBody* body); diff --git a/libraries/shared/src/RegisteredMetaTypes.h b/libraries/shared/src/RegisteredMetaTypes.h index a7f9b72ed2..312e017dc8 100644 --- a/libraries/shared/src/RegisteredMetaTypes.h +++ b/libraries/shared/src/RegisteredMetaTypes.h @@ -254,12 +254,13 @@ public: }; /**jsdoc -* A CollisionPick defines a volume for checking collisions in the physics simulation. +* A CollisionRegion defines a volume for checking collisions in the physics simulation. -* @typedef {object} CollisionPick +* @typedef {object} CollisionRegion * @property {Shape} shape - The information about the collision region's size and shape. * @property {Vec3} position - The position of the collision region, relative to a parent if defined. * @property {Quat} orientation - The orientation of the collision region, relative to a parent if defined. +* @property {float} threshold - The approximate minimum penetration depth for a test object to be considered in contact with the collision region. * @property {Uuid} parentID - The ID of the parent, either an avatar, an entity, or an overlay. * @property {number} parentJointIndex - The joint of the parent to parent to, for example, the joints on the model of an avatar. (default = 0, no joint) * @property {string} joint - If "Mouse," parents the pick to the mouse. If "Head," parents the pick to MyAvatar's head. Otherwise, parents to the joint of the given name on MyAvatar. @@ -269,6 +270,7 @@ public: CollisionRegion() { } CollisionRegion(const CollisionRegion& collisionRegion) : + threshold(collisionRegion.threshold), modelURL(collisionRegion.modelURL), shapeInfo(std::make_shared()), transform(collisionRegion.transform) @@ -299,6 +301,10 @@ public: } } + if (pickVariant["threshold"].isValid()) { + threshold = glm::max(0.0f, pickVariant["threshold"].toFloat()); + } + if (pickVariant["position"].isValid()) { transform.setTranslation(vec3FromVariant(pickVariant["position"])); } @@ -317,6 +323,8 @@ public: collisionRegion["shape"] = shape; + collisionRegion["threshold"] = threshold; + collisionRegion["position"] = vec3toVariant(transform.getTranslation()); collisionRegion["orientation"] = quatToVariant(transform.getRotation()); @@ -324,13 +332,15 @@ public: } operator bool() const override { - return !(glm::any(glm::isnan(transform.getTranslation())) || + return !std::isnan(threshold) && + !(glm::any(glm::isnan(transform.getTranslation())) || glm::any(glm::isnan(transform.getRotation())) || shapeInfo->getType() == SHAPE_TYPE_NONE); } bool operator==(const CollisionRegion& other) const { - return glm::all(glm::equal(transform.getTranslation(), other.transform.getTranslation())) && + return threshold == other.threshold && + glm::all(glm::equal(transform.getTranslation(), other.transform.getTranslation())) && glm::all(glm::equal(transform.getRotation(), other.transform.getRotation())) && glm::all(glm::equal(transform.getScale(), other.transform.getScale())) && shapeInfo->getType() == other.shapeInfo->getType() && @@ -354,6 +364,7 @@ public: // We can't compute the shapeInfo here without loading the model first, so we delegate that responsibility to the owning CollisionPick std::shared_ptr shapeInfo = std::make_shared(); Transform transform; + float threshold; }; namespace std {