From e1ba4ff0a80150d4a7de1c8643fb64c8f0afdee1 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 6 Jan 2016 16:56:47 -0800 Subject: [PATCH 1/9] add CollisionMask entity property --- interface/src/avatar/AvatarMotionState.cpp | 8 ++- interface/src/avatar/AvatarMotionState.h | 2 +- libraries/entities/src/EntityItem.cpp | 15 ++++ libraries/entities/src/EntityItem.h | 6 ++ .../entities/src/EntityItemProperties.cpp | 12 +++- libraries/entities/src/EntityItemProperties.h | 1 + .../entities/src/EntityItemPropertiesMacros.h | 1 + libraries/entities/src/EntityPropertyFlags.h | 2 + libraries/networking/src/udt/PacketHeaders.h | 1 + libraries/physics/src/CharacterController.cpp | 2 +- libraries/physics/src/EntityMotionState.cpp | 31 +++++--- libraries/physics/src/EntityMotionState.h | 2 +- libraries/physics/src/ObjectMotionState.h | 2 +- libraries/physics/src/PhysicsEngine.cpp | 42 ++++++----- libraries/physics/src/PhysicsEngine.h | 5 +- libraries/shared/src/PhysicsCollisionGroups.h | 70 ++++++++++--------- 16 files changed, 128 insertions(+), 74 deletions(-) diff --git a/interface/src/avatar/AvatarMotionState.cpp b/interface/src/avatar/AvatarMotionState.cpp index 9ce9594d45..7f11c83c4a 100644 --- a/interface/src/avatar/AvatarMotionState.cpp +++ b/interface/src/avatar/AvatarMotionState.cpp @@ -9,8 +9,9 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include #include +#include +#include #include "Avatar.h" #include "AvatarMotionState.h" @@ -143,7 +144,8 @@ QUuid AvatarMotionState::getSimulatorID() const { } // virtual -int16_t AvatarMotionState::computeCollisionGroup() const { - return COLLISION_GROUP_OTHER_AVATAR; +void AvatarMotionState::computeCollisionGroupAndMask(int16_t& group, int16_t& mask) const { + group = BULLET_COLLISION_GROUP_OTHER_AVATAR; + mask = PhysicsEngine::getCollisionMask(group); } diff --git a/interface/src/avatar/AvatarMotionState.h b/interface/src/avatar/AvatarMotionState.h index 0465ddf50b..f02dba54bd 100644 --- a/interface/src/avatar/AvatarMotionState.h +++ b/interface/src/avatar/AvatarMotionState.h @@ -61,7 +61,7 @@ public: void addDirtyFlags(uint32_t flags) { _dirtyFlags |= flags; } - virtual int16_t computeCollisionGroup() const override; + virtual void computeCollisionGroupAndMask(int16_t& group, int16_t& mask) const; friend class AvatarManager; friend class Avatar; diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 97043a635d..c04d280132 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -64,6 +64,7 @@ EntityItem::EntityItem(const EntityItemID& entityItemID) : _angularDamping(ENTITY_ITEM_DEFAULT_ANGULAR_DAMPING), _visible(ENTITY_ITEM_DEFAULT_VISIBLE), _ignoreForCollisions(ENTITY_ITEM_DEFAULT_IGNORE_FOR_COLLISIONS), + _collisionMask(ENTITY_COLLISION_MASK_DEFAULT), _collisionsWillMove(ENTITY_ITEM_DEFAULT_COLLISIONS_WILL_MOVE), _locked(ENTITY_ITEM_DEFAULT_LOCKED), _userData(ENTITY_ITEM_DEFAULT_USER_DATA), @@ -123,6 +124,7 @@ EntityPropertyFlags EntityItem::getEntityProperties(EncodeBitstreamParams& param requestedProperties += PROP_ANGULAR_DAMPING; requestedProperties += PROP_VISIBLE; requestedProperties += PROP_IGNORE_FOR_COLLISIONS; + requestedProperties += PROP_COLLISION_MASK; requestedProperties += PROP_COLLISIONS_WILL_MOVE; requestedProperties += PROP_LOCKED; requestedProperties += PROP_USER_DATA; @@ -259,6 +261,7 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet APPEND_ENTITY_PROPERTY(PROP_ANGULAR_DAMPING, getAngularDamping()); APPEND_ENTITY_PROPERTY(PROP_VISIBLE, getVisible()); APPEND_ENTITY_PROPERTY(PROP_IGNORE_FOR_COLLISIONS, getIgnoreForCollisions()); + APPEND_ENTITY_PROPERTY(PROP_COLLISION_MASK, getCollisionMask()); APPEND_ENTITY_PROPERTY(PROP_COLLISIONS_WILL_MOVE, getCollisionsWillMove()); APPEND_ENTITY_PROPERTY(PROP_LOCKED, getLocked()); APPEND_ENTITY_PROPERTY(PROP_USER_DATA, getUserData()); @@ -678,6 +681,9 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef READ_ENTITY_PROPERTY(PROP_ANGULAR_DAMPING, float, updateAngularDamping); READ_ENTITY_PROPERTY(PROP_VISIBLE, bool, setVisible); READ_ENTITY_PROPERTY(PROP_IGNORE_FOR_COLLISIONS, bool, updateIgnoreForCollisions); + if (args.bitstreamVersion >= VERSION_ENTITITES_HAVE_COLLISION_MASK) { + READ_ENTITY_PROPERTY(PROP_COLLISION_MASK, uint8_t, updateCollisionMask); + } READ_ENTITY_PROPERTY(PROP_COLLISIONS_WILL_MOVE, bool, updateCollisionsWillMove); READ_ENTITY_PROPERTY(PROP_LOCKED, bool, setLocked); READ_ENTITY_PROPERTY(PROP_USER_DATA, QString, setUserData); @@ -1041,6 +1047,7 @@ EntityItemProperties EntityItem::getProperties(EntityPropertyFlags desiredProper COPY_ENTITY_PROPERTY_TO_PROPERTIES(localRenderAlpha, getLocalRenderAlpha); COPY_ENTITY_PROPERTY_TO_PROPERTIES(visible, getVisible); COPY_ENTITY_PROPERTY_TO_PROPERTIES(ignoreForCollisions, getIgnoreForCollisions); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(collisionMask, getCollisionMask); COPY_ENTITY_PROPERTY_TO_PROPERTIES(collisionsWillMove, getCollisionsWillMove); COPY_ENTITY_PROPERTY_TO_PROPERTIES(locked, getLocked); COPY_ENTITY_PROPERTY_TO_PROPERTIES(userData, getUserData); @@ -1096,6 +1103,7 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) { SET_ENTITY_PROPERTY_FROM_PROPERTIES(restitution, updateRestitution); SET_ENTITY_PROPERTY_FROM_PROPERTIES(friction, updateFriction); SET_ENTITY_PROPERTY_FROM_PROPERTIES(ignoreForCollisions, updateIgnoreForCollisions); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(collisionMask, updateCollisionMask); SET_ENTITY_PROPERTY_FROM_PROPERTIES(collisionsWillMove, updateCollisionsWillMove); SET_ENTITY_PROPERTY_FROM_PROPERTIES(created, updateCreated); SET_ENTITY_PROPERTY_FROM_PROPERTIES(lifetime, updateLifetime); @@ -1445,6 +1453,13 @@ void EntityItem::updateIgnoreForCollisions(bool value) { } } +void EntityItem::updateCollisionMask(uint8_t value) { + if ((_collisionMask & ENTITY_COLLISION_MASK_DEFAULT) != (value & ENTITY_COLLISION_MASK_DEFAULT)) { + _collisionMask = (value & ENTITY_COLLISION_MASK_DEFAULT); + _dirtyFlags |= Simulation::DIRTY_COLLISION_GROUP; + } +} + void EntityItem::updateCollisionsWillMove(bool value) { if (_collisionsWillMove != value) { _collisionsWillMove = value; diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 83f2ad164e..d3b52814a3 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -21,6 +21,7 @@ #include // for EncodeBitstreamParams class #include // for OctreeElement::AppendState #include +#include #include #include #include @@ -273,6 +274,9 @@ public: bool getIgnoreForCollisions() const { return _ignoreForCollisions; } void setIgnoreForCollisions(bool value) { _ignoreForCollisions = value; } + uint8_t getCollisionMask() const { return _collisionMask; } + void setCollisionMask(uint8_t value); + bool getCollisionsWillMove() const { return _collisionsWillMove; } void setCollisionsWillMove(bool value) { _collisionsWillMove = value; } @@ -327,6 +331,7 @@ public: void updateAngularVelocity(const glm::vec3& value); void updateAngularDamping(float value); void updateIgnoreForCollisions(bool value); + void updateCollisionMask(uint8_t value); void updateCollisionsWillMove(bool value); void updateLifetime(float value); void updateCreated(uint64_t value); @@ -440,6 +445,7 @@ protected: float _angularDamping; bool _visible; bool _ignoreForCollisions; + uint8_t _collisionMask { ENTITY_COLLISION_MASK_DEFAULT }; bool _collisionsWillMove; bool _locked; QString _userData; diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 214f1e5d78..d647896d1f 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -203,6 +203,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_ANGULAR_VELOCITY, angularVelocity); CHECK_PROPERTY_CHANGE(PROP_ANGULAR_DAMPING, angularDamping); CHECK_PROPERTY_CHANGE(PROP_IGNORE_FOR_COLLISIONS, ignoreForCollisions); + CHECK_PROPERTY_CHANGE(PROP_COLLISION_MASK, collisionMask); CHECK_PROPERTY_CHANGE(PROP_COLLISIONS_WILL_MOVE, collisionsWillMove); CHECK_PROPERTY_CHANGE(PROP_IS_SPOTLIGHT, isSpotlight); CHECK_PROPERTY_CHANGE(PROP_INTENSITY, intensity); @@ -317,6 +318,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ANGULAR_DAMPING, angularDamping); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_VISIBLE, visible); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_IGNORE_FOR_COLLISIONS, ignoreForCollisions); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_COLLISION_MASK, collisionMask); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_COLLISIONS_WILL_MOVE, collisionsWillMove); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_HREF, href); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_DESCRIPTION, description); @@ -538,6 +540,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool COPY_PROPERTY_FROM_QSCRIPTVALUE(glowLevel, float, setGlowLevel); COPY_PROPERTY_FROM_QSCRIPTVALUE(localRenderAlpha, float, setLocalRenderAlpha); COPY_PROPERTY_FROM_QSCRIPTVALUE(ignoreForCollisions, bool, setIgnoreForCollisions); + COPY_PROPERTY_FROM_QSCRIPTVALUE(collisionMask, uint8_t, setCollisionMask); COPY_PROPERTY_FROM_QSCRIPTVALUE(collisionsWillMove, bool, setCollisionsWillMove); COPY_PROPERTY_FROM_QSCRIPTVALUE(isSpotlight, bool, setIsSpotlight); COPY_PROPERTY_FROM_QSCRIPTVALUE(intensity, float, setIntensity); @@ -700,6 +703,7 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue ADD_PROPERTY_TO_MAP(PROP_ANGULAR_VELOCITY, AngularVelocity, angularVelocity, glm::vec3); ADD_PROPERTY_TO_MAP(PROP_ANGULAR_DAMPING, AngularDamping, angularDamping, float); ADD_PROPERTY_TO_MAP(PROP_IGNORE_FOR_COLLISIONS, IgnoreForCollisions, ignoreForCollisions, bool); + ADD_PROPERTY_TO_MAP(PROP_COLLISION_MASK, CollisionMask, collisionMask, uint8_t); ADD_PROPERTY_TO_MAP(PROP_COLLISIONS_WILL_MOVE, CollisionsWillMove, collisionsWillMove, bool); ADD_PROPERTY_TO_MAP(PROP_IS_SPOTLIGHT, IsSpotlight, isSpotlight, bool); ADD_PROPERTY_TO_MAP(PROP_INTENSITY, Intensity, intensity, float); @@ -946,6 +950,7 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem APPEND_ENTITY_PROPERTY(PROP_ANGULAR_DAMPING, properties.getAngularDamping()); APPEND_ENTITY_PROPERTY(PROP_VISIBLE, properties.getVisible()); APPEND_ENTITY_PROPERTY(PROP_IGNORE_FOR_COLLISIONS, properties.getIgnoreForCollisions()); + APPEND_ENTITY_PROPERTY(PROP_COLLISION_MASK, properties.getCollisionMask()); APPEND_ENTITY_PROPERTY(PROP_COLLISIONS_WILL_MOVE, properties.getCollisionsWillMove()); APPEND_ENTITY_PROPERTY(PROP_LOCKED, properties.getLocked()); APPEND_ENTITY_PROPERTY(PROP_USER_DATA, properties.getUserData()); @@ -1238,6 +1243,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANGULAR_DAMPING, float, setAngularDamping); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_VISIBLE, bool, setVisible); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_IGNORE_FOR_COLLISIONS, bool, setIgnoreForCollisions); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLLISION_MASK, uint8_t, setCollisionMask); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLLISIONS_WILL_MOVE, bool, setCollisionsWillMove); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LOCKED, bool, setLocked); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_USER_DATA, QString, setUserData); @@ -1419,6 +1425,7 @@ void EntityItemProperties::markAllChanged() { _localRenderAlphaChanged = true; _isSpotlightChanged = true; _ignoreForCollisionsChanged = true; + _collisionMaskChanged = true; _collisionsWillMoveChanged = true; _intensityChanged = true; @@ -1537,7 +1544,7 @@ bool EntityItemProperties::hasTerseUpdateChanges() const { bool EntityItemProperties::hasMiscPhysicsChanges() const { return _gravityChanged || _dimensionsChanged || _densityChanged || _frictionChanged || _restitutionChanged || _dampingChanged || _angularDampingChanged || _registrationPointChanged || - _compoundShapeURLChanged || _collisionsWillMoveChanged || _ignoreForCollisionsChanged; + _compoundShapeURLChanged || _collisionsWillMoveChanged || _ignoreForCollisionsChanged || _collisionMaskChanged; } void EntityItemProperties::clearSimulationOwner() { @@ -1653,6 +1660,9 @@ QList EntityItemProperties::listChangedProperties() { if (ignoreForCollisionsChanged()) { out += "ignoreForCollisions"; } + if (collisionMaskChanged()) { + out += "collisionMask"; + } if (collisionsWillMoveChanged()) { out += "collisionsWillMove"; } diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 35e7bdfb78..46af6a1da9 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -128,6 +128,7 @@ public: DEFINE_PROPERTY_REF(PROP_ANGULAR_VELOCITY, AngularVelocity, angularVelocity, glm::vec3, ENTITY_ITEM_DEFAULT_ANGULAR_VELOCITY); DEFINE_PROPERTY(PROP_ANGULAR_DAMPING, AngularDamping, angularDamping, float, ENTITY_ITEM_DEFAULT_ANGULAR_DAMPING); DEFINE_PROPERTY(PROP_IGNORE_FOR_COLLISIONS, IgnoreForCollisions, ignoreForCollisions, bool, ENTITY_ITEM_DEFAULT_IGNORE_FOR_COLLISIONS); + DEFINE_PROPERTY(PROP_COLLISION_MASK, CollisionMask, collisionMask, uint8_t, ENTITY_COLLISION_MASK_DEFAULT); DEFINE_PROPERTY(PROP_COLLISIONS_WILL_MOVE, CollisionsWillMove, collisionsWillMove, bool, ENTITY_ITEM_DEFAULT_COLLISIONS_WILL_MOVE); DEFINE_PROPERTY(PROP_IS_SPOTLIGHT, IsSpotlight, isSpotlight, bool, false); DEFINE_PROPERTY(PROP_INTENSITY, Intensity, intensity, float, 1.0f); diff --git a/libraries/entities/src/EntityItemPropertiesMacros.h b/libraries/entities/src/EntityItemPropertiesMacros.h index ad98ca7ba1..860da87705 100644 --- a/libraries/entities/src/EntityItemPropertiesMacros.h +++ b/libraries/entities/src/EntityItemPropertiesMacros.h @@ -191,6 +191,7 @@ inline quint16 quint16_convertFromScriptValue(const QScriptValue& v, bool& isVal inline uint16_t uint16_t_convertFromScriptValue(const QScriptValue& v, bool& isValid) { return v.toVariant().toInt(&isValid); } inline int int_convertFromScriptValue(const QScriptValue& v, bool& isValid) { return v.toVariant().toInt(&isValid); } inline bool bool_convertFromScriptValue(const QScriptValue& v, bool& isValid) { isValid = true; return v.toVariant().toBool(); } +inline uint8_t uint8_t_convertFromScriptValue(const QScriptValue& v, bool& isValid) { isValid = true; return (uint8_t)(0xff & v.toVariant().toInt(&isValid)); } inline QString QString_convertFromScriptValue(const QScriptValue& v, bool& isValid) { isValid = true; return v.toVariant().toString().trimmed(); } inline QUuid QUuid_convertFromScriptValue(const QScriptValue& v, bool& isValid) { isValid = true; return v.toVariant().toUuid(); } inline EntityItemID EntityItemID_convertFromScriptValue(const QScriptValue& v, bool& isValid) { isValid = true; return v.toVariant().toUuid(); } diff --git a/libraries/entities/src/EntityPropertyFlags.h b/libraries/entities/src/EntityPropertyFlags.h index c59ed7141b..81301cb52d 100644 --- a/libraries/entities/src/EntityPropertyFlags.h +++ b/libraries/entities/src/EntityPropertyFlags.h @@ -165,6 +165,8 @@ enum EntityPropertyList { PROP_JOINT_TRANSLATIONS_SET, PROP_JOINT_TRANSLATIONS, + PROP_COLLISION_MASK, // one byte of collision group flags + //////////////////////////////////////////////////////////////////////////////////////////////////// // ATTENTION: add new properties to end of list just ABOVE this line PROP_AFTER_LAST_ITEM, diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index c1404178ff..b8637e85cb 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -164,6 +164,7 @@ const PacketVersion VERSION_ENTITIES_HAVE_PARENTS = 51; const PacketVersion VERSION_ENTITIES_REMOVED_START_AUTOMATICALLY_FROM_ANIMATION_PROPERTY_GROUP = 52; const PacketVersion VERSION_MODEL_ENTITIES_JOINTS_ON_WIRE = 53; const PacketVersion VERSION_ENTITITES_HAVE_QUERY_BOX = 54; +const PacketVersion VERSION_ENTITITES_HAVE_COLLISION_MASK = 55; enum class AvatarMixerPacketVersion : PacketVersion { TranslationSupport = 17, diff --git a/libraries/physics/src/CharacterController.cpp b/libraries/physics/src/CharacterController.cpp index 86d57b7ee9..0797058f05 100644 --- a/libraries/physics/src/CharacterController.cpp +++ b/libraries/physics/src/CharacterController.cpp @@ -84,7 +84,7 @@ void CharacterController::setDynamicsWorld(btDynamicsWorld* world) { // Before adding the RigidBody to the world we must save its oldGravity to the side // because adding an object to the world will overwrite it with the default gravity. btVector3 oldGravity = _rigidBody->getGravity(); - _dynamicsWorld->addRigidBody(_rigidBody, COLLISION_GROUP_MY_AVATAR, COLLISION_MASK_MY_AVATAR); + _dynamicsWorld->addRigidBody(_rigidBody, BULLET_COLLISION_GROUP_MY_AVATAR, BULLET_COLLISION_MASK_MY_AVATAR); _dynamicsWorld->addAction(this); // restore gravity settings _rigidBody->setGravity(oldGravity); diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index c1338b772c..d603fde159 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -610,19 +610,28 @@ QString EntityMotionState::getName() const { } // virtual -int16_t EntityMotionState::computeCollisionGroup() const { - if (_entity->getIgnoreForCollisions()) { - return COLLISION_GROUP_COLLISIONLESS; +void EntityMotionState::computeCollisionGroupAndMask(int16_t& group, int16_t& mask) const { + group = BULLET_COLLISION_GROUP_STATIC; + if (_entity) { + if (_entity->getIgnoreForCollisions()) { + group = BULLET_COLLISION_GROUP_COLLISIONLESS; + } + switch (computeObjectMotionType()){ + case MOTION_TYPE_STATIC: + group = BULLET_COLLISION_GROUP_STATIC; + break; + case MOTION_TYPE_KINEMATIC: + group = BULLET_COLLISION_GROUP_KINEMATIC; + break; + default: + break; + } } - switch (computeObjectMotionType()){ - case MOTION_TYPE_STATIC: - return COLLISION_GROUP_STATIC; - case MOTION_TYPE_KINEMATIC: - return COLLISION_GROUP_KINEMATIC; - default: - break; + + mask = PhysicsEngine::getCollisionMask(group); + if (_entity) { + mask &= (int16_t)(_entity->getCollisionMask()); } - return COLLISION_GROUP_DEFAULT; } void EntityMotionState::setOutgoingPriority(quint8 priority) { diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h index 53e7982ae1..e543ee024e 100644 --- a/libraries/physics/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -80,7 +80,7 @@ public: virtual QString getName() const override; - virtual int16_t computeCollisionGroup() const override; + virtual void computeCollisionGroupAndMask(int16_t& group, int16_t& mask) const; // eternal logic can suggest a simuator priority bid for the next outgoing update void setOutgoingPriority(quint8 priority); diff --git a/libraries/physics/src/ObjectMotionState.h b/libraries/physics/src/ObjectMotionState.h index e10d58e3ed..bbdf6c408a 100644 --- a/libraries/physics/src/ObjectMotionState.h +++ b/libraries/physics/src/ObjectMotionState.h @@ -136,7 +136,7 @@ public: virtual QString getName() const { return ""; } - virtual int16_t computeCollisionGroup() const = 0; + virtual void computeCollisionGroupAndMask(int16_t& group, int16_t& mask) const = 0; bool isActive() const { return _body ? _body->isActive() : false; } diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 9e295d5cf5..b2823746ee 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -22,20 +22,30 @@ uint32_t PhysicsEngine::getNumSubsteps() { return _numSubsteps; } +btHashMap _collisionMasks; + +void initCollisionMaskTable() { + if (_collisionMasks.size() == 0) { + // build table of masks with their group as the key + _collisionMasks.insert(btHashInt((int)BULLET_COLLISION_GROUP_DYNAMIC), BULLET_COLLISION_MASK_DYNAMIC); + _collisionMasks.insert(btHashInt((int)BULLET_COLLISION_GROUP_STATIC), BULLET_COLLISION_MASK_STATIC); + _collisionMasks.insert(btHashInt((int)BULLET_COLLISION_GROUP_KINEMATIC), BULLET_COLLISION_MASK_KINEMATIC); + _collisionMasks.insert(btHashInt((int)BULLET_COLLISION_GROUP_MY_AVATAR), BULLET_COLLISION_MASK_MY_AVATAR); + _collisionMasks.insert(btHashInt((int)BULLET_COLLISION_GROUP_OTHER_AVATAR), BULLET_COLLISION_MASK_OTHER_AVATAR); + _collisionMasks.insert(btHashInt((int)BULLET_COLLISION_GROUP_COLLISIONLESS), BULLET_COLLISION_MASK_COLLISIONLESS); + } +} + +// static +int16_t PhysicsEngine::getCollisionMask(int16_t group) { + const int16_t* mask = _collisionMasks.find(btHashInt((int)group)); + return mask ? *mask : BULLET_COLLISION_MASK_DEFAULT; +} + PhysicsEngine::PhysicsEngine(const glm::vec3& offset) : _originOffset(offset), _myAvatarController(nullptr) { - // build table of masks with their group as the key - _collisionMasks.insert(btHashInt((int)COLLISION_GROUP_DEFAULT), COLLISION_MASK_DEFAULT); - _collisionMasks.insert(btHashInt((int)COLLISION_GROUP_STATIC), COLLISION_MASK_STATIC); - _collisionMasks.insert(btHashInt((int)COLLISION_GROUP_KINEMATIC), COLLISION_MASK_KINEMATIC); - _collisionMasks.insert(btHashInt((int)COLLISION_GROUP_DEBRIS), COLLISION_MASK_DEBRIS); - _collisionMasks.insert(btHashInt((int)COLLISION_GROUP_TRIGGER), COLLISION_MASK_TRIGGER); - _collisionMasks.insert(btHashInt((int)COLLISION_GROUP_MY_AVATAR), COLLISION_MASK_MY_AVATAR); - _collisionMasks.insert(btHashInt((int)COLLISION_GROUP_MY_ATTACHMENT), COLLISION_MASK_MY_ATTACHMENT); - _collisionMasks.insert(btHashInt((int)COLLISION_GROUP_OTHER_AVATAR), COLLISION_MASK_OTHER_AVATAR); - _collisionMasks.insert(btHashInt((int)COLLISION_GROUP_OTHER_ATTACHMENT), COLLISION_MASK_OTHER_ATTACHMENT); - _collisionMasks.insert(btHashInt((int)COLLISION_GROUP_COLLISIONLESS), COLLISION_MASK_COLLISIONLESS); + initCollisionMaskTable(); } PhysicsEngine::~PhysicsEngine() { @@ -139,8 +149,9 @@ void PhysicsEngine::addObjectToDynamicsWorld(ObjectMotionState* motionState) { body->setFlags(BT_DISABLE_WORLD_GRAVITY); motionState->updateBodyMaterialProperties(); - int16_t group = motionState->computeCollisionGroup(); - _dynamicsWorld->addRigidBody(body, group, getCollisionMask(group)); + int16_t group, mask; + motionState->computeCollisionGroupAndMask(group, mask); + _dynamicsWorld->addRigidBody(body, group, mask); motionState->clearIncomingDirtyFlags(); } @@ -457,11 +468,6 @@ void PhysicsEngine::setCharacterController(CharacterController* character) { } } -int16_t PhysicsEngine::getCollisionMask(int16_t group) const { - const int16_t* mask = _collisionMasks.find(btHashInt((int)group)); - return mask ? *mask : COLLISION_MASK_DEFAULT; -} - EntityActionPointer PhysicsEngine::getActionByID(const QUuid& actionID) const { if (_objectActions.contains(actionID)) { return _objectActions[actionID]; diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index 0ca9b2aca8..b2a44b7a3c 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -45,6 +45,8 @@ typedef QVector CollisionEvents; class PhysicsEngine { public: + static int16_t getCollisionMask(int16_t group); + uint32_t getNumSubsteps(); PhysicsEngine(const glm::vec3& offset); @@ -88,8 +90,6 @@ public: void dumpNextStats() { _dumpNextStats = true; } - int16_t getCollisionMask(int16_t group) const; - EntityActionPointer getActionByID(const QUuid& actionID) const; void addAction(EntityActionPointer action); void removeAction(const QUuid actionID); @@ -127,7 +127,6 @@ private: QHash _objectActions; - btHashMap _collisionMasks; uint32_t _numSubsteps; }; diff --git a/libraries/shared/src/PhysicsCollisionGroups.h b/libraries/shared/src/PhysicsCollisionGroups.h index 42599a1b28..67862b7983 100644 --- a/libraries/shared/src/PhysicsCollisionGroups.h +++ b/libraries/shared/src/PhysicsCollisionGroups.h @@ -14,8 +14,8 @@ #include -/* Note: These are the Bullet collision groups defined in btBroadphaseProxy. Only - * DefaultFilter and StaticFilter are explicitly used by Bullet (when the collision +/* Note: These are the Bullet collision groups defined in btBroadphaseProxy. Only + * DefaultFilter and StaticFilter are explicitly used by Bullet (when the collision * filter of an object is not manually specified), the rest are merely suggestions. * enum CollisionFilterGroups { @@ -28,52 +28,54 @@ enum CollisionFilterGroups { AllFilter = -1 } * - * When using custom collision filters we pretty much need to do all or nothing. - * We'll be doing it all which means we define our own groups and build custom masks + * When using custom collision filters we pretty much need to do all or nothing. + * We'll be doing it all which means we define our own groups and build custom masks * for everything. * */ -const int16_t COLLISION_GROUP_DEFAULT = 1 << 0; -const int16_t COLLISION_GROUP_STATIC = 1 << 1; -const int16_t COLLISION_GROUP_KINEMATIC = 1 << 2; -const int16_t COLLISION_GROUP_DEBRIS = 1 << 3; -const int16_t COLLISION_GROUP_TRIGGER = 1 << 4; -const int16_t COLLISION_GROUP_MY_AVATAR = 1 << 5; -const int16_t COLLISION_GROUP_OTHER_AVATAR = 1 << 6; -const int16_t COLLISION_GROUP_MY_ATTACHMENT = 1 << 7; -const int16_t COLLISION_GROUP_OTHER_ATTACHMENT = 1 << 8; +const int16_t BULLET_COLLISION_GROUP_DYNAMIC = 1 << 0; +const int16_t BULLET_COLLISION_GROUP_STATIC = 1 << 1; +const int16_t BULLET_COLLISION_GROUP_KINEMATIC = 1 << 2; +const int16_t BULLET_COLLISION_GROUP_MY_AVATAR = 1 << 3; +const int16_t BULLET_COLLISION_GROUP_OTHER_AVATAR = 1 << 4; // ... -const int16_t COLLISION_GROUP_COLLISIONLESS = 1 << 14; +const int16_t BULLET_COLLISION_GROUP_COLLISIONLESS = 1 << 14; -/* Note: In order for objectA to collide with objectB at the filter stage +/* Note: In order for objectA to collide with objectB at the filter stage * both (groupA & maskB) and (groupB & maskA) must be non-zero. */ -// DEFAULT collides with everything except COLLISIONLESS -const int16_t COLLISION_MASK_DEFAULT = ~ COLLISION_GROUP_COLLISIONLESS; +// the default collision mask is: collides with everything except collisionless +const int16_t BULLET_COLLISION_MASK_DEFAULT = ~ BULLET_COLLISION_GROUP_COLLISIONLESS; -// STATIC also doesn't collide with other STATIC -const int16_t COLLISION_MASK_STATIC = ~ (COLLISION_GROUP_COLLISIONLESS | COLLISION_GROUP_STATIC); +const int16_t BULLET_COLLISION_MASK_DYNAMIC = BULLET_COLLISION_MASK_DEFAULT; -const int16_t COLLISION_MASK_KINEMATIC = COLLISION_MASK_DEFAULT; +// STATIC is special: it collides with everything exept COLLISIONLESS and other STATIC +const int16_t BULLET_COLLISION_MASK_STATIC = ~ (BULLET_COLLISION_GROUP_COLLISIONLESS | BULLET_COLLISION_GROUP_STATIC); -// DEBRIS also doesn't collide with other DEBRIS, or TRIGGER -const int16_t COLLISION_MASK_DEBRIS = ~ (COLLISION_GROUP_COLLISIONLESS - | COLLISION_GROUP_DEBRIS - | COLLISION_GROUP_TRIGGER); - -// TRIGGER also doesn't collide with DEBRIS, TRIGGER, or STATIC (TRIGGER only detects moveable things that matter) -const int16_t COLLISION_MASK_TRIGGER = COLLISION_MASK_DEBRIS & ~(COLLISION_GROUP_STATIC); - -// AVATAR also doesn't collide with corresponding ATTACHMENTs -const int16_t COLLISION_MASK_MY_AVATAR = ~(COLLISION_GROUP_COLLISIONLESS | COLLISION_GROUP_MY_ATTACHMENT); -const int16_t COLLISION_MASK_MY_ATTACHMENT = ~(COLLISION_GROUP_COLLISIONLESS | COLLISION_GROUP_MY_AVATAR); -const int16_t COLLISION_MASK_OTHER_AVATAR = ~(COLLISION_GROUP_COLLISIONLESS | COLLISION_GROUP_OTHER_ATTACHMENT); -const int16_t COLLISION_MASK_OTHER_ATTACHMENT = ~(COLLISION_GROUP_COLLISIONLESS | COLLISION_GROUP_OTHER_AVATAR); +const int16_t BULLET_COLLISION_MASK_KINEMATIC = BULLET_COLLISION_MASK_DEFAULT; +const int16_t BULLET_COLLISION_MASK_MY_AVATAR = BULLET_COLLISION_MASK_DEFAULT; +const int16_t BULLET_COLLISION_MASK_OTHER_AVATAR = BULLET_COLLISION_MASK_DEFAULT; // COLLISIONLESS gets an empty mask. -const int16_t COLLISION_MASK_COLLISIONLESS = 0; +const int16_t BULLET_COLLISION_MASK_COLLISIONLESS = 0; + + +// The USER collision groups are exposed to script and can be used to generate per-object collision masks. +const uint8_t USER_COLLISION_GROUP_DYNAMIC = 1 << 0; +const uint8_t USER_COLLISION_GROUP_STATIC = 1 << 1; +const uint8_t USER_COLLISION_GROUP_KINEMATIC = 1 << 2; +const uint8_t USER_COLLISION_GROUP_MY_AVATAR = 1 << 3; +const uint8_t USER_COLLISION_GROUP_OTHER_AVATAR = 1 << 4; + +const uint8_t ENTITY_COLLISION_MASK_DEFAULT = + USER_COLLISION_GROUP_DYNAMIC | + USER_COLLISION_GROUP_STATIC | + USER_COLLISION_GROUP_KINEMATIC | + USER_COLLISION_GROUP_MY_AVATAR | + USER_COLLISION_GROUP_OTHER_AVATAR; + #endif // hifi_PhysicsCollisionGroups_h From c9b125612cb5314bbe44d8c3bb8ed9fd86baec09 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 7 Jan 2016 13:40:24 -0800 Subject: [PATCH 2/9] fix bugs --- libraries/networking/src/udt/PacketHeaders.cpp | 2 +- libraries/physics/src/EntityMotionState.cpp | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index 43f4b5dcc9..46bf41398c 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -41,7 +41,7 @@ PacketVersion versionForPacketType(PacketType packetType) { case PacketType::EntityAdd: case PacketType::EntityEdit: case PacketType::EntityData: - return VERSION_ENTITITES_HAVE_QUERY_BOX; + return VERSION_ENTITITES_HAVE_COLLISION_MASK; case PacketType::AvatarData: case PacketType::BulkAvatarData: return static_cast(AvatarMixerPacketVersion::SoftAttachmentSupport); diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index d603fde159..cecc5c96b1 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -623,6 +623,9 @@ void EntityMotionState::computeCollisionGroupAndMask(int16_t& group, int16_t& ma case MOTION_TYPE_KINEMATIC: group = BULLET_COLLISION_GROUP_KINEMATIC; break; + case MOTION_TYPE_DYNAMIC: + group = BULLET_COLLISION_GROUP_DYNAMIC; + break; default: break; } From 502921e87708cbb21c25104612921131146c7495 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 7 Jan 2016 13:53:50 -0800 Subject: [PATCH 3/9] more consistency for collision group values --- libraries/physics/src/EntityMotionState.cpp | 6 +++--- libraries/shared/src/PhysicsCollisionGroups.h | 21 +++++++++++-------- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index cecc5c96b1..956ed9fedd 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -620,12 +620,12 @@ void EntityMotionState::computeCollisionGroupAndMask(int16_t& group, int16_t& ma case MOTION_TYPE_STATIC: group = BULLET_COLLISION_GROUP_STATIC; break; - case MOTION_TYPE_KINEMATIC: - group = BULLET_COLLISION_GROUP_KINEMATIC; - break; case MOTION_TYPE_DYNAMIC: group = BULLET_COLLISION_GROUP_DYNAMIC; break; + case MOTION_TYPE_KINEMATIC: + group = BULLET_COLLISION_GROUP_KINEMATIC; + break; default: break; } diff --git a/libraries/shared/src/PhysicsCollisionGroups.h b/libraries/shared/src/PhysicsCollisionGroups.h index 67862b7983..a86722a084 100644 --- a/libraries/shared/src/PhysicsCollisionGroups.h +++ b/libraries/shared/src/PhysicsCollisionGroups.h @@ -34,8 +34,8 @@ enum CollisionFilterGroups { * */ -const int16_t BULLET_COLLISION_GROUP_DYNAMIC = 1 << 0; -const int16_t BULLET_COLLISION_GROUP_STATIC = 1 << 1; +const int16_t BULLET_COLLISION_GROUP_STATIC = 1 << 0; +const int16_t BULLET_COLLISION_GROUP_DYNAMIC = 1 << 1; const int16_t BULLET_COLLISION_GROUP_KINEMATIC = 1 << 2; const int16_t BULLET_COLLISION_GROUP_MY_AVATAR = 1 << 3; const int16_t BULLET_COLLISION_GROUP_OTHER_AVATAR = 1 << 4; @@ -50,13 +50,15 @@ const int16_t BULLET_COLLISION_GROUP_COLLISIONLESS = 1 << 14; // the default collision mask is: collides with everything except collisionless const int16_t BULLET_COLLISION_MASK_DEFAULT = ~ BULLET_COLLISION_GROUP_COLLISIONLESS; -const int16_t BULLET_COLLISION_MASK_DYNAMIC = BULLET_COLLISION_MASK_DEFAULT; - -// STATIC is special: it collides with everything exept COLLISIONLESS and other STATIC +// STATIC does not collide with itself (as optimization of physics simulation) const int16_t BULLET_COLLISION_MASK_STATIC = ~ (BULLET_COLLISION_GROUP_COLLISIONLESS | BULLET_COLLISION_GROUP_STATIC); +const int16_t BULLET_COLLISION_MASK_DYNAMIC = BULLET_COLLISION_MASK_DEFAULT; const int16_t BULLET_COLLISION_MASK_KINEMATIC = BULLET_COLLISION_MASK_DEFAULT; -const int16_t BULLET_COLLISION_MASK_MY_AVATAR = BULLET_COLLISION_MASK_DEFAULT; + +// MY_AVATAR does not collide with itself +const int16_t BULLET_COLLISION_MASK_MY_AVATAR = ~(BULLET_COLLISION_GROUP_COLLISIONLESS | BULLET_COLLISION_GROUP_MY_AVATAR); + const int16_t BULLET_COLLISION_MASK_OTHER_AVATAR = BULLET_COLLISION_MASK_DEFAULT; // COLLISIONLESS gets an empty mask. @@ -64,15 +66,16 @@ const int16_t BULLET_COLLISION_MASK_COLLISIONLESS = 0; // The USER collision groups are exposed to script and can be used to generate per-object collision masks. -const uint8_t USER_COLLISION_GROUP_DYNAMIC = 1 << 0; -const uint8_t USER_COLLISION_GROUP_STATIC = 1 << 1; +// They are not necessarily the same as the BULLET_COLLISION_GROUPS, but we start them off with matching numbers. +const uint8_t USER_COLLISION_GROUP_STATIC = 1 << 0; +const uint8_t USER_COLLISION_GROUP_DYNAMIC = 1 << 1; const uint8_t USER_COLLISION_GROUP_KINEMATIC = 1 << 2; const uint8_t USER_COLLISION_GROUP_MY_AVATAR = 1 << 3; const uint8_t USER_COLLISION_GROUP_OTHER_AVATAR = 1 << 4; const uint8_t ENTITY_COLLISION_MASK_DEFAULT = - USER_COLLISION_GROUP_DYNAMIC | USER_COLLISION_GROUP_STATIC | + USER_COLLISION_GROUP_DYNAMIC | USER_COLLISION_GROUP_KINEMATIC | USER_COLLISION_GROUP_MY_AVATAR | USER_COLLISION_GROUP_OTHER_AVATAR; From 6c49d81475e19fb9873ddf89837bbbbb984c245c Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 7 Jan 2016 16:56:13 -0800 Subject: [PATCH 4/9] collision mask bit reinterpretation also cache sessionID in static methods inside PhysicsEngine --- libraries/entities/src/EntityItem.h | 2 +- libraries/physics/src/EntityMotionState.cpp | 36 ++++++++++++++----- libraries/physics/src/EntityMotionState.h | 4 +-- libraries/physics/src/ObjectMotionState.cpp | 6 ++-- libraries/physics/src/ObjectMotionState.h | 2 +- libraries/physics/src/PhysicsEngine.cpp | 15 +++++++- libraries/physics/src/PhysicsEngine.h | 5 ++- libraries/shared/src/PhysicsCollisionGroups.h | 1 + 8 files changed, 52 insertions(+), 19 deletions(-) diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index d3b52814a3..d526ffec0d 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -275,7 +275,7 @@ public: void setIgnoreForCollisions(bool value) { _ignoreForCollisions = value; } uint8_t getCollisionMask() const { return _collisionMask; } - void setCollisionMask(uint8_t value); + void setCollisionMask(uint8_t value) { _collisionMask = value; } bool getCollisionsWillMove() const { return _collisionsWillMove; } void setCollisionsWillMove(bool value) { _collisionsWillMove = value; } diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 956ed9fedd..f75469e820 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -80,9 +80,9 @@ EntityMotionState::~EntityMotionState() { _entity = nullptr; } -void EntityMotionState::updateServerPhysicsVariables(const QUuid& sessionID) { +void EntityMotionState::updateServerPhysicsVariables() { assert(entityTreeIsLocked()); - if (_entity->getSimulatorID() == sessionID) { + if (_entity->getSimulatorID() == PhysicsEngine::getSessionID()) { // don't slam these values if we are the simulation owner return; } @@ -96,10 +96,10 @@ void EntityMotionState::updateServerPhysicsVariables(const QUuid& sessionID) { } // virtual -bool EntityMotionState::handleEasyChanges(uint32_t& flags, PhysicsEngine* engine) { +bool EntityMotionState::handleEasyChanges(uint32_t& flags) { assert(entityTreeIsLocked()); - updateServerPhysicsVariables(engine->getSessionID()); - ObjectMotionState::handleEasyChanges(flags, engine); + updateServerPhysicsVariables(); + ObjectMotionState::handleEasyChanges(flags); if (flags & Simulation::DIRTY_SIMULATOR_ID) { _loopsWithoutOwner = 0; @@ -113,7 +113,7 @@ bool EntityMotionState::handleEasyChanges(uint32_t& flags, PhysicsEngine* engine _outgoingPriority = NO_PRORITY; } else { _nextOwnershipBid = usecTimestampNow() + USECS_BETWEEN_OWNERSHIP_BIDS; - if (engine->getSessionID() == _entity->getSimulatorID() || _entity->getSimulationPriority() >= _outgoingPriority) { + if (PhysicsEngine::getSessionID() == _entity->getSimulatorID() || _entity->getSimulationPriority() >= _outgoingPriority) { // we own the simulation or our priority looses to (or ties with) remote _outgoingPriority = NO_PRORITY; } @@ -135,7 +135,7 @@ bool EntityMotionState::handleEasyChanges(uint32_t& flags, PhysicsEngine* engine // virtual bool EntityMotionState::handleHardAndEasyChanges(uint32_t& flags, PhysicsEngine* engine) { - updateServerPhysicsVariables(engine->getSessionID()); + updateServerPhysicsVariables(); return ObjectMotionState::handleHardAndEasyChanges(flags, engine); } @@ -523,6 +523,17 @@ uint32_t EntityMotionState::getIncomingDirtyFlags() { uint32_t dirtyFlags = 0; if (_body && _entity) { dirtyFlags = _entity->getDirtyFlags(); + + if (dirtyFlags | Simulation::DIRTY_SIMULATOR_ID) { + // when SIMULATOR_ID changes we must check for reinterpretation of asymmetric collision mask + // bits for the avatar groups (e.g. MY_AVATAR vs OTHER_AVATAR) + uint8_t entityCollisionMask = _entity->getCollisionMask(); + if ((bool)(entityCollisionMask & USER_COLLISION_GROUP_MY_AVATAR) != + (bool)(entityCollisionMask & USER_COLLISION_GROUP_OTHER_AVATAR)) { + // bits are asymmetric --> flag for reinsertion in physics simulation + dirtyFlags |= Simulation::DIRTY_COLLISION_GROUP; + } + } // we add DIRTY_MOTION_TYPE if the body's motion type disagrees with entity velocity settings int bodyFlags = _body->getCollisionFlags(); bool isMoving = _entity->isMoving(); @@ -633,7 +644,16 @@ void EntityMotionState::computeCollisionGroupAndMask(int16_t& group, int16_t& ma mask = PhysicsEngine::getCollisionMask(group); if (_entity) { - mask &= (int16_t)(_entity->getCollisionMask()); + uint8_t entityCollisionMask = _entity->getCollisionMask(); + if ((bool)(entityCollisionMask & USER_COLLISION_GROUP_MY_AVATAR) != + (bool)(entityCollisionMask & USER_COLLISION_GROUP_OTHER_AVATAR)) { + // asymmetric avatar collision mask bits + if (!_entity->getSimulatorID().isNull() && _entity->getSimulatorID() != PhysicsEngine::getSessionID()) { + // someone else owns the simulation, so we swap the interpretation of the bits + entityCollisionMask ^= USER_COLLISION_MASK_AVATARS | ~entityCollisionMask; + } + } + mask &= (int16_t)(entityCollisionMask); } } diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h index e543ee024e..7d7987b641 100644 --- a/libraries/physics/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -28,8 +28,8 @@ public: EntityMotionState(btCollisionShape* shape, EntityItemPointer item); virtual ~EntityMotionState(); - void updateServerPhysicsVariables(const QUuid& sessionID); - virtual bool handleEasyChanges(uint32_t& flags, PhysicsEngine* engine); + void updateServerPhysicsVariables(); + virtual bool handleEasyChanges(uint32_t& flags); virtual bool handleHardAndEasyChanges(uint32_t& flags, PhysicsEngine* engine); /// \return MOTION_TYPE_DYNAMIC or MOTION_TYPE_STATIC based on params set in EntityItem diff --git a/libraries/physics/src/ObjectMotionState.cpp b/libraries/physics/src/ObjectMotionState.cpp index c434f67ad2..ecce821adf 100644 --- a/libraries/physics/src/ObjectMotionState.cpp +++ b/libraries/physics/src/ObjectMotionState.cpp @@ -164,7 +164,7 @@ void ObjectMotionState::setRigidBody(btRigidBody* body) { } } -bool ObjectMotionState::handleEasyChanges(uint32_t& flags, PhysicsEngine* engine) { +bool ObjectMotionState::handleEasyChanges(uint32_t& flags) { if (flags & Simulation::DIRTY_POSITION) { btTransform worldTrans = _body->getWorldTransform(); btVector3 newPosition = glmToBullet(getObjectPosition()); @@ -251,7 +251,7 @@ bool ObjectMotionState::handleHardAndEasyChanges(uint32_t& flags, PhysicsEngine* if ((flags & HARD_DIRTY_PHYSICS_FLAGS) == 0) { // no HARD flags remain, so do any EASY changes if (flags & EASY_DIRTY_PHYSICS_FLAGS) { - handleEasyChanges(flags, engine); + handleEasyChanges(flags); } return true; } @@ -268,7 +268,7 @@ bool ObjectMotionState::handleHardAndEasyChanges(uint32_t& flags, PhysicsEngine* } } if (flags & EASY_DIRTY_PHYSICS_FLAGS) { - handleEasyChanges(flags, engine); + handleEasyChanges(flags); } // it is possible there are no HARD flags at this point (if DIRTY_SHAPE was removed) // so we check again before we reinsert: diff --git a/libraries/physics/src/ObjectMotionState.h b/libraries/physics/src/ObjectMotionState.h index bbdf6c408a..4a90b1d985 100644 --- a/libraries/physics/src/ObjectMotionState.h +++ b/libraries/physics/src/ObjectMotionState.h @@ -80,7 +80,7 @@ public: ObjectMotionState(btCollisionShape* shape); ~ObjectMotionState(); - virtual bool handleEasyChanges(uint32_t& flags, PhysicsEngine* engine); + virtual bool handleEasyChanges(uint32_t& flags); virtual bool handleHardAndEasyChanges(uint32_t& flags, PhysicsEngine* engine); void updateBodyMaterialProperties(); diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index b2823746ee..b665be5d53 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -42,6 +42,19 @@ int16_t PhysicsEngine::getCollisionMask(int16_t group) { return mask ? *mask : BULLET_COLLISION_MASK_DEFAULT; } +QUuid _sessionID; + +// static +void PhysicsEngine::setSessionUUID(const QUuid& sessionID) { + _sessionID = sessionID; +} + +// static +const QUuid& PhysicsEngine::getSessionID() { + return _sessionID; +} + + PhysicsEngine::PhysicsEngine(const glm::vec3& offset) : _originOffset(offset), _myAvatarController(nullptr) { @@ -209,7 +222,7 @@ VectorOfMotionStates PhysicsEngine::changeObjects(const VectorOfMotionStates& ob stillNeedChange.push_back(object); } } else if (flags & EASY_DIRTY_PHYSICS_FLAGS) { - if (object->handleEasyChanges(flags, this)) { + if (object->handleEasyChanges(flags)) { object->clearIncomingDirtyFlags(); } else { stillNeedChange.push_back(object); diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index b2a44b7a3c..c42fe2f66e 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -53,8 +53,8 @@ public: ~PhysicsEngine(); void init(); - void setSessionUUID(const QUuid& sessionID) { _sessionID = sessionID; } - const QUuid& getSessionID() const { return _sessionID; } + static void setSessionUUID(const QUuid& sessionID); + static const QUuid& getSessionID(); void removeObjects(const VectorOfMotionStates& objects); void removeObjects(const SetOfMotionStates& objects); // only called during teardown @@ -122,7 +122,6 @@ private: bool _dumpNextStats = false; bool _hasOutgoingChanges = false; - QUuid _sessionID; CollisionEvents _collisionEvents; QHash _objectActions; diff --git a/libraries/shared/src/PhysicsCollisionGroups.h b/libraries/shared/src/PhysicsCollisionGroups.h index a86722a084..e7f9d57fef 100644 --- a/libraries/shared/src/PhysicsCollisionGroups.h +++ b/libraries/shared/src/PhysicsCollisionGroups.h @@ -80,5 +80,6 @@ const uint8_t ENTITY_COLLISION_MASK_DEFAULT = USER_COLLISION_GROUP_MY_AVATAR | USER_COLLISION_GROUP_OTHER_AVATAR; +const uint8_t USER_COLLISION_MASK_AVATARS = USER_COLLISION_GROUP_MY_AVATAR | USER_COLLISION_GROUP_OTHER_AVATAR; #endif // hifi_PhysicsCollisionGroups_h From 00e5d040a21e654d84528e41133c9ffc0cbead78 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 8 Jan 2016 10:47:14 -0800 Subject: [PATCH 5/9] use collision masks to prevent grab-bootstrap --- examples/controllers/handControllerGrab.js | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 0e1a42863e..06fde5e002 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -106,7 +106,7 @@ var GRABBABLE_PROPERTIES = [ "position", "rotation", "gravity", - "ignoreForCollisions", + "collisionMask", "collisionsWillMove", "locked", "name" @@ -117,7 +117,6 @@ var GRAB_USER_DATA_KEY = "grabKey"; // shared with grab.js var DEFAULT_GRABBABLE_DATA = { grabbable: true, - invertSolidWhileHeld: false }; @@ -164,6 +163,14 @@ var POINT_HAND_STATES = [STATE_NEAR_TRIGGER, STATE_CONTINUE_NEAR_TRIGGER, STATE_ var FAR_GRASP_HAND_STATES = [STATE_DISTANCE_HOLDING, STATE_CONTINUE_DISTANCE_HOLDING]; // otherwise grasp +var COLLISION_GROUP_STATIC = 0x01; // bit 0 +var COLLISION_GROUP_DYNAMIC = 0x02; // bit 1 +var COLLISION_GROUP_KINEMATIC = 0x04; // bit 2 +var COLLISION_GROUP_MY_AVATAR = 0x08; // bit 3 +var COLLISION_GROUP_OTHER_AVATAR = 0x10; // bit 4 +var COLLISION_MASK_WHILE_GRABBED = COLLISION_GROUP_DYNAMIC | COLLISION_GROUP_OTHER_AVATAR; + + function stateToName(state) { switch (state) { case STATE_OFF: @@ -1823,7 +1830,6 @@ function MyController(hand) { this.activateEntity = function(entityID, grabbedProperties) { var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, entityID, DEFAULT_GRABBABLE_DATA); - var invertSolidWhileHeld = grabbableData["invertSolidWhileHeld"]; var data = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, {}); data["activated"] = true; data["avatarId"] = MyAvatar.sessionUUID; @@ -1831,18 +1837,16 @@ function MyController(hand) { // zero gravity and set ignoreForCollisions in a way that lets us put them back, after all grabs are done if (data["refCount"] == 1) { data["gravity"] = grabbedProperties.gravity; - data["ignoreForCollisions"] = grabbedProperties.ignoreForCollisions; + data["collisionMask"] = grabbedProperties.collisionMask; data["collisionsWillMove"] = grabbedProperties.collisionsWillMove; var whileHeldProperties = { gravity: { x: 0, y: 0, z: 0 - } + }, + collisionMask: COLLISION_MASK_WHILE_GRABBED & grabbedProperties.collisionMask }; - if (invertSolidWhileHeld) { - whileHeldProperties["ignoreForCollisions"] = !grabbedProperties.ignoreForCollisions; - } Entities.editEntity(entityID, whileHeldProperties); } @@ -1857,7 +1861,7 @@ function MyController(hand) { if (data["refCount"] < 1) { Entities.editEntity(entityID, { gravity: data["gravity"], - ignoreForCollisions: data["ignoreForCollisions"], + collisionMask: data["collisionMask"], collisionsWillMove: data["collisionsWillMove"] }); data = null; From 222398e5cc942edc13c54983701485dc6fec1011 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 8 Jan 2016 11:46:40 -0800 Subject: [PATCH 6/9] no packet version check for collision mask --- libraries/entities/src/EntityItem.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index c04d280132..0a7a30f098 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -681,9 +681,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef READ_ENTITY_PROPERTY(PROP_ANGULAR_DAMPING, float, updateAngularDamping); READ_ENTITY_PROPERTY(PROP_VISIBLE, bool, setVisible); READ_ENTITY_PROPERTY(PROP_IGNORE_FOR_COLLISIONS, bool, updateIgnoreForCollisions); - if (args.bitstreamVersion >= VERSION_ENTITITES_HAVE_COLLISION_MASK) { - READ_ENTITY_PROPERTY(PROP_COLLISION_MASK, uint8_t, updateCollisionMask); - } + READ_ENTITY_PROPERTY(PROP_COLLISION_MASK, uint8_t, updateCollisionMask); READ_ENTITY_PROPERTY(PROP_COLLISIONS_WILL_MOVE, bool, updateCollisionsWillMove); READ_ENTITY_PROPERTY(PROP_LOCKED, bool, setLocked); READ_ENTITY_PROPERTY(PROP_USER_DATA, QString, setUserData); From c52c543ab8482248f76741d6f58ca35411fe6d7b Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 8 Jan 2016 20:24:37 -0800 Subject: [PATCH 7/9] use strings for JS collisionGroup API --- examples/controllers/handControllerGrab.js | 11 ++-- .../entities/src/EntityItemProperties.cpp | 57 ++++++++++++++++++- libraries/entities/src/EntityItemProperties.h | 4 ++ libraries/shared/src/PhysicsCollisionGroups.h | 2 + 4 files changed, 65 insertions(+), 9 deletions(-) diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 06fde5e002..be5fdd7edb 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -163,12 +163,9 @@ var POINT_HAND_STATES = [STATE_NEAR_TRIGGER, STATE_CONTINUE_NEAR_TRIGGER, STATE_ var FAR_GRASP_HAND_STATES = [STATE_DISTANCE_HOLDING, STATE_CONTINUE_DISTANCE_HOLDING]; // otherwise grasp -var COLLISION_GROUP_STATIC = 0x01; // bit 0 -var COLLISION_GROUP_DYNAMIC = 0x02; // bit 1 -var COLLISION_GROUP_KINEMATIC = 0x04; // bit 2 -var COLLISION_GROUP_MY_AVATAR = 0x08; // bit 3 -var COLLISION_GROUP_OTHER_AVATAR = 0x10; // bit 4 -var COLLISION_MASK_WHILE_GRABBED = COLLISION_GROUP_DYNAMIC | COLLISION_GROUP_OTHER_AVATAR; +// collision masks are specified by comma-separated list of group names +// the possible list of names is: static, dynamic, kinematic, myAvatar, otherAvatar +var COLLISION_MASK_WHILE_GRABBED = "dynamic,otherAvatar"; function stateToName(state) { @@ -1845,7 +1842,7 @@ function MyController(hand) { y: 0, z: 0 }, - collisionMask: COLLISION_MASK_WHILE_GRABBED & grabbedProperties.collisionMask + "collisionMask": COLLISION_MASK_WHILE_GRABBED }; Entities.editEntity(entityID, whileHeldProperties); } diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index d647896d1f..f8dcb6ee56 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -116,6 +116,59 @@ void buildStringToShapeTypeLookup() { addShapeType(SHAPE_TYPE_CYLINDER_Z); } +QString getCollisionGroupAsString(uint8_t group) { + switch (group) { + case USER_COLLISION_GROUP_DYNAMIC: + return "dynamic"; + case USER_COLLISION_GROUP_STATIC: + return "static"; + case USER_COLLISION_GROUP_KINEMATIC: + return "kinematic"; + case USER_COLLISION_GROUP_MY_AVATAR: + return "myAvatar"; + case USER_COLLISION_GROUP_OTHER_AVATAR: + return "otherAvatar"; + }; + return ""; +} + +uint8_t getCollisionGroupAsBitMask(const QStringRef& name) { + if (0 == name.compare("dynamic")) { + return USER_COLLISION_GROUP_DYNAMIC; + } else if (0 == name.compare("static")) { + return USER_COLLISION_GROUP_STATIC; + } else if (0 == name.compare("kinematic")) { + return USER_COLLISION_GROUP_KINEMATIC; + } else if (0 == name.compare("myAvatar")) { + return USER_COLLISION_GROUP_MY_AVATAR; + } else if (0 == name.compare("otherAvatar")) { + return USER_COLLISION_GROUP_OTHER_AVATAR; + } + return 0; +} + +QString EntityItemProperties::getCollisionMaskAsString() const { + QString maskString(""); + for (int i = 0; i < NUM_USER_COLLISION_GROUPS; ++i) { + uint8_t group = 0x01 << i; + if (group & _collisionMask) { + maskString.append(getCollisionGroupAsString(group)); + maskString.append(','); + } + } + return maskString; +} + +void EntityItemProperties::setCollisionMaskFromString(const QString& maskString) { + QVector groups = maskString.splitRef(','); + uint8_t mask = 0x00; + for (auto group : groups) { + mask |= getCollisionGroupAsBitMask(group); + } + _collisionMask = mask; + _collisionMaskChanged = true; +} + QString EntityItemProperties::getShapeTypeAsString() const { if (_shapeType < sizeof(shapeTypeNames) / sizeof(char *)) return QString(shapeTypeNames[_shapeType]); @@ -318,7 +371,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ANGULAR_DAMPING, angularDamping); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_VISIBLE, visible); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_IGNORE_FOR_COLLISIONS, ignoreForCollisions); - COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_COLLISION_MASK, collisionMask); + COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_COLLISION_MASK, collisionMask, getCollisionMaskAsString()); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_COLLISIONS_WILL_MOVE, collisionsWillMove); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_HREF, href); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_DESCRIPTION, description); @@ -540,7 +593,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool COPY_PROPERTY_FROM_QSCRIPTVALUE(glowLevel, float, setGlowLevel); COPY_PROPERTY_FROM_QSCRIPTVALUE(localRenderAlpha, float, setLocalRenderAlpha); COPY_PROPERTY_FROM_QSCRIPTVALUE(ignoreForCollisions, bool, setIgnoreForCollisions); - COPY_PROPERTY_FROM_QSCRIPTVALUE(collisionMask, uint8_t, setCollisionMask); + COPY_PROPERTY_FROM_QSCRITPTVALUE_ENUM(collisionMask, CollisionMask); COPY_PROPERTY_FROM_QSCRIPTVALUE(collisionsWillMove, bool, setCollisionsWillMove); COPY_PROPERTY_FROM_QSCRIPTVALUE(isSpotlight, bool, setIsSpotlight); COPY_PROPERTY_FROM_QSCRIPTVALUE(intensity, float, setIntensity); diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 46af6a1da9..087925b139 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -274,6 +274,10 @@ public: void setJointRotationsDirty() { _jointRotationsSetChanged = true; _jointRotationsChanged = true; } void setJointTranslationsDirty() { _jointTranslationsSetChanged = true; _jointTranslationsChanged = true; } +protected: + QString getCollisionMaskAsString() const; + void setCollisionMaskFromString(const QString& maskString); + private: QUuid _id; bool _idSet; diff --git a/libraries/shared/src/PhysicsCollisionGroups.h b/libraries/shared/src/PhysicsCollisionGroups.h index e7f9d57fef..6d320e69cb 100644 --- a/libraries/shared/src/PhysicsCollisionGroups.h +++ b/libraries/shared/src/PhysicsCollisionGroups.h @@ -82,4 +82,6 @@ const uint8_t ENTITY_COLLISION_MASK_DEFAULT = const uint8_t USER_COLLISION_MASK_AVATARS = USER_COLLISION_GROUP_MY_AVATAR | USER_COLLISION_GROUP_OTHER_AVATAR; +const int NUM_USER_COLLISION_GROUPS = 5; + #endif // hifi_PhysicsCollisionGroups_h From 2288d96868339be5725161ecc5252de88a6c3925 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 12 Jan 2016 10:20:35 -0800 Subject: [PATCH 8/9] fix CharacterController ray cast for floor --- libraries/physics/src/CharacterController.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libraries/physics/src/CharacterController.cpp b/libraries/physics/src/CharacterController.cpp index 0797058f05..7c2ca31f8f 100644 --- a/libraries/physics/src/CharacterController.cpp +++ b/libraries/physics/src/CharacterController.cpp @@ -27,6 +27,9 @@ class ClosestNotMe : public btCollisionWorld::ClosestRayResultCallback { public: ClosestNotMe(btRigidBody* me) : btCollisionWorld::ClosestRayResultCallback(btVector3(0.0f, 0.0f, 0.0f), btVector3(0.0f, 0.0f, 0.0f)) { _me = me; + // the RayResultCallback's group and mask must match MY_AVATAR + m_collisionFilterGroup = BULLET_COLLISION_GROUP_MY_AVATAR; + m_collisionFilterMask = BULLET_COLLISION_MASK_MY_AVATAR; } virtual btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult,bool normalInWorldSpace) { if (rayResult.m_collisionObject == _me) { From 6a5a74700fa508d03cb8dd9acb1396e1c2dbbb9e Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 12 Jan 2016 12:53:35 -0800 Subject: [PATCH 9/9] activate sprung objects when action strong enough --- libraries/physics/src/ObjectActionSpring.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/libraries/physics/src/ObjectActionSpring.cpp b/libraries/physics/src/ObjectActionSpring.cpp index d9d6a323a7..a737a2b8b6 100644 --- a/libraries/physics/src/ObjectActionSpring.cpp +++ b/libraries/physics/src/ObjectActionSpring.cpp @@ -62,9 +62,10 @@ void ObjectActionSpring::updateActionWorker(btScalar deltaTimeStep) { float offsetLength = offset.length(); btVector3 targetVelocity(0.0f, 0.0f, 0.0f); - if (offsetLength > 0) { - float speed = (offsetLength > FLT_EPSILON) ? glm::min(offsetLength / _linearTimeScale, SPRING_MAX_SPEED) : 0.0f; + float speed = (offsetLength > FLT_EPSILON) ? glm::min(offsetLength / _linearTimeScale, SPRING_MAX_SPEED) : 0.0f; + if (speed > rigidBody->getLinearSleepingThreshold()) { targetVelocity = (-speed / offsetLength) * offset; + rigidBody->activate(); } // this action is aggresively critically damped and defeats the current velocity @@ -90,10 +91,10 @@ void ObjectActionSpring::updateActionWorker(btScalar deltaTimeStep) { // // dQ = Q1 * Q0^ btQuaternion deltaQ = target * bodyRotation.inverse(); - float angle = deltaQ.getAngle(); - const float MIN_ANGLE = 1.0e-4f; - if (angle > MIN_ANGLE) { - targetVelocity = (angle / _angularTimeScale) * deltaQ.getAxis(); + float speed = deltaQ.getAngle() / _angularTimeScale; + if (speed > rigidBody->getAngularSleepingThreshold()) { + targetVelocity = speed * deltaQ.getAxis(); + rigidBody->activate(); } } // this action is aggresively critically damped and defeats the current velocity