move collision group/mask calculus into EntityItem

This commit is contained in:
Andrew Meadows 2016-01-19 19:49:34 -08:00
parent 730640068c
commit a92c512c17
10 changed files with 108 additions and 101 deletions

View file

@ -92,6 +92,7 @@
#include <PathUtils.h> #include <PathUtils.h>
#include <PerfStat.h> #include <PerfStat.h>
#include <PhysicsEngine.h> #include <PhysicsEngine.h>
#include <PhysicsHelpers.h>
#include <plugins/PluginContainer.h> #include <plugins/PluginContainer.h>
#include <plugins/PluginManager.h> #include <plugins/PluginManager.h>
#include <RenderableWebEntityItem.h> #include <RenderableWebEntityItem.h>
@ -3135,7 +3136,7 @@ void Application::update(float deltaTime) {
PerformanceTimer perfTimer("havestChanges"); PerformanceTimer perfTimer("havestChanges");
if (_physicsEngine->hasOutgoingChanges()) { if (_physicsEngine->hasOutgoingChanges()) {
getEntities()->getTree()->withWriteLock([&] { getEntities()->getTree()->withWriteLock([&] {
_entitySimulation.handleOutgoingChanges(_physicsEngine->getOutgoingChanges(), _physicsEngine->getSessionID()); _entitySimulation.handleOutgoingChanges(_physicsEngine->getOutgoingChanges(), Physics::getSessionUUID());
avatarManager->handleOutgoingChanges(_physicsEngine->getOutgoingChanges()); avatarManager->handleOutgoingChanges(_physicsEngine->getOutgoingChanges());
}); });
@ -4296,6 +4297,9 @@ bool Application::acceptURL(const QString& urlString, bool defaultUpload) {
} }
void Application::setSessionUUID(const QUuid& sessionUUID) { void Application::setSessionUUID(const QUuid& sessionUUID) {
// HACK: until we swap the library dependency order between physics and entities
// we cache the sessionID in two distinct places for physics.
Physics::setSessionUUID(sessionUUID); // TODO: remove this one
_physicsEngine->setSessionUUID(sessionUUID); _physicsEngine->setSessionUUID(sessionUUID);
} }

View file

@ -146,6 +146,6 @@ QUuid AvatarMotionState::getSimulatorID() const {
// virtual // virtual
void AvatarMotionState::computeCollisionGroupAndMask(int16_t& group, int16_t& mask) const { void AvatarMotionState::computeCollisionGroupAndMask(int16_t& group, int16_t& mask) const {
group = BULLET_COLLISION_GROUP_OTHER_AVATAR; group = BULLET_COLLISION_GROUP_OTHER_AVATAR;
mask = PhysicsEngine::getCollisionMask(group); mask = Physics::getDefaultCollisionMask(group);
} }

View file

@ -1507,6 +1507,33 @@ void EntityItem::updateCreated(uint64_t value) {
} }
} }
void EntityItem::computeCollisionGroupAndFinalMask(int16_t& group, int16_t& mask) const {
// TODO: detect attachment status and adopt group of wearer
if (_collisionless) {
group = BULLET_COLLISION_GROUP_COLLISIONLESS;
mask = 0;
} else {
if (_dynamic) {
group = BULLET_COLLISION_GROUP_DYNAMIC;
} else if (isMoving() || hasActions()) {
group = BULLET_COLLISION_GROUP_KINEMATIC;
} else {
group = BULLET_COLLISION_GROUP_STATIC;
}
uint8_t userMask = getCollisionMask();
if ((bool)(userMask & USER_COLLISION_GROUP_MY_AVATAR) !=
(bool)(userMask & USER_COLLISION_GROUP_OTHER_AVATAR)) {
// asymmetric avatar collision mask bits
if (!getSimulatorID().isNull() && (!getSimulatorID().isNull()) && getSimulatorID() != Physics::getSessionUUID()) {
// someone else owns the simulation, so we toggle the avatar bits (swap interpretation)
userMask ^= USER_COLLISION_MASK_AVATARS | ~userMask;
}
}
mask = Physics::getDefaultCollisionMask(group) & (int16_t)(userMask);
}
}
void EntityItem::setSimulationOwner(const QUuid& id, quint8 priority) { void EntityItem::setSimulationOwner(const QUuid& id, quint8 priority) {
if (wantTerseEditLogging() && (id != _simulationOwner.getID() || priority != _simulationOwner.getPriority())) { if (wantTerseEditLogging() && (id != _simulationOwner.getID() || priority != _simulationOwner.getPriority())) {
qCDebug(entities) << "sim ownership for" << getDebugName() << "is now" << id << priority; qCDebug(entities) << "sim ownership for" << getDebugName() << "is now" << id << priority;

View file

@ -275,9 +275,10 @@ public:
void setCollisionless(bool value) { _collisionless = value; } void setCollisionless(bool value) { _collisionless = value; }
uint8_t getCollisionMask() const { return _collisionMask; } uint8_t getCollisionMask() const { return _collisionMask; }
uint8_t getFinalCollisionMask() const { return _collisionless ? 0 : _collisionMask; }
void setCollisionMask(uint8_t value) { _collisionMask = value; } void setCollisionMask(uint8_t value) { _collisionMask = value; }
void computeCollisionGroupAndFinalMask(int16_t& group, int16_t& mask) const;
bool getDynamic() const { return _dynamic; } bool getDynamic() const { return _dynamic; }
void setDynamic(bool value) { _dynamic = value; } void setDynamic(bool value) { _dynamic = value; }
@ -370,8 +371,8 @@ public:
bool clearActions(EntitySimulation* simulation); bool clearActions(EntitySimulation* simulation);
void setActionData(QByteArray actionData); void setActionData(QByteArray actionData);
const QByteArray getActionData() const; const QByteArray getActionData() const;
bool hasActions() { return !_objectActions.empty(); } bool hasActions() const { return !_objectActions.empty(); }
QList<QUuid> getActionIDs() { return _objectActions.keys(); } QList<QUuid> getActionIDs() const { return _objectActions.keys(); }
QVariantMap getActionArguments(const QUuid& actionID) const; QVariantMap getActionArguments(const QUuid& actionID) const;
void deserializeActions(); void deserializeActions();

View file

@ -162,8 +162,8 @@ QString EntityItemProperties::getCollisionMaskAsString() const {
void EntityItemProperties::setCollisionMaskFromString(const QString& maskString) { void EntityItemProperties::setCollisionMaskFromString(const QString& maskString) {
QVector<QStringRef> groups = maskString.splitRef(','); QVector<QStringRef> groups = maskString.splitRef(',');
uint8_t mask = 0x00; uint8_t mask = 0x00;
for (auto group : groups) { for (auto groupName : groups) {
mask |= getCollisionGroupAsBitMask(group); mask |= getCollisionGroupAsBitMask(groupName);
} }
_collisionMask = mask; _collisionMask = mask;
_collisionMaskChanged = true; _collisionMaskChanged = true;

View file

@ -82,7 +82,7 @@ EntityMotionState::~EntityMotionState() {
void EntityMotionState::updateServerPhysicsVariables() { void EntityMotionState::updateServerPhysicsVariables() {
assert(entityTreeIsLocked()); assert(entityTreeIsLocked());
if (_entity->getSimulatorID() == PhysicsEngine::getSessionID()) { if (_entity->getSimulatorID() == Physics::getSessionUUID()) {
// don't slam these values if we are the simulation owner // don't slam these values if we are the simulation owner
return; return;
} }
@ -113,7 +113,7 @@ bool EntityMotionState::handleEasyChanges(uint32_t& flags) {
_outgoingPriority = NO_PRORITY; _outgoingPriority = NO_PRORITY;
} else { } else {
_nextOwnershipBid = usecTimestampNow() + USECS_BETWEEN_OWNERSHIP_BIDS; _nextOwnershipBid = usecTimestampNow() + USECS_BETWEEN_OWNERSHIP_BIDS;
if (PhysicsEngine::getSessionID() == _entity->getSimulatorID() || _entity->getSimulationPriority() >= _outgoingPriority) { if (Physics::getSessionUUID() == _entity->getSimulatorID() || _entity->getSimulationPriority() >= _outgoingPriority) {
// we own the simulation or our priority looses to (or ties with) remote // we own the simulation or our priority looses to (or ties with) remote
_outgoingPriority = NO_PRORITY; _outgoingPriority = NO_PRORITY;
} }
@ -527,7 +527,7 @@ uint32_t EntityMotionState::getIncomingDirtyFlags() {
if (dirtyFlags | Simulation::DIRTY_SIMULATOR_ID) { if (dirtyFlags | Simulation::DIRTY_SIMULATOR_ID) {
// when SIMULATOR_ID changes we must check for reinterpretation of asymmetric collision mask // 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) // bits for the avatar groups (e.g. MY_AVATAR vs OTHER_AVATAR)
uint8_t entityCollisionMask = _entity->getCollisionMask(); uint8_t entityCollisionMask = _entity->getCollisionless() ? 0 : _entity->getCollisionMask();
if ((bool)(entityCollisionMask & USER_COLLISION_GROUP_MY_AVATAR) != if ((bool)(entityCollisionMask & USER_COLLISION_GROUP_MY_AVATAR) !=
(bool)(entityCollisionMask & USER_COLLISION_GROUP_OTHER_AVATAR)) { (bool)(entityCollisionMask & USER_COLLISION_GROUP_OTHER_AVATAR)) {
// bits are asymmetric --> flag for reinsertion in physics simulation // bits are asymmetric --> flag for reinsertion in physics simulation
@ -622,39 +622,8 @@ QString EntityMotionState::getName() const {
// virtual // virtual
void EntityMotionState::computeCollisionGroupAndMask(int16_t& group, int16_t& mask) const { void EntityMotionState::computeCollisionGroupAndMask(int16_t& group, int16_t& mask) const {
group = BULLET_COLLISION_GROUP_STATIC; assert(_entity);
if (_entity) { _entity->computeCollisionGroupAndFinalMask(group, mask);
if (_entity->getCollisionless()) {
group = BULLET_COLLISION_GROUP_COLLISIONLESS;
}
switch (computePhysicsMotionType()){
case MOTION_TYPE_STATIC:
group = BULLET_COLLISION_GROUP_STATIC;
break;
case MOTION_TYPE_DYNAMIC:
group = BULLET_COLLISION_GROUP_DYNAMIC;
break;
case MOTION_TYPE_KINEMATIC:
group = BULLET_COLLISION_GROUP_KINEMATIC;
break;
default:
break;
}
}
mask = PhysicsEngine::getCollisionMask(group);
if (_entity) {
uint8_t entityCollisionMask = _entity->getFinalCollisionMask();
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);
}
} }
void EntityMotionState::setOutgoingPriority(quint8 priority) { void EntityMotionState::setOutgoingPriority(quint8 priority) {

View file

@ -18,47 +18,10 @@
#include "ThreadSafeDynamicsWorld.h" #include "ThreadSafeDynamicsWorld.h"
#include "PhysicsLogging.h" #include "PhysicsLogging.h"
uint32_t PhysicsEngine::getNumSubsteps() {
return _numSubsteps;
}
btHashMap<btHashInt, int16_t> _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;
}
QUuid _sessionID;
// static
void PhysicsEngine::setSessionUUID(const QUuid& sessionID) {
_sessionID = sessionID;
}
// static
const QUuid& PhysicsEngine::getSessionID() {
return _sessionID;
}
PhysicsEngine::PhysicsEngine(const glm::vec3& offset) : PhysicsEngine::PhysicsEngine(const glm::vec3& offset) :
_originOffset(offset), _originOffset(offset),
_sessionID(),
_myAvatarController(nullptr) { _myAvatarController(nullptr) {
initCollisionMaskTable();
} }
PhysicsEngine::~PhysicsEngine() { PhysicsEngine::~PhysicsEngine() {
@ -90,6 +53,10 @@ void PhysicsEngine::init() {
} }
} }
uint32_t PhysicsEngine::getNumSubsteps() {
return _numSubsteps;
}
// private // private
void PhysicsEngine::addObjectToDynamicsWorld(ObjectMotionState* motionState) { void PhysicsEngine::addObjectToDynamicsWorld(ObjectMotionState* motionState) {
assert(motionState); assert(motionState);

View file

@ -45,16 +45,11 @@ typedef QVector<Collision> CollisionEvents;
class PhysicsEngine { class PhysicsEngine {
public: public:
static int16_t getCollisionMask(int16_t group);
uint32_t getNumSubsteps();
PhysicsEngine(const glm::vec3& offset); PhysicsEngine(const glm::vec3& offset);
~PhysicsEngine(); ~PhysicsEngine();
void init(); void init();
static void setSessionUUID(const QUuid& sessionID); uint32_t getNumSubsteps();
static const QUuid& getSessionID();
void removeObjects(const VectorOfMotionStates& objects); void removeObjects(const VectorOfMotionStates& objects);
void removeObjects(const SetOfMotionStates& objects); // only called during teardown void removeObjects(const SetOfMotionStates& objects); // only called during teardown
@ -95,6 +90,8 @@ public:
void removeAction(const QUuid actionID); void removeAction(const QUuid actionID);
void forEachAction(std::function<void(EntityActionPointer)> actor); void forEachAction(std::function<void(EntityActionPointer)> actor);
void setSessionUUID(const QUuid& sessionID) { _sessionID = sessionID; }
private: private:
void addObjectToDynamicsWorld(ObjectMotionState* motionState); void addObjectToDynamicsWorld(ObjectMotionState* motionState);
void removeObjectFromDynamicsWorld(ObjectMotionState* motionState); void removeObjectFromDynamicsWorld(ObjectMotionState* motionState);
@ -111,23 +108,21 @@ private:
ThreadSafeDynamicsWorld* _dynamicsWorld = NULL; ThreadSafeDynamicsWorld* _dynamicsWorld = NULL;
btGhostPairCallback* _ghostPairCallback = NULL; btGhostPairCallback* _ghostPairCallback = NULL;
glm::vec3 _originOffset;
ContactMap _contactMap; ContactMap _contactMap;
uint32_t _numContactFrames = 0; CollisionEvents _collisionEvents;
QHash<QUuid, EntityActionPointer> _objectActions;
glm::vec3 _originOffset;
QUuid _sessionID;
/// character collisions
CharacterController* _myAvatarController; CharacterController* _myAvatarController;
uint32_t _numContactFrames = 0;
uint32_t _numSubsteps;
bool _dumpNextStats = false; bool _dumpNextStats = false;
bool _hasOutgoingChanges = false; bool _hasOutgoingChanges = false;
CollisionEvents _collisionEvents;
QHash<QUuid, EntityActionPointer> _objectActions;
uint32_t _numSubsteps;
}; };
typedef std::shared_ptr<PhysicsEngine> PhysicsEnginePointer; typedef std::shared_ptr<PhysicsEngine> PhysicsEnginePointer;

View file

@ -11,6 +11,9 @@
#include "PhysicsHelpers.h" #include "PhysicsHelpers.h"
#include "NumericalConstants.h" #include "NumericalConstants.h"
#include <QUuid>
#include "PhysicsCollisionGroups.h"
// This chunk of code was copied from Bullet-2.82, so we include the Bullet license here: // This chunk of code was copied from Bullet-2.82, so we include the Bullet license here:
/* /*
@ -19,12 +22,12 @@
* *
* This software is provided 'as-is', without any express or implied warranty. * This software is provided 'as-is', without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from the use of this software. * In no event will the authors be held liable for any damages arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose, * Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it freely, * including commercial applications, and to alter it and redistribute it freely,
* subject to the following restrictions: * subject to the following restrictions:
* *
* 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. * 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software.
* If you use this software in a product, an acknowledgment in the product documentation would be appreciated but * If you use this software in a product, an acknowledgment in the product documentation would be appreciated but
* is not required. * is not required.
* 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. * 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution. * 3. This notice may not be removed or altered from any source distribution.
@ -56,3 +59,33 @@ glm::quat computeBulletRotationStep(const glm::vec3& angularVelocity, float time
} }
return glm::quat(cosf(0.5f * speed * timeStep), axis.x, axis.y, axis.z); return glm::quat(cosf(0.5f * speed * timeStep), axis.x, axis.y, axis.z);
} }
/* end Bullet code derivation*/
int16_t Physics::getDefaultCollisionMask(int16_t group) {
switch(group) {
case BULLET_COLLISION_GROUP_STATIC:
return BULLET_COLLISION_MASK_STATIC;
case BULLET_COLLISION_GROUP_DYNAMIC:
return BULLET_COLLISION_MASK_DYNAMIC;
case BULLET_COLLISION_GROUP_KINEMATIC:
return BULLET_COLLISION_MASK_KINEMATIC;
case BULLET_COLLISION_GROUP_MY_AVATAR:
return BULLET_COLLISION_MASK_MY_AVATAR;
case BULLET_COLLISION_GROUP_OTHER_AVATAR:
return BULLET_COLLISION_MASK_OTHER_AVATAR;
default:
break;
};
return BULLET_COLLISION_MASK_COLLISIONLESS;
}
QUuid _sessionID;
void Physics::setSessionUUID(const QUuid& sessionID) {
_sessionID = sessionID;
}
const QUuid& Physics::getSessionUUID() {
return _sessionID;
}

View file

@ -14,6 +14,10 @@
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <glm/gtc/quaternion.hpp> #include <glm/gtc/quaternion.hpp>
#include <QUuid>
// TODO: move everything in here to the physics library after the physics/entities library
// dependency order is swapped.
const int PHYSICS_ENGINE_MAX_NUM_SUBSTEPS = 6; // Bullet will start to "lose time" at 10 FPS. const int PHYSICS_ENGINE_MAX_NUM_SUBSTEPS = 6; // Bullet will start to "lose time" at 10 FPS.
const float PHYSICS_ENGINE_FIXED_SUBSTEP = 1.0f / 90.0f; const float PHYSICS_ENGINE_FIXED_SUBSTEP = 1.0f / 90.0f;
@ -21,4 +25,11 @@ const float PHYSICS_ENGINE_FIXED_SUBSTEP = 1.0f / 90.0f;
// return incremental rotation (Bullet-style) caused by angularVelocity over timeStep // return incremental rotation (Bullet-style) caused by angularVelocity over timeStep
glm::quat computeBulletRotationStep(const glm::vec3& angularVelocity, float timeStep); glm::quat computeBulletRotationStep(const glm::vec3& angularVelocity, float timeStep);
namespace Physics {
int16_t getDefaultCollisionMask(int16_t group);
void setSessionUUID(const QUuid& sessionID);
const QUuid& getSessionUUID();
};
#endif // hifi_PhysicsHelpers_h #endif // hifi_PhysicsHelpers_h