diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index bcf5192bed..fc2394cfc0 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -4619,7 +4619,7 @@ bool MyAvatar::getFlyingHMDPref() { } // Public interface for targetscale -float MyAvatar::getAvatarScale() { +float MyAvatar::getAvatarScale() const { return getTargetScale(); } @@ -5341,7 +5341,6 @@ void MyAvatar::setIsInSittingState(bool isSitting) { // on reset height we need the count to be more than one in case the user sits and stands up quickly. _isInSittingState.set(isSitting); setResetMode(true); - setCenterOfGravityModelEnabled(!isSitting); setSitStandStateChange(true); } @@ -5679,7 +5678,10 @@ bool MyAvatar::FollowHelper::shouldActivateRotation(const MyAvatar& myAvatar, return glm::dot(-myAvatar.getHeadControllerFacingMovingAverage(), bodyFacing) < FOLLOW_ROTATION_THRESHOLD; } -bool MyAvatar::FollowHelper::shouldActivateHorizontal(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const { +// Determine if the horizontal following should activate, for a user who is sitting in the real world. +bool MyAvatar::FollowHelper::shouldActivateHorizontal_userSitting(const MyAvatar& myAvatar, + const glm::mat4& desiredBodyMatrix, + const glm::mat4& currentBodyMatrix) const { if (!myAvatar.isAllowedToLean()) { controller::Pose currentHeadPose = myAvatar.getControllerPoseInAvatarFrame(controller::Action::HEAD); if (!withinBaseOfSupport(currentHeadPose)) { @@ -5711,13 +5713,21 @@ bool MyAvatar::FollowHelper::shouldActivateHorizontal(const MyAvatar& myAvatar, return stepDetected; } -bool MyAvatar::FollowHelper::shouldActivateHorizontalCG(MyAvatar& myAvatar) const { +// Determine if the horizontal following should activate, for a user who is standing in the real world. +// resetModeOut: (out) true if setResetMode(true) should be called if this function returns true. +// currentHeadPoseForWalkingStateOut: (out) the head pose, in the avatar frame, +// that can be tested in order to trigger walking state if this function returns true. +bool MyAvatar::FollowHelper::shouldActivateHorizontal_userStanding( + const MyAvatar& myAvatar, + bool& resetModeOut, + controller::Pose& currentHeadPoseForWalkingStateOut) const { if (myAvatar.getIsInWalkingState()) { return true; } - controller::Pose currentHeadPose = myAvatar.getControllerPoseInAvatarFrame(controller::Action::HEAD); + currentHeadPoseForWalkingStateOut = myAvatar.getControllerPoseInAvatarFrame(controller::Action::HEAD); + controller::Pose& currentHeadPose = currentHeadPoseForWalkingStateOut; bool stepDetected = false; if (!withinBaseOfSupport(currentHeadPose)) { @@ -5750,20 +5760,30 @@ bool MyAvatar::FollowHelper::shouldActivateHorizontalCG(MyAvatar& myAvatar) cons float anatomicalHeadToHipsDistance = glm::length(defaultHeadPosition - defaultHipsPosition); if (!isActive(CharacterController::FollowType::Horizontal) && (!isActive(CharacterController::FollowType::Vertical)) && (glm::length(currentHeadPosition - defaultHipsPosition) > (anatomicalHeadToHipsDistance + (DEFAULT_AVATAR_SPINE_STRETCH_LIMIT * anatomicalHeadToHipsDistance)))) { - myAvatar.setResetMode(true); + resetModeOut = true; stepDetected = true; } } - if (stepDetected) { - if (glm::length(currentHeadPose.velocity) > DEFAULT_AVATAR_WALK_SPEED_THRESHOLD) { - myAvatar.setIsInWalkingState(true); - } - } - return stepDetected; } +// Determine if the horizontal following should activate. +// resetModeOut: (out) true if setResetMode(true) should be called if this function returns true. +// currentHeadPoseForWalkingStateOut: (out) the head pose, in the avatar frame, +// that can be tested in order to trigger walking state if this function returns true. +bool MyAvatar::FollowHelper::shouldActivateHorizontal(const MyAvatar& myAvatar, + const glm::mat4& desiredBodyMatrix, + const glm::mat4& currentBodyMatrix, + bool& resetModeOut, + controller::Pose& currentHeadPoseForWalkingStateOut) const { + if (myAvatar.getIsInSittingState()) { + return shouldActivateHorizontal_userSitting(myAvatar, desiredBodyMatrix, currentBodyMatrix); + } else { + return shouldActivateHorizontal_userStanding(myAvatar, resetModeOut, currentHeadPoseForWalkingStateOut); + } +} + bool MyAvatar::FollowHelper::shouldActivateVertical(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const { @@ -5807,7 +5827,7 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, } } - // Horizontal and rotation recenter + // Lean recenter if ((myAvatar.areFeetTracked() || getForceActivateHorizontal()) && !isActive(CharacterController::FollowType::Horizontal)) { activate(CharacterController::FollowType::Horizontal, myAvatar.areFeetTracked()); @@ -5815,22 +5835,33 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, } else { if ((myAvatar.getAllowAvatarLeaningPreference() != MyAvatar::AllowAvatarLeaningPreference::AlwaysNoRecenter) && qApp->getCamera().getMode() != CAMERA_MODE_MIRROR) { - if (myAvatar.getCenterOfGravityModelEnabled()) { - if (!isActive(CharacterController::FollowType::Horizontal) && (shouldActivateHorizontalCG(myAvatar) || hasDriveInput)) { - activate(CharacterController::FollowType::Horizontal, false); - if (myAvatar.getEnableStepResetRotation()) { - activate(CharacterController::FollowType::Rotation, false); - myAvatar.setHeadControllerFacingMovingAverage(myAvatar.getHeadControllerFacing()); - } + + bool resetModeOut = false; + controller::Pose currentHeadPoseForWalkingStateOut; + + // True if the user can turn their body while sitting (eg. swivel chair). + // Todo?: We could expose this as an option. + // (Regardless, rotation recentering does kick-in if they turn too far). + constexpr bool USER_CAN_TURN_BODY_WHILE_SITTING = false; + + if (!isActive(CharacterController::FollowType::Horizontal) && + (shouldActivateHorizontal(myAvatar, desiredBodyMatrix, currentBodyMatrix, + resetModeOut, currentHeadPoseForWalkingStateOut) || + hasDriveInput)) { + activate(CharacterController::FollowType::Horizontal, false); + if (myAvatar.getEnableStepResetRotation() && + (USER_CAN_TURN_BODY_WHILE_SITTING || !myAvatar.getIsInSittingState())) { + activate(CharacterController::FollowType::Rotation, false); + myAvatar.setHeadControllerFacingMovingAverage(myAvatar.getHeadControllerFacing()); } - } else { - // center of gravity model is not enabled - if (!isActive(CharacterController::FollowType::Horizontal) && - (shouldActivateHorizontal(myAvatar, desiredBodyMatrix, currentBodyMatrix) || hasDriveInput)) { - activate(CharacterController::FollowType::Horizontal, false); - if (myAvatar.getEnableStepResetRotation() && !myAvatar.getIsInSittingState()) { - activate(CharacterController::FollowType::Rotation, false); - myAvatar.setHeadControllerFacingMovingAverage(myAvatar.getHeadControllerFacing()); + + if (resetModeOut) { + myAvatar.setResetMode(true); + } + + if (currentHeadPoseForWalkingStateOut.isValid()) { + if (glm::length(currentHeadPoseForWalkingStateOut.velocity) > DEFAULT_AVATAR_WALK_SPEED_THRESHOLD) { + myAvatar.setIsInWalkingState(true); } } } diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index a2a02fa7f8..cde10619ff 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -1634,7 +1634,7 @@ public: * @function MyAvatar.getAvatarScale * @returns {number} The target scale for the avatar, range 0.0051000.0. */ - Q_INVOKABLE float getAvatarScale(); + Q_INVOKABLE float getAvatarScale() const; /**jsdoc * Sets the target scale of the avatar. The target scale is the desired scale of the avatar without any restrictions on @@ -2908,8 +2908,11 @@ private: void decrementTimeRemaining(float dt); bool shouldActivateRotation(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix, bool& shouldSnapOut) const; bool shouldActivateVertical(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const; - bool shouldActivateHorizontal(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const; - bool shouldActivateHorizontalCG(MyAvatar& myAvatar) const; + bool shouldActivateHorizontal(const MyAvatar& myAvatar, + const glm::mat4& desiredBodyMatrix, + const glm::mat4& currentBodyMatrix, + bool& resetModeOut, + controller::Pose& currentHeadPoseForWalkingStateOut) const; void prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat4& bodySensorMatrix, const glm::mat4& currentBodyMatrix, bool hasDriveInput); glm::mat4 postPhysicsUpdate(MyAvatar& myAvatar, const glm::mat4& currentBodyMatrix); bool getForceActivateRotation() const; @@ -2924,6 +2927,14 @@ private: std::atomic _forceActivateVertical { false }; std::atomic _forceActivateHorizontal { false }; std::atomic _toggleHipsFollowing { true }; + + private: + bool shouldActivateHorizontal_userSitting(const MyAvatar& myAvatar, + const glm::mat4& desiredBodyMatrix, + const glm::mat4& currentBodyMatrix) const; + bool shouldActivateHorizontal_userStanding(const MyAvatar& myAvatar, + bool& resetModeOut, + controller::Pose& currentHeadPoseForWalkingStateOut) const; }; FollowHelper _follow;