cleanup how MotionStates are deleted from physics

also fixed some compile errors
removed cruft
This commit is contained in:
Andrew Meadows 2015-05-01 08:28:32 -07:00
parent 9f8b266a03
commit 4cb469dd79
8 changed files with 127 additions and 114 deletions

View file

@ -2355,7 +2355,7 @@ void Application::update(float deltaTime) {
PerformanceTimer perfTimer("physics");
_myAvatar->relayDriveKeysToCharacterController();
_physicsEngine.removeObjects(_entitySimulation.getObjectsToRemove());
_physicsEngine.deleteObjects(_entitySimulation.getObjectsToRemove());
_physicsEngine.addObjects(_entitySimulation.getObjectsToAdd());
_physicsEngine.changeObjects(_entitySimulation.getObjectsToChange());

View file

@ -40,7 +40,6 @@ public:
virtual void setWorldTransform(const btTransform& worldTrans);
virtual void computeObjectShapeInfo(ShapeInfo& shapeInfo);
virtual float computeObjectMass(const ShapeInfo& shapeInfo) const;
bool doesNotNeedToSendUpdate() const;
bool remoteSimulationOutOfSync(uint32_t simulationStep);

View file

@ -115,15 +115,15 @@ void ObjectMotionState::handleEasyChanges(uint32_t flags) {
if (flags & EntityItem::DIRTY_POSITION) {
btTransform worldTrans;
if (flags & EntityItem::DIRTY_ROTATION) {
worldTrans = getObjectTransform();
worldTrans.setRotation(glmToBullet(getObjectRotation()));
} else {
worldTrans = _body->getWorldTransform();
worldTrans.setOrigin(getObjectPosition());
}
worldTrans.setOrigin(glmToBullet(getObjectPosition()));
_body->setWorldTransform(worldTrans);
} else {
btTransform worldTrans = _body->getWorldTransform();
worldTrans.setRotation(getObjectRotation());
worldTrans.setRotation(glmToBullet(getObjectRotation()));
_body->setWorldTransform(worldTrans);
}
@ -155,14 +155,13 @@ void ObjectMotionState::handleHardAndEasyChanges(uint32_t flags, PhysicsEngine*
if (flags & EntityItem::DIRTY_SHAPE) {
// make sure the new shape is valid
ShapeInfo shapeInfo;
motionState->computeObjectShapeInfo(shapeInfo);
computeObjectShapeInfo(shapeInfo);
btCollisionShape* newShape = getShapeManager()->getShape(shapeInfo);
if (!newShape) {
// failed to generate new shape!
// remove shape-change flag
// failed to generate new shape! --> keep old shape and remove shape-change flag
flags &= ~EntityItem::DIRTY_SHAPE;
// TODO: force this object out of PhysicsEngine rather than just use the old shape
if (flags & HARD_DIRTY_PHYSICS_FLAGS == 0) {
if ((flags & HARD_DIRTY_PHYSICS_FLAGS) == 0) {
// no HARD flags remain, so do any EASY changes
if (flags & EASY_DIRTY_PHYSICS_FLAGS) {
handleEasyChanges(flags);
@ -170,21 +169,18 @@ void ObjectMotionState::handleHardAndEasyChanges(uint32_t flags, PhysicsEngine*
return;
}
}
engine->removeRigidBody(_body);
getShapeManager()->removeReference(_shape);
getShapeManager()->releaseShape(_shape);
_shape = newShape;
_body->setShape(_shape);
_body->setCollisionShape(_shape);
if (flags & EASY_DIRTY_PHYSICS_FLAGS) {
handleEasyChanges(flags);
}
engine->addRigidBody(_body, motionType, mass);
} else {
engine->removeRigidBody(_body);
if (flags & EASY_DIRTY_PHYSICS_FLAGS) {
handleEasyChanges(flags);
}
engine->addRigidBody(_body, motionType, mass);
}
engine->reinsertObject(this);
}
void ObjectMotionState::updateBodyMaterialProperties() {

View file

@ -90,6 +90,8 @@ public:
virtual void clearIncomingDirtyFlags(uint32_t flags) = 0;
virtual MotionType computeObjectMotionType() const = 0;
virtual void computeObjectShapeInfo(ShapeInfo& shapeInfo);
btCollisionShape* getShape() const { return _shape; }
btRigidBody* getRigidBody() const { return _body; }

View file

@ -59,8 +59,6 @@ void PhysicalEntitySimulation::removeEntityInternal(EntityItem* entity) {
void* physicsInfo = entity->getPhysicsInfo();
if (physicsInfo) {
_pendingRemoves.insert(entity);
} else {
clearEntitySimulation(entity);
}
}
@ -69,9 +67,6 @@ void PhysicalEntitySimulation::deleteEntityInternal(EntityItem* entity) {
void* physicsInfo = entity->getPhysicsInfo();
if (physicsInfo) {
_pendingRemoves.insert(entity);
} else {
clearEntitySimulation(entity);
delete entity;
}
}
@ -110,16 +105,18 @@ void PhysicalEntitySimulation::clearEntitiesInternal() {
// while it is in the middle of a simulation step. As it is, we're probably in shutdown mode
// anyway, so maybe the simulation was already properly shutdown? Cross our fingers...
_physicsEngine->deleteObjects(_physicalEntities);
for (auto stateItr : _physicalEntities) {
// first disconnect each MotionStates from its Entity
for (auto stateItr : _physicalObjects) {
EntityMotionState* motionState = static_cast<EntityMotionState*>(&(*stateItr));
EntityItem* entity = motionState->getEntity();
entity->setPhysicsInfo(nullptr);
delete motionState;
}
_physicalEntities.clear();
// then delete the objects (aka MotionStates)
_physicsEngine->deleteObjects(_physicalObjects);
// finally clear all lists (which now have only dangling pointers)
_physicalObjects.clear();
_pendingRemoves.clear();
_pendingAdds.clear();
_pendingChanges.clear();
@ -127,7 +124,7 @@ void PhysicalEntitySimulation::clearEntitiesInternal() {
// end EntitySimulation overrides
VectorOfMotionStates& PhysicalEntitySimulation::getObjectsToRemove() {
VectorOfMotionStates& PhysicalEntitySimulation::getObjectsToDelete() {
_tempVector.clear();
for (auto entityItr : _pendingRemoves) {
EntityItem* entity = &(*entityItr);
@ -135,8 +132,12 @@ VectorOfMotionStates& PhysicalEntitySimulation::getObjectsToRemove() {
_pendingChanges.remove(entity);
EntityMotionState* motionState = static_cast<EntityMotionState*>(entity->getPhysicsInfo());
if (motionState) {
_physicalObjects.remove(motionState);
// disconnect EntityMotionState from its Entity
// NOTE: EntityMotionState still has a back pointer to its Entity, but is about to be deleted
// (by PhysicsEngine) and shouldn't actually access its Entity during this process.
entity->setPhysicsInfo(nullptr);
_tempVector.push_back(motionState);
_physicalEntities.remove(motionState);
}
}
_pendingRemoves.clear();
@ -158,7 +159,7 @@ VectorOfMotionStates& PhysicalEntitySimulation::getObjectsToAdd() {
EntityMotionState* motionState = new EntityMotionState(shape, entity);
entity->setPhysicsInfo(static_cast<void*>(motionState));
motionState->setMass(entity->computeMass());
_physicalEntities.insert(motionState);
_physicalObjects.insert(motionState);
_tempVector.push_back(motionState);
entityItr = _pendingAdds.erase(entityItr);
} else {

View file

@ -42,7 +42,7 @@ public:
void sortEntitiesThatMovedInternal();
void clearEntitiesInternal();
VectorOfMotionStates& getObjectsToRemove();
VectorOfMotionStates& getObjectsToDelete();
VectorOfMotionStates& getObjectsToAdd();
VectorOfMotionStates& getObjectsToChange();
@ -52,15 +52,15 @@ private:
void bump(EntityItem* bumpEntity);
// incoming changes
SetOfEntities _pendingRemoves; // entities to be removed from simulation
SetOfEntities _pendingAdds; // entities to be be added to simulation
SetOfEntities _pendingChanges; // entities already in simulation that need to be changed
SetOfEntities _pendingRemoves; // entities to be removed from PhysicsEngine (and their MotionState deleted)
SetOfEntities _pendingAdds; // entities to be be added to PhysicsEngine (and a their MotionState created)
SetOfEntities _pendingChanges; // entities already in PhysicsEngine that need their physics changed
// outgoing changes
QSet<EntityMotionState*> _outgoingChanges; // entities for which we need to send updates to entity-server
SetOfMotionStates _physicalEntities; // MotionStates of entities in PhysicsEngine
VectorOfMotionStates _tempVector; // temporary list, valid by reference immediately after call to getObjectsToRemove/Add/Update()
SetOfMotionStates _physicalObjects; // MotionStates of entities in PhysicsEngine
VectorOfMotionStates _tempVector; // temporary array, valid by reference immediately after call to getObjectsToRemove/Add/Update()
ShapeManager* _shapeManager = nullptr;
PhysicsEngine* _physicsEngine = nullptr;

View file

@ -59,42 +59,113 @@ void PhysicsEngine::init() {
}
}
void PhysicsEngine::removeObjects(VectorOfMotionStates& objects) {
for (auto object : objects) {
assert(object);
// wake up anything touching this object
bump(object);
void PhysicsEngine::addObject(ObjectMotionState* motionState) {
assert(motionState);
btRigidBody* body = object->getRigidBody();
_dynamicsWorld->removeRigidBody(body);
removeContacts(object);
btVector3 inertia(0.0f, 0.0f, 0.0f);
float mass = 0.0f;
// NOTE: the body may or may not already exist, depending on whether this corresponds to a reinsertion, or a new insertion.
btRigidBody* body = motionState->getRigidBody();
MotionType motionType = motionState->computeObjectMotionType();
motionState->setMotionType(motionType);
switch(motionType) {
case MOTION_TYPE_KINEMATIC: {
if (!body) {
btCollisionShape* shape = motionState->getShape();
assert(shape);
body = new btRigidBody(mass, motionState, shape, inertia);
} else {
body->setMassProps(mass, inertia);
}
body->setCollisionFlags(btCollisionObject::CF_KINEMATIC_OBJECT);
body->updateInertiaTensor();
motionState->setRigidBody(body);
motionState->updateBodyVelocities();
const float KINEMATIC_LINEAR_VELOCITY_THRESHOLD = 0.01f; // 1 cm/sec
const float KINEMATIC_ANGULAR_VELOCITY_THRESHOLD = 0.01f; // ~1 deg/sec
body->setSleepingThresholds(KINEMATIC_LINEAR_VELOCITY_THRESHOLD, KINEMATIC_ANGULAR_VELOCITY_THRESHOLD);
break;
}
case MOTION_TYPE_DYNAMIC: {
mass = motionState->getMass();
btCollisionShape* shape = motionState->getShape();
assert(shape);
shape->calculateLocalInertia(mass, inertia);
if (!body) {
body = new btRigidBody(mass, motionState, shape, inertia);
} else {
body->setMassProps(mass, inertia);
}
body->updateInertiaTensor();
motionState->setRigidBody(body);
motionState->updateBodyVelocities();
// NOTE: Bullet will deactivate any object whose velocity is below these thresholds for longer than 2 seconds.
// (the 2 seconds is determined by: static btRigidBody::gDeactivationTime
const float DYNAMIC_LINEAR_VELOCITY_THRESHOLD = 0.05f; // 5 cm/sec
const float DYNAMIC_ANGULAR_VELOCITY_THRESHOLD = 0.087266f; // ~5 deg/sec
body->setSleepingThresholds(DYNAMIC_LINEAR_VELOCITY_THRESHOLD, DYNAMIC_ANGULAR_VELOCITY_THRESHOLD);
if (!motionState->isMoving()) {
// try to initialize this object as inactive
body->forceActivationState(ISLAND_SLEEPING);
}
break;
}
case MOTION_TYPE_STATIC:
default: {
if (!body) {
body = new btRigidBody(mass, motionState, shape, inertia);
} else {
body->setMassProps(mass, inertia);
}
body->setCollisionFlags(btCollisionObject::CF_STATIC_OBJECT);
body->updateInertiaTensor();
motionState->setRigidBody(body);
break;
}
}
body->setFlags(BT_DISABLE_WORLD_GRAVITY);
motionState->updateBodyMaterialProperties();
_dynamicsWorld->addRigidBody(body);
}
void PhysicsEngine::removeObject(ObjectMotionState* object) {
// wake up anything touching this object
bump(object);
removeContacts(object);
btRigidBody* body = object->getRigidBody();
assert(body);
_dynamicsWorld->removeRigidBody(body);
}
void PhysicsEngine::deleteObjects(VectorOfMotionStates& objects) {
for (auto object : objects) {
removeObject(object);
// NOTE: setRigidBody() modifies body->m_userPointer so we should clear the MotionState's body BEFORE deleting it.
object->setRigidBody(nullptr);
delete body;
object->releaseShape();
delete object;
}
}
// Same as above, but takes a Set instead of a Vector. Only called during teardown.
void PhysicsEngine::deleteObjects(SetOfMotionStates& objects) {
for (auto object : objects) {
assert(object);
btRigidBody* body = object->getRigidBody();
_dynamicsWorld->removeRigidBody(body);
removeContacts(object);
// NOTE: setRigidBody() modifies body->m_userPointer so we should clear the MotionState's body BEFORE deleting it.
object->setRigidBody(nullptr);
delete body;
object->releaseShape();
delete object;
}
}
void PhysicsEngine::addObjects(VectorOfMotionStates& objects) {
for (auto object : objects) {
assert(object);
addObject(object);
}
}
@ -302,62 +373,13 @@ void PhysicsEngine::dumpStatsIfNecessary() {
// CF_DISABLE_VISUALIZE_OBJECT = 32, //disable debug drawing
// CF_DISABLE_SPU_COLLISION_PROCESSING = 64//disable parallel/SPU processing
void PhysicsEngine::addObject(ObjectMotionState* motionState) {
assert(motionState);
btCollisionShape* shape = motionState->getShape();
assert(shape);
btVector3 inertia(0.0f, 0.0f, 0.0f);
float mass = 0.0f;
btRigidBody* body = nullptr;
MotionType motionType = motionState->computeObjectMotionType();
motionState->setMotionType(motionType);
switch(motionType) {
case MOTION_TYPE_KINEMATIC: {
body = new btRigidBody(mass, motionState, shape, inertia);
body->setCollisionFlags(btCollisionObject::CF_KINEMATIC_OBJECT);
body->updateInertiaTensor();
motionState->setRigidBody(body);
motionState->updateBodyVelocities();
const float KINEMATIC_LINEAR_VELOCITY_THRESHOLD = 0.01f; // 1 cm/sec
const float KINEMATIC_ANGULAR_VELOCITY_THRESHOLD = 0.01f; // ~1 deg/sec
body->setSleepingThresholds(KINEMATIC_LINEAR_VELOCITY_THRESHOLD, KINEMATIC_ANGULAR_VELOCITY_THRESHOLD);
break;
}
case MOTION_TYPE_DYNAMIC: {
mass = motionState->getMass();
shape->calculateLocalInertia(mass, inertia);
body = new btRigidBody(mass, motionState, shape, inertia);
body->updateInertiaTensor();
motionState->setRigidBody(body);
motionState->updateBodyVelocities();
// NOTE: Bullet will deactivate any object whose velocity is below these thresholds for longer than 2 seconds.
// (the 2 seconds is determined by: static btRigidBody::gDeactivationTime
const float DYNAMIC_LINEAR_VELOCITY_THRESHOLD = 0.05f; // 5 cm/sec
const float DYNAMIC_ANGULAR_VELOCITY_THRESHOLD = 0.087266f; // ~5 deg/sec
body->setSleepingThresholds(DYNAMIC_LINEAR_VELOCITY_THRESHOLD, DYNAMIC_ANGULAR_VELOCITY_THRESHOLD);
if (!motionState->isMoving()) {
// try to initialize this object as inactive
body->forceActivationState(ISLAND_SLEEPING);
}
break;
}
case MOTION_TYPE_STATIC:
default: {
body = new btRigidBody(mass, motionState, shape, inertia);
body->setCollisionFlags(btCollisionObject::CF_STATIC_OBJECT);
body->updateInertiaTensor();
motionState->setRigidBody(body);
break;
}
}
body->setFlags(BT_DISABLE_WORLD_GRAVITY);
motionState->updateBodyMaterialProperties();
_dynamicsWorld->addRigidBody(body);
void PhysicsEngine::reinsertObject(ObjectMotionState* object) {
removeObject(object);
addObject(object);
}
void PhysicsEngine::bump(ObjectMotionState* object) {
assert(object);
/* TODO: Andrew to implement this
// If this node is doing something like deleting an entity, scan for contacts involving the
// entity. For each found, flag the other entity involved as being simulated by this node.
@ -437,11 +459,6 @@ void PhysicsEngine::bump(EntityItem* bumpEntity) {
}
*/
void PhysicsEngine::removeRigidBody(btRigidBody* body) {
// pull body out of physics engine
_dynamicsWorld->removeRigidBody(body);
}
void PhysicsEngine::setCharacterController(DynamicCharacterController* character) {
if (_characterController != character) {
if (_characterController) {

View file

@ -51,9 +51,11 @@ public:
~PhysicsEngine();
void init();
/// process queue of changed from external sources
void removeObjects(VectorOfMotionStates& objects);
void deleteObjects(SetOfMotionStates& objects);
void addObject(ObjectMotionState* motionState);
void removeObject(ObjectMotionState* motionState);
void deleteObjects(VectorOfMotionStates& objects);
void deleteObjects(SetOfMotionStates& objects); // only called during teardown
void addObjects(VectorOfMotionStates& objects);
void changeObjects(VectorOfMotionStates& objects);
@ -71,10 +73,6 @@ public:
/// \return position of simulation origin in domain-frame
const glm::vec3& getOriginOffset() const { return _originOffset; }
/// \param motionState pointer to Object's MotionState
/// \return true if Object added
void addObject(ObjectMotionState* motionState);
void bump(ObjectMotionState* motionState);
void removeRigidBody(btRigidBody* body);