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.005
– 1000.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;