Add threshold parameter to collision pick with minimum of 0

This commit is contained in:
sabrina-shanman 2018-08-27 14:12:24 -07:00
parent 51683b0b53
commit 397b03d5d5
4 changed files with 28 additions and 11 deletions

View file

@ -391,7 +391,7 @@ PickResultPointer CollisionPick::getEntityIntersection(const CollisionRegion& pi
return std::make_shared<CollisionPickResult>(pick.toVariantMap(), CollisionPickResult::LOAD_STATE_NOT_LOADED, std::vector<ContactTestResult>(), std::vector<ContactTestResult>()); return std::make_shared<CollisionPickResult>(pick.toVariantMap(), CollisionPickResult::LOAD_STATE_NOT_LOADED, std::vector<ContactTestResult>(), std::vector<ContactTestResult>());
} }
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); filterIntersections(entityIntersections);
return std::make_shared<CollisionPickResult>(pick, CollisionPickResult::LOAD_STATE_LOADED, entityIntersections, std::vector<ContactTestResult>()); return std::make_shared<CollisionPickResult>(pick, CollisionPickResult::LOAD_STATE_LOADED, entityIntersections, std::vector<ContactTestResult>());
} }
@ -406,7 +406,7 @@ PickResultPointer CollisionPick::getAvatarIntersection(const CollisionRegion& pi
return std::make_shared<CollisionPickResult>(pick, CollisionPickResult::LOAD_STATE_NOT_LOADED, std::vector<ContactTestResult>(), std::vector<ContactTestResult>()); return std::make_shared<CollisionPickResult>(pick, CollisionPickResult::LOAD_STATE_NOT_LOADED, std::vector<ContactTestResult>(), std::vector<ContactTestResult>());
} }
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); filterIntersections(avatarIntersections);
return std::make_shared<CollisionPickResult>(pick, CollisionPickResult::LOAD_STATE_LOADED, std::vector<ContactTestResult>(), avatarIntersections); return std::make_shared<CollisionPickResult>(pick, CollisionPickResult::LOAD_STATE_LOADED, std::vector<ContactTestResult>(), avatarIntersections);
} }

View file

