diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index bcf5192bed..bab57044df 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,19 @@ 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. +// goToWalkingStateOut: (out) true if setIsInWalkingState(true) should be called if this function returns true. +bool MyAvatar::FollowHelper::shouldActivateHorizontal_userStanding( + const MyAvatar& myAvatar, + bool& resetModeOut, + bool& goToWalkingStateOut) const { if (myAvatar.getIsInWalkingState()) { return true; } - controller::Pose currentHeadPose = myAvatar.getControllerPoseInAvatarFrame(controller::Action::HEAD); + controller::Pose currentHeadPose = myAvatar.getControllerPoseInAvatarFrame(controller::Action::HEAD); bool stepDetected = false; if (!withinBaseOfSupport(currentHeadPose)) { @@ -5749,21 +5757,36 @@ bool MyAvatar::FollowHelper::shouldActivateHorizontalCG(MyAvatar& myAvatar) cons glm::vec3 currentHeadPosition = currentHeadPose.getTranslation(); 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); + (glm::length(currentHeadPosition - defaultHipsPosition) > + (anatomicalHeadToHipsDistance + (DEFAULT_AVATAR_SPINE_STRETCH_LIMIT * anatomicalHeadToHipsDistance)))) { + resetModeOut = true; stepDetected = true; - } - } - - if (stepDetected) { - if (glm::length(currentHeadPose.velocity) > DEFAULT_AVATAR_WALK_SPEED_THRESHOLD) { - myAvatar.setIsInWalkingState(true); + if (currentHeadPose.isValid()) { + if (glm::length(currentHeadPose.velocity) > DEFAULT_AVATAR_WALK_SPEED_THRESHOLD) { + goToWalkingStateOut = true; + } + } } } return stepDetected; } +// Determine if the horizontal following should activate. +// resetModeOut: (out) true if setResetMode(true) should be called if this function returns true. +// goToWalkingStateOut: (out) true if setIsInWalkingState(true) should be called if this function returns true. +bool MyAvatar::FollowHelper::shouldActivateHorizontal(const MyAvatar& myAvatar, + const glm::mat4& desiredBodyMatrix, + const glm::mat4& currentBodyMatrix, + bool& resetModeOut, + bool& goToWalkingStateOut) const { + if (myAvatar.getIsInSittingState()) { + return shouldActivateHorizontal_userSitting(myAvatar, desiredBodyMatrix, currentBodyMatrix); + } else { + return shouldActivateHorizontal_userStanding(myAvatar, resetModeOut, goToWalkingStateOut); + } +} + bool MyAvatar::FollowHelper::shouldActivateVertical(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const { @@ -5807,7 +5830,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,23 +5838,32 @@ 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; + bool goToWalkingStateOut = false; + + // 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, + goToWalkingStateOut) || + 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 (goToWalkingStateOut) { + myAvatar.setIsInWalkingState(true); } } } diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index a2a02fa7f8..a411b1d747 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, + bool& goToWalkingStateOut) 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, + bool& goToWalkingStateOut) const; }; FollowHelper _follow;