AvatarManager::AvatarManager(QObject* parent) : _myAvatar(new MyAvatar(qApp->thread()), [](MyAvatar* ptr) { ptr->deleteLater(); }) { // register a meta type for the weak pointer we'll use for the owning avatar mixer for each avatar qRegisterMetaType<QWeakPointer<Node> >("NodeWeakPointer"); auto nodeList = DependencyManager::get<NodeList>(); // when we hear that the user has ignored an avatar by session UUID // immediately remove that avatar instead of waiting for the absence of packets from avatar mixer connect(nodeList.data(), &NodeList::ignoredNode, this, [this](const QUuid& nodeID, bool enabled) { if (enabled) { removeAvatar(nodeID, KillAvatarReason::AvatarIgnored); } else { auto avatar = std::static_pointer_cast<Avatar>(getAvatarBySessionID(nodeID)); if (avatar) { avatar->createOrb(); } } }); _transitConfig._totalFrames = AVATAR_TRANSIT_FRAME_COUNT; _transitConfig._minTriggerDistance = AVATAR_TRANSIT_MIN_TRIGGER_DISTANCE; _transitConfig._maxTriggerDistance = AVATAR_TRANSIT_MAX_TRIGGER_DISTANCE; _transitConfig._framesPerMeter = AVATAR_TRANSIT_FRAMES_PER_METER; _transitConfig._isDistanceBased = AVATAR_TRANSIT_DISTANCE_BASED; _transitConfig._abortDistance = AVATAR_TRANSIT_ABORT_DISTANCE; }
void AvatarManager::removeDeadAvatarEntities(const SetOfEntities& deadEntities) { auto treeRenderer = DependencyManager::get<EntityTreeRenderer>(); EntityTreePointer entityTree = treeRenderer ? treeRenderer->getTree() : nullptr; for (auto entity : deadEntities) { QUuid entityOwnerID = entity->getOwningAvatarID(); AvatarSharedPointer avatar = getAvatarBySessionID(entityOwnerID); const bool REQUIRES_REMOVAL_FROM_TREE = false; if (avatar) { avatar->clearAvatarEntity(entity->getID(), REQUIRES_REMOVAL_FROM_TREE); } if (entityTree && entity->isMyAvatarEntity()) { entityTree->withWriteLock([&] { // We only need to delete the direct children (rather than the descendants) because // when the child is deleted, it will take care of its own children. If the child // is also an avatar-entity, we'll end up back here. If it's not, the entity-server // will take care of it in the usual way. entity->forEachChild([&](SpatiallyNestablePointer child) { EntityItemPointer childEntity = std::dynamic_pointer_cast<EntityItem>(child); if (childEntity) { entityTree->deleteEntity(childEntity->getID(), true, true); if (avatar) { avatar->clearAvatarEntity(childEntity->getID(), REQUIRES_REMOVAL_FROM_TREE); } } }); }); } } }
void AvatarManager::removeDeadAvatarEntities(const SetOfEntities& deadEntities) { for (auto entity : deadEntities) { QUuid sessionID = entity->getOwningAvatarID(); AvatarSharedPointer avatar = getAvatarBySessionID(sessionID); if (avatar) { const bool REQUIRES_REMOVAL_FROM_TREE = false; avatar->clearAvatarEntity(entity->getID(), REQUIRES_REMOVAL_FROM_TREE); } } }
void AvatarActionHold::prepareForPhysicsSimulation() { auto avatarManager = DependencyManager::get<AvatarManager>(); auto holdingAvatar = std::static_pointer_cast<Avatar>(avatarManager->getAvatarBySessionID(_holderID)); if (!holdingAvatar || !holdingAvatar->isMyAvatar()) { return; } withWriteLock([&]{ glm::vec3 avatarRigidBodyPosition; glm::quat avatarRigidBodyRotation; getAvatarRigidBodyLocation(avatarRigidBodyPosition, avatarRigidBodyRotation); if (_ignoreIK) { return; } glm::vec3 palmPosition; glm::quat palmRotation; if (_hand == "right") { palmPosition = holdingAvatar->getUncachedRightPalmPosition(); palmRotation = holdingAvatar->getUncachedRightPalmRotation(); } else { palmPosition = holdingAvatar->getUncachedLeftPalmPosition(); palmRotation = holdingAvatar->getUncachedLeftPalmRotation(); } // determine the difference in translation and rotation between the avatar's // rigid body and the palm position. The avatar's rigid body will be moved by bullet // between this call and the call to getTarget, below. A call to get*PalmPosition in // getTarget would get the palm position of the previous location of the avatar (because // bullet has moved the av's rigid body but the rigid body's location has not yet been // copied out into the Avatar class. //glm::quat avatarRotationInverse = glm::inverse(avatarRigidBodyRotation); // the offset should be in the frame of the avatar, but something about the order // things are updated makes this wrong: // _palmOffsetFromRigidBody = avatarRotationInverse * (palmPosition - avatarRigidBodyPosition); // I'll leave it here as a comment in case avatar handling changes. _palmOffsetFromRigidBody = palmPosition - avatarRigidBodyPosition; // rotation should also be needed, but again, the order of updates makes this unneeded. leaving // code here for future reference. // _palmRotationFromRigidBody = avatarRotationInverse * palmRotation; }); activateBody(true); }
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; }
float AvatarManager::getAvatarSimulationRate(const QUuid& sessionID, const QString& rateName) const { auto avatar = std::static_pointer_cast<Avatar>(getAvatarBySessionID(sessionID)); return avatar ? avatar->getSimulationRate(rateName) : 0.0f; }
float AvatarManager::getAvatarUpdateRate(const QUuid& sessionID, const QString& rateName) const { auto avatar = getAvatarBySessionID(sessionID); return avatar ? avatar->getUpdateRate(rateName) : 0.0f; }
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; }