void AvatarActionHold::updateActionWorker(float deltaTimeStep) { if (!_mine) { // if a local script isn't updating this, then we are just getting spring-action data over the wire. // let the super-class handle it. ObjectActionSpring::updateActionWorker(deltaTimeStep); return; } glm::quat rotation; glm::vec3 position; glm::vec3 offset; bool gotLock = withTryReadLock([&]{ auto myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar(); glm::vec3 palmPosition; glm::quat palmRotation; if (_hand == "right") { palmPosition = myAvatar->getRightPalmPosition(); palmRotation = myAvatar->getRightPalmRotation(); } else { palmPosition = myAvatar->getLeftPalmPosition(); palmRotation = myAvatar->getLeftPalmRotation(); } rotation = palmRotation * _relativeRotation; offset = rotation * _relativePosition; position = palmPosition + offset; }); if (gotLock) { gotLock = withTryWriteLock([&]{ if (_positionalTarget != position || _rotationalTarget != rotation) { auto ownerEntity = _ownerEntity.lock(); if (ownerEntity) { ownerEntity->setActionDataDirty(true); } _positionalTarget = position; _rotationalTarget = rotation; } }); } if (gotLock) { ObjectActionSpring::updateActionWorker(deltaTimeStep); } }
void AvatarActionHold::updateActionWorker(float deltaTimeStep) { bool gotLock = false; glm::quat rotation; glm::vec3 position; glm::vec3 offset; gotLock = withTryReadLock([&]{ auto myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar(); glm::vec3 palmPosition; glm::quat palmRotation; if (_hand == "right") { palmPosition = myAvatar->getRightPalmPosition(); palmRotation = myAvatar->getRightPalmRotation(); } else { palmPosition = myAvatar->getLeftPalmPosition(); palmRotation = myAvatar->getLeftPalmRotation(); } rotation = palmRotation * _relativeRotation; offset = rotation * _relativePosition; position = palmPosition + offset; }); if (gotLock) { gotLock = withTryWriteLock([&]{ _positionalTarget = position; _rotationalTarget = rotation; _positionalTargetSet = true; _rotationalTargetSet = true; auto ownerEntity = _ownerEntity.lock(); if (ownerEntity) { ownerEntity->setActionDataDirty(true); } }); } if (gotLock) { ObjectActionSpring::updateActionWorker(deltaTimeStep); } }
bool AvatarActionHold::getTarget(float deltaTimeStep, glm::quat& rotation, glm::vec3& position, glm::vec3& linearVelocity, glm::vec3& angularVelocity, float& linearTimeScale, float& angularTimeScale) { auto avatarManager = DependencyManager::get<AvatarManager>(); auto holdingAvatar = std::static_pointer_cast<Avatar>(avatarManager->getAvatarBySessionID(_holderID)); if (!holdingAvatar) { return false;; } withReadLock([&]{ bool isRightHand = (_hand == "right"); glm::vec3 palmPosition; glm::quat palmRotation; if (holdingAvatar->isMyAvatar()) { std::shared_ptr<MyAvatar> myAvatar = avatarManager->getMyAvatar(); // fetch the hand controller pose controller::Pose pose; if (isRightHand) { pose = myAvatar->getControllerPoseInWorldFrame(controller::Action::RIGHT_HAND); } else { pose = myAvatar->getControllerPoseInWorldFrame(controller::Action::LEFT_HAND); } if (pose.isValid()) { linearVelocity = pose.getVelocity(); angularVelocity = pose.getAngularVelocity(); } if (_ignoreIK && pose.isValid()) { // this position/rotation should be the same as the one in scripts/system/libraries/controllers.js // otherwise things will do a little hop when you grab them. // if (isRightHand) { // pose = myAvatar->getRightHandControllerPoseInAvatarFrame(); // } else { // pose = myAvatar->getLeftHandControllerPoseInAvatarFrame(); // } // glm::vec3 camRelPos = pose.getTranslation(); // glm::quat camRelRot = pose.getRotation(); int camRelIndex = isRightHand ? CAMERA_RELATIVE_CONTROLLER_RIGHTHAND_INDEX : CAMERA_RELATIVE_CONTROLLER_LEFTHAND_INDEX; glm::vec3 camRelPos = myAvatar->getAbsoluteJointTranslationInObjectFrame(camRelIndex); glm::quat camRelRot = myAvatar->getAbsoluteJointRotationInObjectFrame(camRelIndex); Transform avatarTransform; avatarTransform = myAvatar->getTransform(); palmPosition = avatarTransform.transform(camRelPos); palmRotation = avatarTransform.getRotation() * camRelRot; } else { glm::vec3 avatarRigidBodyPosition; glm::quat avatarRigidBodyRotation; getAvatarRigidBodyLocation(avatarRigidBodyPosition, avatarRigidBodyRotation); // the offset and rotation between the avatar's rigid body and the palm were determined earlier // in prepareForPhysicsSimulation. At this point, the avatar's rigid body has been moved by bullet // and the data in the Avatar class is stale. This means that the result of get*PalmPosition will // be stale. Instead, determine the current palm position with the current avatar's rigid body // location and the saved offsets. // this line is more correct but breaks for the current way avatar data is updated. // palmPosition = avatarRigidBodyPosition + avatarRigidBodyRotation * _palmOffsetFromRigidBody; // instead, use this for now: palmPosition = avatarRigidBodyPosition + _palmOffsetFromRigidBody; // the item jitters the least by getting the rotation based on the opinion of Avatar.h rather // than that of the rigid body. leaving this next line here for future reference: // palmRotation = avatarRigidBodyRotation * _palmRotationFromRigidBody; if (isRightHand) { palmRotation = holdingAvatar->getRightPalmRotation(); } else { palmRotation = holdingAvatar->getLeftPalmRotation(); } } } else { // regular avatar if (isRightHand) { Transform controllerRightTransform = Transform(holdingAvatar->getControllerRightHandMatrix()); Transform avatarTransform = holdingAvatar->getTransform(); palmRotation = avatarTransform.getRotation() * controllerRightTransform.getRotation(); palmPosition = avatarTransform.getTranslation() + (avatarTransform.getRotation() * controllerRightTransform.getTranslation()); } else { Transform controllerLeftTransform = Transform(holdingAvatar->getControllerLeftHandMatrix()); Transform avatarTransform = holdingAvatar->getTransform(); palmRotation = avatarTransform.getRotation() * controllerLeftTransform.getRotation(); palmPosition = avatarTransform.getTranslation() + (avatarTransform.getRotation() * controllerLeftTransform.getTranslation()); } } rotation = palmRotation * _relativeRotation; position = palmPosition + rotation * _relativePosition; // update linearVelocity based on offset via _relativePosition; linearVelocity = linearVelocity + glm::cross(angularVelocity, position - palmPosition); linearTimeScale = _linearTimeScale; angularTimeScale = _angularTimeScale; }); return true; }
bool AvatarActionHold::getTarget(float deltaTimeStep, glm::quat& rotation, glm::vec3& position, glm::vec3& linearVelocity, glm::vec3& angularVelocity) { auto avatarManager = DependencyManager::get<AvatarManager>(); auto holdingAvatar = std::static_pointer_cast<Avatar>(avatarManager->getAvatarBySessionID(_holderID)); if (!holdingAvatar) { return false;; } withReadLock([&]{ bool isRightHand = (_hand == "right"); glm::vec3 palmPosition; glm::quat palmRotation; if (holdingAvatar->isMyAvatar()) { // fetch the hand controller pose controller::Pose pose; if (isRightHand) { pose = avatarManager->getMyAvatar()->getRightHandControllerPoseInWorldFrame(); } else { pose = avatarManager->getMyAvatar()->getLeftHandControllerPoseInWorldFrame(); } if (pose.isValid()) { linearVelocity = pose.getVelocity(); angularVelocity = pose.getAngularVelocity(); if (isRightHand) { pose = avatarManager->getMyAvatar()->getRightHandControllerPoseInAvatarFrame(); } else { pose = avatarManager->getMyAvatar()->getLeftHandControllerPoseInAvatarFrame(); } } if (_ignoreIK && pose.isValid()) { Transform avatarTransform; auto myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar(); avatarTransform = myAvatar->getTransform(); palmPosition = avatarTransform.transform(pose.getTranslation() / myAvatar->getTargetScale()); palmRotation = avatarTransform.getRotation() * pose.getRotation(); } else { glm::vec3 avatarRigidBodyPosition; glm::quat avatarRigidBodyRotation; getAvatarRigidBodyLocation(avatarRigidBodyPosition, avatarRigidBodyRotation); // the offset and rotation between the avatar's rigid body and the palm were determined earlier // in prepareForPhysicsSimulation. At this point, the avatar's rigid body has been moved by bullet // and the data in the Avatar class is stale. This means that the result of get*PalmPosition will // be stale. Instead, determine the current palm position with the current avatar's rigid body // location and the saved offsets. // this line is more correct but breaks for the current way avatar data is updated. // palmPosition = avatarRigidBodyPosition + avatarRigidBodyRotation * _palmOffsetFromRigidBody; // instead, use this for now: palmPosition = avatarRigidBodyPosition + _palmOffsetFromRigidBody; // the item jitters the least by getting the rotation based on the opinion of Avatar.h rather // than that of the rigid body. leaving this next line here for future reference: // palmRotation = avatarRigidBodyRotation * _palmRotationFromRigidBody; if (isRightHand) { palmRotation = holdingAvatar->getRightPalmRotation(); } else { palmRotation = holdingAvatar->getLeftPalmRotation(); } } } else { // regular avatar if (isRightHand) { Transform controllerRightTransform = Transform(holdingAvatar->getControllerRightHandMatrix()); Transform avatarTransform = holdingAvatar->getTransform(); palmRotation = avatarTransform.getRotation() * controllerRightTransform.getRotation(); palmPosition = avatarTransform.getTranslation() + (avatarTransform.getRotation() * controllerRightTransform.getTranslation()); } else { Transform controllerLeftTransform = Transform(holdingAvatar->getControllerLeftHandMatrix()); Transform avatarTransform = holdingAvatar->getTransform(); palmRotation = avatarTransform.getRotation() * controllerLeftTransform.getRotation(); palmPosition = avatarTransform.getTranslation() + (avatarTransform.getRotation() * controllerLeftTransform.getTranslation()); } } rotation = palmRotation * _relativeRotation; position = palmPosition + rotation * _relativePosition; // update linearVelocity based on offset via _relativePosition; linearVelocity = linearVelocity + glm::cross(angularVelocity, position - palmPosition); }); return true; }