Merge pull request #13574 from AndrewMeadows/grab-kinematic-children

more correct kinematic motion of grabbed things
This commit is contained in:
Seth Alves 2018-07-11 10:34:44 -07:00 committed by GitHub
commit 4cf706dd96
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 77 additions and 49 deletions

View file

@ -2414,11 +2414,7 @@ bool EntityItem::shouldSuppressLocationEdits() const {
}
// if any of the ancestors are MyAvatar, suppress
if (isChildOfMyAvatar()) {
return true;
}
return false;
return isChildOfMyAvatar();
}
QList<EntityDynamicPointer> EntityItem::getActionsOfType(EntityDynamicType typeToGet) const {

View file

@ -234,7 +234,7 @@ void EntityMotionState::getWorldTransform(btTransform& worldTrans) const {
return;
}
assert(entityTreeIsLocked());
if (_motionType == MOTION_TYPE_KINEMATIC && !_entity->hasAncestorOfType(NestableType::Avatar)) {
if (_motionType == MOTION_TYPE_KINEMATIC) {
BT_PROFILE("kinematicIntegration");
// This is physical kinematic motion which steps strictly by the subframe count
// of the physics simulation and uses full gravity for acceleration.
@ -327,13 +327,6 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) {
return true;
}
bool parentTransformSuccess;
Transform localToWorld = _entity->getParentTransform(parentTransformSuccess);
Transform worldToLocal;
if (parentTransformSuccess) {
localToWorld.evalInverse(worldToLocal);
}
int numSteps = simulationStep - _lastStep;
float dt = (float)(numSteps) * PHYSICS_ENGINE_FIXED_SUBSTEP;
@ -361,6 +354,10 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) {
return true;
}
if (_body->isStaticOrKinematicObject()) {
return false;
}
_lastStep = simulationStep;
if (glm::length2(_serverVelocity) > 0.0f) {
// the entity-server doesn't know where avatars are, so it doesn't do simple extrapolation for children of
@ -388,6 +385,12 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) {
// TODO: compensate for _worldOffset offset here
// compute position error
bool parentTransformSuccess;
Transform localToWorld = _entity->getParentTransform(parentTransformSuccess);
Transform worldToLocal;
if (parentTransformSuccess) {
localToWorld.evalInverse(worldToLocal);
}
btTransform worldTrans = _body->getWorldTransform();
glm::vec3 position = worldToLocal.transform(bulletToGLM(worldTrans.getOrigin()));
@ -407,20 +410,23 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) {
if (glm::length2(_serverAngularVelocity) > 0.0f) {
// compute rotation error
float attenuation = powf(1.0f - _body->getAngularDamping(), dt);
_serverAngularVelocity *= attenuation;
//
// Bullet caps the effective rotation velocity inside its rotation integration step, therefore
// we must integrate with the same algorithm and timestep in order achieve similar results.
for (int i = 0; i < numSteps; ++i) {
_serverRotation = glm::normalize(computeBulletRotationStep(_serverAngularVelocity,
PHYSICS_ENGINE_FIXED_SUBSTEP) * _serverRotation);
float attenuation = powf(1.0f - _body->getAngularDamping(), PHYSICS_ENGINE_FIXED_SUBSTEP);
_serverAngularVelocity *= attenuation;
glm::quat rotation = computeBulletRotationStep(_serverAngularVelocity, PHYSICS_ENGINE_FIXED_SUBSTEP);
for (int i = 1; i < numSteps; ++i) {
_serverAngularVelocity *= attenuation;
rotation = computeBulletRotationStep(_serverAngularVelocity, PHYSICS_ENGINE_FIXED_SUBSTEP) * rotation;
}
_serverRotation = glm::normalize(rotation * _serverRotation);
const float MIN_ROTATION_DOT = 0.99999f; // This corresponds to about 0.5 degrees of rotation
glm::quat actualRotation = worldToLocal.getRotation() * bulletToGLM(worldTrans.getRotation());
return (fabsf(glm::dot(actualRotation, _serverRotation)) < MIN_ROTATION_DOT);
}
const float MIN_ROTATION_DOT = 0.99999f; // This corresponds to about 0.5 degrees of rotation
glm::quat actualRotation = worldToLocal.getRotation() * bulletToGLM(worldTrans.getRotation());
return (fabsf(glm::dot(actualRotation, _serverRotation)) < MIN_ROTATION_DOT);
return false;
}
bool EntityMotionState::shouldSendUpdate(uint32_t simulationStep) {

View file

@ -59,7 +59,10 @@ void PhysicalEntitySimulation::addEntityInternal(EntityItemPointer entity) {
_entitiesToAddToPhysics.insert(entity);
}
} else if (canBeKinematic && entity->isMovingRelativeToParent()) {
_simpleKinematicEntities.insert(entity);
SetOfEntities::iterator itr = _simpleKinematicEntities.find(entity);
if (itr == _simpleKinematicEntities.end()) {
_simpleKinematicEntities.insert(entity);
}
}
}
@ -150,7 +153,10 @@ void PhysicalEntitySimulation::changeEntityInternal(EntityItemPointer entity) {
removeOwnershipData(motionState);
_entitiesToRemoveFromPhysics.insert(entity);
if (canBeKinematic && entity->isMovingRelativeToParent()) {
_simpleKinematicEntities.insert(entity);
SetOfEntities::iterator itr = _simpleKinematicEntities.find(entity);
if (itr == _simpleKinematicEntities.end()) {
_simpleKinematicEntities.insert(entity);
}
}
} else {
_incomingChanges.insert(motionState);
@ -160,11 +166,20 @@ void PhysicalEntitySimulation::changeEntityInternal(EntityItemPointer entity) {
// The intent is for this object to be in the PhysicsEngine, but it has no MotionState yet.
// Perhaps it's shape has changed and it can now be added?
_entitiesToAddToPhysics.insert(entity);
_simpleKinematicEntities.remove(entity); // just in case it's non-physical-kinematic
SetOfEntities::iterator itr = _simpleKinematicEntities.find(entity);
if (itr != _simpleKinematicEntities.end()) {
_simpleKinematicEntities.erase(itr);
}
} else if (canBeKinematic && entity->isMovingRelativeToParent()) {
_simpleKinematicEntities.insert(entity);
SetOfEntities::iterator itr = _simpleKinematicEntities.find(entity);
if (itr == _simpleKinematicEntities.end()) {
_simpleKinematicEntities.insert(entity);
}
} else {
_simpleKinematicEntities.remove(entity); // just in case it's non-physical-kinematic
SetOfEntities::iterator itr = _simpleKinematicEntities.find(entity);
if (itr != _simpleKinematicEntities.end()) {
_simpleKinematicEntities.erase(itr);
}
}
}
@ -212,7 +227,6 @@ const VectorOfMotionStates& PhysicalEntitySimulation::getObjectsToRemoveFromPhys
assert(motionState);
// TODO CLEan this, just a n extra check to avoid the crash that shouldn;t happen
if (motionState) {
_entitiesToAddToPhysics.remove(entity);
if (entity->isDead() && entity->getElement()) {
_deadEntities.insert(entity);
@ -255,7 +269,10 @@ void PhysicalEntitySimulation::getObjectsToAddToPhysics(VectorOfMotionStates& re
// this entity should no longer be on the internal _entitiesToAddToPhysics
entityItr = _entitiesToAddToPhysics.erase(entityItr);
if (entity->isMovingRelativeToParent()) {
_simpleKinematicEntities.insert(entity);
SetOfEntities::iterator itr = _simpleKinematicEntities.find(entity);
if (itr == _simpleKinematicEntities.end()) {
_simpleKinematicEntities.insert(entity);
}
}
} else if (entity->isReadyToComputeShape()) {
ShapeInfo shapeInfo;
@ -375,19 +392,21 @@ void PhysicalEntitySimulation::handleChangedMotionStates(const VectorOfMotionSta
}
void PhysicalEntitySimulation::addOwnershipBid(EntityMotionState* motionState) {
if (!getEntityTree()->isServerlessMode()) {
motionState->initForBid();
motionState->sendBid(_entityPacketSender, _physicsEngine->getNumSubsteps());
_bids.push_back(motionState);
_nextBidExpiry = glm::min(_nextBidExpiry, motionState->getNextBidExpiry());
if (getEntityTree()->isServerlessMode()) {
return;
}
motionState->initForBid();
motionState->sendBid(_entityPacketSender, _physicsEngine->getNumSubsteps());
_bids.push_back(motionState);
_nextBidExpiry = glm::min(_nextBidExpiry, motionState->getNextBidExpiry());
}
void PhysicalEntitySimulation::addOwnership(EntityMotionState* motionState) {
if (!getEntityTree()->isServerlessMode()) {
motionState->initForOwned();
_owned.push_back(motionState);
if (getEntityTree()->isServerlessMode()) {
return;
}
motionState->initForOwned();
_owned.push_back(motionState);
}
void PhysicalEntitySimulation::sendOwnershipBids(uint32_t numSubsteps) {
@ -426,7 +445,9 @@ void PhysicalEntitySimulation::sendOwnershipBids(uint32_t numSubsteps) {
}
void PhysicalEntitySimulation::sendOwnedUpdates(uint32_t numSubsteps) {
bool serverlessMode = getEntityTree()->isServerlessMode();
if (getEntityTree()->isServerlessMode()) {
return;
}
PROFILE_RANGE_EX(simulation_physics, "Update", 0x00000000, (uint64_t)_owned.size());
uint32_t i = 0;
while (i < _owned.size()) {
@ -438,7 +459,7 @@ void PhysicalEntitySimulation::sendOwnedUpdates(uint32_t numSubsteps) {
}
_owned.remove(i);
} else {
if (!serverlessMode && _owned[i]->shouldSendUpdate(numSubsteps)) {
if (_owned[i]->shouldSendUpdate(numSubsteps)) {
_owned[i]->sendUpdate(_entityPacketSender, numSubsteps);
}
++i;

View file

@ -42,22 +42,27 @@ glm::quat computeBulletRotationStep(const glm::vec3& angularVelocity, float time
// Exponential map
// google for "Practical Parameterization of Rotations Using the Exponential Map", F. Sebastian Grassia
float speed = glm::length(angularVelocity);
glm::vec3 axis = angularVelocity;
float angle = glm::length(axis) * timeStep;
// limit the angular motion because the exponential approximation fails for large steps
const float ANGULAR_MOTION_THRESHOLD = 0.5f * PI_OVER_TWO;
if (speed * timeStep > ANGULAR_MOTION_THRESHOLD) {
speed = ANGULAR_MOTION_THRESHOLD / timeStep;
if (angle > ANGULAR_MOTION_THRESHOLD) {
angle = ANGULAR_MOTION_THRESHOLD;
}
glm::vec3 axis = angularVelocity;
if (speed < 0.001f) {
// use Taylor's expansions of sync function
axis *= (0.5f * timeStep - (timeStep * timeStep * timeStep) * (0.020833333333f * speed * speed));
const float MIN_ANGLE = 0.001f;
if (angle < MIN_ANGLE) {
// for small angles use Taylor's expansion of sin(x):
// sin(x) = x - (x^3)/(3!) + ...
// where: x = angle/2
// sin(angle/2) = angle/2 - (angle*angle*angle)/48
// but (angle = speed * timeStep) and we want to normalize the axis by dividing by speed
// which gives us:
axis *= timeStep * (0.5f - 0.020833333333f * angle * angle);
} else {
// sync(speed) = sin(c * speed)/t
axis *= (sinf(0.5f * speed * timeStep) / speed );
axis *= (sinf(0.5f * angle) * timeStep / angle);
}
return glm::quat(cosf(0.5f * speed * timeStep), axis.x, axis.y, axis.z);
return glm::quat(cosf(0.5f * angle), axis.x, axis.y, axis.z);
}
/* end Bullet code derivation*/