@ -898,11 +898,12 @@ void PhysicsEngine::setShowBulletConstraintLimits(bool value) {
} }
struct AllContactsCallback : public btCollisionWorld::ContactResultCallback { 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(), btCollisionWorld::ContactResultCallback(),
collisionObject(), collisionObject(),
contacts(), contacts(),
myAvatarCollisionObject(myAvatarCollisionObject) { myAvatarCollisionObject(myAvatarCollisionObject),
threshold(threshold) {
const btCollisionShape* collisionShape = ObjectMotionState::getShapeManager()->getShape(shapeInfo); const btCollisionShape* collisionShape = ObjectMotionState::getShapeManager()->getShape(shapeInfo);
collisionObject.setCollisionShape(const_cast<btCollisionShape*>(collisionShape)); collisionObject.setCollisionShape(const_cast<btCollisionShape*>(collisionShape));
@ -924,8 +925,13 @@ struct AllContactsCallback : public btCollisionWorld::ContactResultCallback {
btCollisionObject collisionObject; btCollisionObject collisionObject;
std::vector<ContactTestResult> contacts; std::vector<ContactTestResult> contacts;
btCollisionObject* myAvatarCollisionObject; btCollisionObject* myAvatarCollisionObject;
btScalar threshold;
btScalar addSingleResult(btManifoldPoint& cp, const btCollisionObjectWrapper* colObj0, int partId0, int index0, const btCollisionObjectWrapper* colObj1, int partId1, int index1) override { 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; const btCollisionObject* otherBody;
btVector3 penetrationPoint; btVector3 penetrationPoint;
btVector3 otherPenetrationPoint; btVector3 otherPenetrationPoint;
@ -968,14 +974,14 @@ protected:
} }
}; };
std::vector<ContactTestResult> PhysicsEngine::contactTest(uint16_t mask, const ShapeInfo& regionShapeInfo, const Transform& regionTransform, uint16_t group) const { std::vector<ContactTestResult> 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 // TODO: Give MyAvatar a motion state so we don't have to do this
btCollisionObject* myAvatarCollisionObject = nullptr; btCollisionObject* myAvatarCollisionObject = nullptr;
if ((mask & USER_COLLISION_GROUP_MY_AVATAR) && _myAvatarController) { if ((mask & USER_COLLISION_GROUP_MY_AVATAR) && _myAvatarController) {
myAvatarCollisionObject = _myAvatarController->getCollisionObject(); 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); _dynamicsWorld->contactTest(&contactCallback.collisionObject, contactCallback);
return contactCallback.contacts; return contactCallback.contacts;

View file

@ -142,7 +142,7 @@ public:
// Function for getting colliding objects in the world of specified type // Function for getting colliding objects in the world of specified type
// See PhysicsCollisionGroups.h for mask flags. // See PhysicsCollisionGroups.h for mask flags.
std::vector<ContactTestResult> contactTest(uint16_t mask, const ShapeInfo& regionShapeInfo, const Transform& regionTransform, uint16_t group = USER_COLLISION_GROUP_DYNAMIC) const; std::vector<ContactTestResult> contactTest(uint16_t mask, const ShapeInfo& regionShapeInfo, const Transform& regionTransform, uint16_t group = USER_COLLISION_GROUP_DYNAMIC, float threshold = 0.0f) const;
private: private:
QList<EntityDynamicPointer> removeDynamicsForBody(btRigidBody* body); QList<EntityDynamicPointer> removeDynamicsForBody(btRigidBody* body);

View file

@ -254,12 +254,13 @@ public:
}; };
/**jsdoc /**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 {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 {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 {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 {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 {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. * @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() { }
CollisionRegion(const CollisionRegion& collisionRegion) : CollisionRegion(const CollisionRegion& collisionRegion) :
threshold(collisionRegion.threshold),
modelURL(collisionRegion.modelURL), modelURL(collisionRegion.modelURL),
shapeInfo(std::make_shared<ShapeInfo>()), shapeInfo(std::make_shared<ShapeInfo>()),
transform(collisionRegion.transform) transform(collisionRegion.transform)
@ -299,6 +301,10 @@ public:
} }
} }
if (pickVariant["threshold"].isValid()) {
threshold = glm::max(0.0f, pickVariant["threshold"].toFloat());
}
if (pickVariant["position"].isValid()) { if (pickVariant["position"].isValid()) {
transform.setTranslation(vec3FromVariant(pickVariant["position"])); transform.setTranslation(vec3FromVariant(pickVariant["position"]));
} }
@ -317,6 +323,8 @@ public:
collisionRegion["shape"] = shape; collisionRegion["shape"] = shape;
collisionRegion["threshold"] = threshold;
collisionRegion["position"] = vec3toVariant(transform.getTranslation()); collisionRegion["position"] = vec3toVariant(transform.getTranslation());
collisionRegion["orientation"] = quatToVariant(transform.getRotation()); collisionRegion["orientation"] = quatToVariant(transform.getRotation());
@ -324,13 +332,15 @@ public:
} }
operator bool() const override { 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())) || glm::any(glm::isnan(transform.getRotation())) ||
shapeInfo->getType() == SHAPE_TYPE_NONE); shapeInfo->getType() == SHAPE_TYPE_NONE);
} }
bool operator==(const CollisionRegion& other) const { 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.getRotation(), other.transform.getRotation())) &&
glm::all(glm::equal(transform.getScale(), other.transform.getScale())) && glm::all(glm::equal(transform.getScale(), other.transform.getScale())) &&
shapeInfo->getType() == other.shapeInfo->getType() && 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 // 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> shapeInfo = std::make_shared<ShapeInfo>(); std::shared_ptr<ShapeInfo> shapeInfo = std::make_shared<ShapeInfo>();
Transform transform; Transform transform;
float threshold;
}; };
namespace std { namespace std {