restore transform of deactivated entities

This commit is contained in:
Andrew Meadows 2017-03-09 17:25:22 -08:00
parent d4abdcb6c8
commit 8ddcae2a15
10 changed files with 77 additions and 20 deletions

View file

@ -4439,7 +4439,10 @@ void Application::update(float deltaTime) {
getEntities()->getTree()->withWriteLock([&] {
PerformanceTimer perfTimer("handleOutgoingChanges");
const VectorOfMotionStates& outgoingChanges = _physicsEngine->getOutgoingChanges();
const VectorOfMotionStates& deactivations = _physicsEngine->getDeactivatedMotionStates();
_entitySimulation->handleDeactivatedMotionStates(deactivations);
const VectorOfMotionStates& outgoingChanges = _physicsEngine->getChangedMotionStates();
_entitySimulation->handleChangedMotionStates(outgoingChanges);
avatarManager->handleChangedMotionStates(outgoingChanges);
});

View file

@ -676,7 +676,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
filterRejection = newSimOwner.getID().isNull();
bool verbose = getName() == "fubar"; // adebug
if (verbose && _simulationOwner != newSimOwner) {
std::cout << (void*)(this) << " adebug ownership changed "
std::cout << (void*)(this) << " " << secTimestampNow() << " adebug ownership changed "
<< _simulationOwner.getID().toString().toStdString() << "." << (int)_simulationOwner.getPriority() << "-->"
<< newSimOwner.getID().toString().toStdString() << "." << (int)newSimOwner.getPriority()
<< std::endl; // adebug

View file

@ -10,6 +10,7 @@
//
#include <glm/gtx/norm.hpp>
#include <iostream> // adebug
#include <EntityItem.h>
#include <EntityItemProperties.h>
@ -28,7 +29,8 @@
#endif
// adebug TODO BOOKMARK:
// The problem is that userB may deactivate and disown and object before userA deactivates
// Consider an object near deactivation owned by userB and in view of userA...
// The problem is that userB may deactivate and disown the object before userA deactivates
// userA will sometimes insert non-zero velocities (and position errors) into the Entity before it is deactivated locally
//
// It would be nice to prevent data export from Bullet to Entity for unowned objects except in cases where it is really needed (?)
@ -109,6 +111,24 @@ void EntityMotionState::updateServerPhysicsVariables() {
_serverActionData = _entity->getActionData();
}
void EntityMotionState::handleDeactivation() {
// adebug
glm::vec3 pos = _entity->getPosition();
float dx = glm::distance(pos, _serverPosition);
glm::vec3 v = _entity->getVelocity();
float dv = glm::distance(v, _serverVelocity);
std::cout << "adebug deactivate '" << _entity->getName().toStdString()
<< "' dx = " << dx << " dv = " << dv << std::endl; // adebug
// adebug
// copy _server data to entity
bool success;
_entity->setPosition(_serverPosition, success, false);
_entity->setOrientation(_serverRotation, success, false);
_entity->setVelocity(ENTITY_ITEM_ZERO_VEC3);
_entity->setAngularVelocity(ENTITY_ITEM_ZERO_VEC3);
}
// virtual
void EntityMotionState::handleEasyChanges(uint32_t& flags) {
assert(entityTreeIsLocked());
@ -125,7 +145,7 @@ void EntityMotionState::handleEasyChanges(uint32_t& flags) {
_outgoingPriority = 0;
bool verbose = _entity->getName() == "fubar"; // adebug
if (verbose) {
std::cout << (void*)(this) << " adebug flag for deactivation" << std::endl; // adebug
std::cout << (void*)(this) << " " << secTimestampNow() << " adebug flag for deactivation" << std::endl; // adebug
}
} else {
// disowned object is still moving --> start timer for ownership bid
@ -244,7 +264,7 @@ void EntityMotionState::getWorldTransform(btTransform& worldTrans) const {
}
// This callback is invoked by the physics simulation at the end of each simulation step...
// iff the corresponding RigidBody is DYNAMIC and has moved.
// iff the corresponding RigidBody is DYNAMIC and ACTIVE.
void EntityMotionState::setWorldTransform(const btTransform& worldTrans) {
assert(_entity);
assert(entityTreeIsLocked());
@ -256,7 +276,10 @@ void EntityMotionState::setWorldTransform(const btTransform& worldTrans) {
// it goes inactive (at which point we should slam bullet to agree with entity)
if (_body->getActivationState() == WANTS_DEACTIVATION && !_entity->isMoving()) {
if (verbose) {
std::cout << (void*)(this) << " adebug v = " << _body->getLinearVelocity().length() << " w = " << _body->getAngularVelocity().length() << std::endl; // adebug
std::cout << (void*)(this) << " " << secTimestampNow() << " adebug entity at rest but physics is not?"
<< " v = " << _body->getLinearVelocity().length()
<< " w = " << _body->getAngularVelocity().length()
<< std::endl; // adebug
}
}
measureBodyAcceleration();
@ -279,7 +302,7 @@ void EntityMotionState::setWorldTransform(const btTransform& worldTrans) {
if (verbose
&& (glm::length(getBodyLinearVelocity()) > 0.0f || glm::length(getBodyAngularVelocity()) > 0.0f)
&& _entity->getSimulationOwner().getID().isNull()) {
std::cout << (void*)(this) << " adebug set non-zero v on unowned object AS = " << _body->getActivationState() << std::endl; // adebug
std::cout << (void*)(this) << " " << secTimestampNow() << " adebug set non-zero v on unowned object AS = " << _body->getActivationState() << std::endl; // adebug
}
_entity->setVelocity(getBodyLinearVelocity());
@ -627,7 +650,7 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_
_outgoingPriority = 0;
_entity->setPendingOwnershipPriority(_outgoingPriority, now);
if (verbose) {
std::cout << (void*)(this) << " adebug sendUpdate() clearOwnership numInactiveUpdates = " << (int)_numInactiveUpdates << std::endl; // adebug
std::cout << (void*)(this) << " " << secTimestampNow() << " adebug sendUpdate() clearOwnership numInactiveUpdates = " << (int)_numInactiveUpdates << std::endl; // adebug
}
} else if (Physics::getSessionUUID() != _entity->getSimulatorID()) {
// we don't own the simulation for this entity yet, but we're sending a bid for it
@ -640,7 +663,7 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_
_entity->rememberHasSimulationOwnershipBid();
// ...then reset _outgoingPriority in preparation for the next frame
if (verbose) {
std::cout << (void*)(this) << " adebug sendUpdate() bidOwnership at " << (int)_outgoingPriority << std::endl; // adebug
std::cout << (void*)(this) << " " << secTimestampNow() << " adebug sendUpdate() bidOwnership at " << (int)_outgoingPriority << std::endl; // adebug
}
_outgoingPriority = 0;
} else if (_outgoingPriority != _entity->getSimulationPriority()) {
@ -654,7 +677,7 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_
}
_entity->setPendingOwnershipPriority(_outgoingPriority, now);
if (verbose) {
std::cout << (void*)(this) << " adebug sendUpdate() changePriority to " << (int)_outgoingPriority << std::endl; // adebug
std::cout << (void*)(this) << " " << secTimestampNow() << " adebug sendUpdate() changePriority to " << (int)_outgoingPriority << std::endl; // adebug
}
}

View file

@ -29,6 +29,7 @@ public:
virtual ~EntityMotionState();
void updateServerPhysicsVariables();
void handleDeactivation();
virtual void handleEasyChanges(uint32_t& flags) override;
virtual bool handleHardAndEasyChanges(uint32_t& flags, PhysicsEngine* engine) override;

View file

@ -259,6 +259,19 @@ void PhysicalEntitySimulation::getObjectsToChange(VectorOfMotionStates& result)
_pendingChanges.clear();
}
void PhysicalEntitySimulation::handleDeactivatedMotionStates(const VectorOfMotionStates& motionStates) {
for (auto stateItr : motionStates) {
ObjectMotionState* state = &(*stateItr);
assert(state);
if (state->getType() == MOTIONSTATE_TYPE_ENTITY) {
EntityMotionState* entityState = static_cast<EntityMotionState*>(state);
entityState->handleDeactivation();
EntityItemPointer entity = entityState->getEntity();
_entitiesToSort.insert(entity);
}
}
}
void PhysicalEntitySimulation::handleChangedMotionStates(const VectorOfMotionStates& motionStates) {
QMutexLocker lock(&_mutex);

View file

@ -56,6 +56,7 @@ public:
void setObjectsToChange(const VectorOfMotionStates& objectsToChange);
void getObjectsToChange(VectorOfMotionStates& result);
void handleDeactivatedMotionStates(const VectorOfMotionStates& motionStates);
void handleChangedMotionStates(const VectorOfMotionStates& motionStates);
void handleCollisionEvents(const CollisionEvents& collisionEvents);

View file

@ -449,7 +449,7 @@ const CollisionEvents& PhysicsEngine::getCollisionEvents() {
return _collisionEvents;
}
const VectorOfMotionStates& PhysicsEngine::getOutgoingChanges() {
const VectorOfMotionStates& PhysicsEngine::getChangedMotionStates() {
BT_PROFILE("copyOutgoingChanges");
// Bullet will not deactivate static objects (it doesn't expect them to be active)
// so we must deactivate them ourselves

View file

@ -65,7 +65,8 @@ public:
bool hasOutgoingChanges() const { return _hasOutgoingChanges; }
/// \return reference to list of changed MotionStates. The list is only valid until beginning of next simulation loop.
const VectorOfMotionStates& getOutgoingChanges();
const VectorOfMotionStates& getChangedMotionStates();
const VectorOfMotionStates& getDeactivatedMotionStates() const { return _dynamicsWorld->getDeactivatedMotionStates(); }
/// \return reference to list of Collision events. The list is only valid until beginning of next simulation loop.
const CollisionEvents& getCollisionEvents();

View file

@ -128,25 +128,36 @@ void ThreadSafeDynamicsWorld::synchronizeMotionStates() {
for (int i=0;i<m_collisionObjects.size();i++) {
btCollisionObject* colObj = m_collisionObjects[i];
btRigidBody* body = btRigidBody::upcast(colObj);
if (body) {
if (body->getMotionState()) {
synchronizeMotionState(body);
_changedMotionStates.push_back(static_cast<ObjectMotionState*>(body->getMotionState()));
}
if (body && body->getMotionState()) {
synchronizeMotionState(body);
_changedMotionStates.push_back(static_cast<ObjectMotionState*>(body->getMotionState()));
}
}
} else {
//iterate over all active rigid bodies
// TODO? if this becomes a performance bottleneck we could derive our own SimulationIslandManager
// that remembers a list of objects it recently deactivated
_activeStates.clear();
_deactivatedStates.clear();
for (int i=0;i<m_nonStaticRigidBodies.size();i++) {
btRigidBody* body = m_nonStaticRigidBodies[i];
if (body->isActive()) {
if (body->getMotionState()) {
ObjectMotionState* motionState = static_cast<ObjectMotionState*>(body->getMotionState());
if (motionState) {
if (body->isActive()) {
synchronizeMotionState(body);
_changedMotionStates.push_back(static_cast<ObjectMotionState*>(body->getMotionState()));
_changedMotionStates.push_back(motionState);
_activeStates.insert(motionState);
} else if (_lastActiveStates.find(motionState) != _lastActiveStates.end()) {
// this object was active last frame but is no longer
_deactivatedStates.push_back(motionState);
}
}
}
}
if (_deactivatedStates.size() > 0) {
std::cout << secTimestampNow() << " adebug num deactivated = " << _deactivatedStates.size() << std::endl; // adebug
}
_activeStates.swap(_lastActiveStates);
}
void ThreadSafeDynamicsWorld::saveKinematicState(btScalar timeStep) {

View file

@ -49,12 +49,16 @@ public:
float getLocalTimeAccumulation() const { return m_localTime; }
const VectorOfMotionStates& getChangedMotionStates() const { return _changedMotionStates; }
const VectorOfMotionStates& getDeactivatedMotionStates() const { return _deactivatedStates; }
private:
// call this instead of non-virtual btDiscreteDynamicsWorld::synchronizeSingleMotionState()
void synchronizeMotionState(btRigidBody* body);
VectorOfMotionStates _changedMotionStates;
VectorOfMotionStates _deactivatedStates;
SetOfMotionStates _activeStates;
SetOfMotionStates _lastActiveStates;
};
#endif // hifi_ThreadSafeDynamicsWorld_h