diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 979dc99453..60b6171fa7 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2402,6 +2402,10 @@ void Application::updateMouseRay() { } } +// Called during Application::update immediately before AvatarManager::updateMyAvatar, updating my data that is then sent to everyone. +// (Maybe this code should be moved there?) +// The principal result is to call updateLookAtTargetAvatar() and then setLookAtPosition(). +// Note that it is called BEFORE we update position or joints based on sensors, etc. void Application::updateMyAvatarLookAtPosition() { PerformanceTimer perfTimer("lookAt"); bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp index cec9079443..9ab2c83a79 100644 --- a/interface/src/avatar/Head.cpp +++ b/interface/src/avatar/Head.cpp @@ -344,6 +344,20 @@ glm::quat Head::getFinalOrientationInLocalFrame() const { return glm::quat(glm::radians(glm::vec3(getFinalPitch(), getFinalYaw(), getFinalRoll() ))); } +// Everyone else's head keeps track of a lookAtPosition that everybody sees the same, and refers to where that head +// is looking in model space -- e.g., at someone's eyeball, or between their eyes, or mouth, etc. Everyon's Interface +// will have the same value for the lookAtPosition of any given head. +// +// Everyone else's head also keeps track of a correctedLookAtPosition that may be different for the same head within +// different Interfaces. If that head is not looking at me, the correctedLookAtPosition is the same as the lookAtPosition. +// However, if that head is looking at me, then I will attempt to adjust the lookAtPosition by the difference between +// my (singular) eye position and my actual camera position. This adjustment is used on their eyeballs during rendering +// (and also on any lookAt vector display for that head, during rendering). Note that: +// 1. this adjustment can be made directly to the other head's eyeball joints, because we won't be send their joint information to others. +// 2. the corrected position is a separate ivar, so the common/uncorrected value is still available +// +// There is a pun here: The two lookAtPositions will always be the same for my own avatar in my own Interface, because I +// will not be looking at myself. (Even in a mirror, I will be looking at the camera.) glm::vec3 Head::getCorrectedLookAtPosition() { if (isLookingAtMe()) { return _correctedLookAtPosition; @@ -364,7 +378,7 @@ void Head::setCorrectedLookAtPosition(glm::vec3 correctedLookAtPosition) { bool Head::isLookingAtMe() { // Allow for outages such as may be encountered during avatar movement quint64 now = usecTimestampNow(); - const quint64 LOOKING_AT_ME_GAP_ALLOWED = 1000000; // microseconds + const quint64 LOOKING_AT_ME_GAP_ALLOWED = (5 * 1000 * 1000) / 60; // n frames, in microseconds return _isLookingAtMe || (now - _wasLastLookingAtMe) < LOOKING_AT_ME_GAP_ALLOWED; } diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index e870ba2140..d58cd8d7c4 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -97,7 +97,7 @@ void SkeletonModel::initJointStates(QVector states) { } const float PALM_PRIORITY = DEFAULT_PRIORITY; - +// Called within Model::simulate call, below. void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) { if (_owningAvatar->isMyAvatar()) { _rig->computeMotionAnimationState(deltaTime, _owningAvatar->getPosition(), _owningAvatar->getVelocity(), _owningAvatar->getOrientation()); @@ -105,26 +105,43 @@ void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) { Model::updateRig(deltaTime, parentTransform); if (_owningAvatar->isMyAvatar()) { const FBXGeometry& geometry = _geometry->getFBXGeometry(); + Head* head = _owningAvatar->getHead(); Rig::HeadParameters params; params.modelRotation = getRotation(); params.modelTranslation = getTranslation(); - params.leanSideways = _owningAvatar->getHead()->getFinalLeanSideways(); - params.leanForward = _owningAvatar->getHead()->getFinalLeanForward(); - params.torsoTwist = _owningAvatar->getHead()->getTorsoTwist(); - params.localHeadOrientation = _owningAvatar->getHead()->getFinalOrientationInLocalFrame(); - params.worldHeadOrientation = _owningAvatar->getHead()->getFinalOrientationInWorldFrame(); - params.eyeLookAt = _owningAvatar->getHead()->getLookAtPosition(); - params.eyeSaccade = _owningAvatar->getHead()->getSaccade(); + params.leanSideways = head->getFinalLeanSideways(); + params.leanForward = head->getFinalLeanForward(); + params.torsoTwist = head->getTorsoTwist(); + params.localHeadOrientation = head->getFinalOrientationInLocalFrame(); + params.worldHeadOrientation = head->getFinalOrientationInWorldFrame(); + params.eyeLookAt = head->getLookAtPosition(); + params.eyeSaccade = head->getSaccade(); params.leanJointIndex = geometry.leanJointIndex; params.neckJointIndex = geometry.neckJointIndex; params.leftEyeJointIndex = geometry.leftEyeJointIndex; params.rightEyeJointIndex = geometry.rightEyeJointIndex; _rig->updateFromHeadParameters(params); + } else { + // This is a little more work than we really want. + // + // Other avatars joint, including their eyes, should already be set just like any other joints + // from the wire data. But when looking at me, we want the eyes to use the corrected lookAt. + // + // Thus this should really only be ... else if (_owningAvatar->getHead()->isLookingAtMe()) {... + // However, in the !isLookingAtMe case, the eyes aren't rotating the way they should right now. + // (They latch their looking at me position.) We will revisit that as priorities allow. + const FBXGeometry& geometry = _geometry->getFBXGeometry(); + Head* head = _owningAvatar->getHead(); + _rig->updateEyeJoints(geometry.leftEyeJointIndex, geometry.rightEyeJointIndex, + getTranslation(), getRotation(), + head->getFinalOrientationInWorldFrame(), head->getCorrectedLookAtPosition()); } } +// Called by Avatar::simulate after it has set the joint states (fullUpdate true if changed), +// but just before head has been simulated. void SkeletonModel::simulate(float deltaTime, bool fullUpdate) { setTranslation(_owningAvatar->getSkeletonPosition()); static const glm::quat refOrientation = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)); diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index 1a8bd0bbad..2212e06e31 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -786,8 +786,8 @@ glm::quat Rig::getJointDefaultRotationInParentFrame(int jointIndex) { void Rig::updateFromHeadParameters(const HeadParameters& params) { updateLeanJoint(params.leanJointIndex, params.leanSideways, params.leanForward, params.torsoTwist); updateNeckJoint(params.neckJointIndex, params.localHeadOrientation, params.leanSideways, params.leanForward, params.torsoTwist); - updateEyeJoint(params.leftEyeJointIndex, params.modelTranslation, params.modelRotation, params.worldHeadOrientation, params.eyeLookAt, params.eyeSaccade); - updateEyeJoint(params.rightEyeJointIndex, params.modelTranslation, params.modelRotation, params.worldHeadOrientation, params.eyeLookAt, params.eyeSaccade); + updateEyeJoints(params.leftEyeJointIndex, params.rightEyeJointIndex, params.modelTranslation, params.modelRotation, + params.worldHeadOrientation, params.eyeLookAt, params.eyeSaccade); } void Rig::updateLeanJoint(int index, float leanSideways, float leanForward, float torsoTwist) { @@ -828,6 +828,11 @@ void Rig::updateNeckJoint(int index, const glm::quat& localHeadOrientation, floa } } +void Rig::updateEyeJoints(int leftEyeIndex, int rightEyeIndex, const glm::vec3& modelTranslation, const glm::quat& modelRotation, + const glm::quat& worldHeadOrientation, const glm::vec3& lookAtSpot, const glm::vec3& saccade) { + updateEyeJoint(leftEyeIndex, modelTranslation, modelRotation, worldHeadOrientation, lookAtSpot, saccade); + updateEyeJoint(rightEyeIndex, modelTranslation, modelRotation, worldHeadOrientation, lookAtSpot, saccade); +} void Rig::updateEyeJoint(int index, const glm::vec3& modelTranslation, const glm::quat& modelRotation, const glm::quat& worldHeadOrientation, const glm::vec3& lookAtSpot, const glm::vec3& saccade) { if (index >= 0 && _jointStates[index].getParentIndex() >= 0) { auto& state = _jointStates[index]; diff --git a/libraries/animation/src/Rig.h b/libraries/animation/src/Rig.h index face79bc15..8da20062cf 100644 --- a/libraries/animation/src/Rig.h +++ b/libraries/animation/src/Rig.h @@ -157,6 +157,8 @@ public: void setEnableRig(bool isEnabled) { _enableRig = isEnabled; } void updateFromHeadParameters(const HeadParameters& params); + void updateEyeJoints(int leftEyeIndex, int rightEyeIndex, const glm::vec3& modelTranslation, const glm::quat& modelRotation, + const glm::quat& worldHeadOrientation, const glm::vec3& lookAtSpot, const glm::vec3& saccade = glm::vec3(0.0f)); virtual void setHandPosition(int jointIndex, const glm::vec3& position, const glm::quat& rotation, float scale, float priority) = 0;