Merge pull request #6867 from AndrewMeadows/collision-group-prep

cleanup in preparation for smarter collision grouping
This commit is contained in:
Seth Alves 2016-01-22 11:45:42 -08:00
commit 7a3401a8d7
10 changed files with 108 additions and 101 deletions

View file

@ -95,6 +95,7 @@
#include <PathUtils.h>
#include <PerfStat.h>
#include <PhysicsEngine.h>
#include <PhysicsHelpers.h>
#include <plugins/PluginContainer.h>
#include <plugins/PluginManager.h>
#include <RenderableWebEntityItem.h>
@ -3125,7 +3126,7 @@ void Application::update(float deltaTime) {
PerformanceTimer perfTimer("havestChanges");
if (_physicsEngine->hasOutgoingChanges()) {
getEntities()->getTree()->withWriteLock([&] {
_entitySimulation.handleOutgoingChanges(_physicsEngine->getOutgoingChanges(), _physicsEngine->getSessionID());
_entitySimulation.handleOutgoingChanges(_physicsEngine->getOutgoingChanges(), Physics::getSessionUUID());
avatarManager->handleOutgoingChanges(_physicsEngine->getOutgoingChanges());
});
@ -4225,6 +4226,9 @@ bool Application::acceptURL(const QString& urlString, bool defaultUpload) {
}
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);
}

View file

@ -146,6 +146,6 @@ QUuid AvatarMotionState::getSimulatorID() const {
// virtual
void AvatarMotionState::computeCollisionGroupAndMask(int16_t& group, int16_t& mask) const {
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) {
if (wantTerseEditLogging() && (id != _simulationOwner.getID() || priority != _simulationOwner.getPriority())) {
qCDebug(entities) << "sim ownership for" << getDebugName() << "is now" << id << priority;

View file

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

View file

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

View file

@ -82,7 +82,7 @@ EntityMotionState::~EntityMotionState() {
void EntityMotionState::updateServerPhysicsVariables() {
assert(entityTreeIsLocked());
if (_entity->getSimulatorID() == PhysicsEngine::getSessionID()) {
if (_entity->getSimulatorID() == Physics::getSessionUUID()) {
// don't slam these values if we are the simulation owner
return;
}
@ -113,7 +113,7 @@ bool EntityMotionState::handleEasyChanges(uint32_t& flags) {
_outgoingPriority = NO_PRORITY;
} else {
_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
_outgoingPriority = NO_PRORITY;
}
@ -527,7 +527,7 @@ uint32_t EntityMotionState::getIncomingDirtyFlags() {
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();
uint8_t entityCollisionMask = _entity->getCollisionless() ? 0 : _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
@ -622,39 +622,8 @@ QString EntityMotionState::getName() const {
// virtual
void EntityMotionState::computeCollisionGroupAndMask(int16_t& group, int16_t& mask) const {
group = BULLET_COLLISION_GROUP_STATIC;
if (_entity) {
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);
}
assert(_entity);
_entity->computeCollisionGroupAndFinalMask(group, mask);
}
void EntityMotionState::setOutgoingPriority(quint8 priority) {

View file

@ -18,47 +18,10 @@
#include "ThreadSafeDynamicsWorld.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) :
_originOffset(offset),
_sessionID(),
_myAvatarController(nullptr) {
initCollisionMaskTable();
}
PhysicsEngine::~PhysicsEngine() {
@ -90,6 +53,10 @@ void PhysicsEngine::init() {
}
}
uint32_t PhysicsEngine::getNumSubsteps() {
return _numSubsteps;
}
// private
void PhysicsEngine::addObjectToDynamicsWorld(ObjectMotionState* motionState) {
assert(motionState);

View file

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

View file

@ -11,6 +11,9 @@
#include "PhysicsHelpers.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:
/*
@ -19,12 +22,12 @@
*
* 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.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it freely,
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it freely,
* 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.
* If you use this software in a product, an acknowledgment in the product documentation would be appreciated but
* 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
* is not required.
* 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.
@ -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);
}
/* 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/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 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
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