mirror of
https://github.com/overte-org/overte.git
synced 2025-04-07 19:12:28 +02:00
Merge pull request #13574 from AndrewMeadows/grab-kinematic-children
more correct kinematic motion of grabbed things
This commit is contained in:
commit
4cf706dd96
4 changed files with 77 additions and 49 deletions
|
@ -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 {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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*/
|
||||
|
||||
|
|
Loading…
Reference in a new issue