diff --git a/interface/src/avatar/AvatarActionHold.cpp b/interface/src/avatar/AvatarActionHold.cpp index 87990b941e..5b493c4215 100644 --- a/interface/src/avatar/AvatarActionHold.cpp +++ b/interface/src/avatar/AvatarActionHold.cpp @@ -93,7 +93,7 @@ void AvatarActionHold::prepareForPhysicsSimulation() { activateBody(true); } -std::shared_ptr AvatarActionHold::getTarget(glm::quat& rotation, glm::vec3& position, +std::shared_ptr AvatarActionHold::getTarget(float deltaTimeStep, glm::quat& rotation, glm::vec3& position, glm::vec3& linearVelocity, glm::vec3& angularVelocity) { auto avatarManager = DependencyManager::get(); auto holdingAvatar = std::static_pointer_cast(avatarManager->getAvatarBySessionID(_holderID)); @@ -106,16 +106,16 @@ std::shared_ptr AvatarActionHold::getTarget(glm::quat& rotation, glm::ve bool isRightHand = (_hand == "right"); glm::vec3 palmPosition; glm::quat palmRotation; - glm::vec3 palmLinearVelocity; - glm::vec3 palmAngularVelocity; PalmData palmData = holdingAvatar->getHand()->getCopyOfPalmData(isRightHand ? HandData::RightHand : HandData::LeftHand); - // TODO: adjust according to _relativePosition and _relativeRotation? - linearVelocity = palmData.getVelocity(); - angularVelocity = palmData.getAngularVelocity(); + if (palmData.isValid()) { + // TODO: adjust according to _relativePosition and _relativeRotation? + linearVelocity = palmData.getVelocity(); + angularVelocity = palmData.getAngularVelocity(); + } - if (_ignoreIK && holdingAvatar->isMyAvatar()) { + if (_ignoreIK && holdingAvatar->isMyAvatar() && palmData.isValid()) { // We cannot ignore other avatars IK and this is not the point of this option // This is meant to make the grabbing behavior more reactive. palmPosition = palmData.getPosition(); @@ -153,6 +153,25 @@ std::shared_ptr AvatarActionHold::getTarget(glm::quat& rotation, glm::ve palmPosition = holdingAvatar->getLeftPalmPosition(); palmRotation = holdingAvatar->getLeftPalmRotation(); } + + // In this case we are simulating the grab of another avatar. + // Because the hand controller velocity for their palms is not transmitted over the + // network, we have to synthesize our own. + + if (_previousSet) { + // smooth linear velocity over two frames + glm::vec3 positionalDelta = palmPosition - _previousPositionalTarget; + linearVelocity = (positionalDelta + _previousPositionalDelta) / (deltaTimeStep + _previousDeltaTimeStep); + glm::quat deltaRotation = palmRotation * glm::inverse(_previousRotationalTarget); + float rotationAngle = glm::angle(deltaRotation); + if (rotationAngle > EPSILON) { + angularVelocity = glm::normalize(glm::axis(deltaRotation)); + angularVelocity *= (rotationAngle / deltaTimeStep); + } + + _previousPositionalDelta = positionalDelta; + _previousDeltaTimeStep = deltaTimeStep; + } } rotation = palmRotation * _relativeRotation; @@ -183,7 +202,7 @@ void AvatarActionHold::updateActionWorker(float deltaTimeStep) { glm::quat rotationForAction; glm::vec3 positionForAction; glm::vec3 linearVelocityForAction, angularVelocityForAction; - std::shared_ptr holdingAvatar = holdAction->getTarget(rotationForAction, positionForAction, linearVelocityForAction, angularVelocityForAction); + std::shared_ptr holdingAvatar = holdAction->getTarget(deltaTimeStep, rotationForAction, positionForAction, linearVelocityForAction, angularVelocityForAction); if (holdingAvatar) { holdCount ++; if (holdAction.get() == this) { @@ -254,6 +273,7 @@ void AvatarActionHold::doKinematicUpdate(float deltaTimeStep) { _previousPositionalTarget = _positionalTarget; _previousRotationalTarget = _rotationalTarget; + _previousDeltaTimeStep = deltaTimeStep; _previousSet = true; }); diff --git a/interface/src/avatar/AvatarActionHold.h b/interface/src/avatar/AvatarActionHold.h index 1c3a4386bc..0ad9cff257 100644 --- a/interface/src/avatar/AvatarActionHold.h +++ b/interface/src/avatar/AvatarActionHold.h @@ -36,7 +36,7 @@ public: virtual bool shouldSuppressLocationEdits() override { return _active && !_ownerEntity.expired(); } bool getAvatarRigidBodyLocation(glm::vec3& avatarRigidBodyPosition, glm::quat& avatarRigidBodyRotation); - std::shared_ptr getTarget(glm::quat& rotation, glm::vec3& position, + std::shared_ptr getTarget(float deltaTimeStep, glm::quat& rotation, glm::vec3& position, glm::vec3& linearVelocity, glm::vec3& angularVelocity); virtual void prepareForPhysicsSimulation() override; @@ -61,6 +61,7 @@ private: glm::vec3 _previousPositionalTarget; glm::quat _previousRotationalTarget; + float _previousDeltaTimeStep { 0.0f }; glm::vec3 _previousPositionalDelta; glm::vec3 _palmOffsetFromRigidBody;