Decouple MyAvatar.centerOfGravityModelEnabled from the user standing state.

Engine code no longer controls MyAvatar.centerOfGravityModelEnabled.  Maybe we should deprecate it now, since its reason to exist seemed to be only to disable the CG model while the user was sitting, which is now done more explicitly (see below).

MyAvatar::FollowHelper:
- rename shouldActivateHorizontal to shouldActivateHorizontal_userSitting, now private.
- rename shouldActivateHorizontalCG to shouldActivateHorizontal_userStanding, now private.
- add new shouldActivateHorizontal that calls one of the above based on the user's sit/stand state.
- these functions no longer modify their 'myAvatar' parameter.

Add USER_CAN_TURN_BODY_WHILE_SITTING (false), which retains the old rotation behaviour of lean recentering:
a lean recenter doesn't rotate the body if the user is sitting (new: unless the feet are tracked).
In other words, the lean recentering assumes the user isn't on a swivel chair and keeps the avatar pointing in the same direction.  It might be good to expose that as an option.  (Regardless, rotation recentering does kick-in if they turn too far).
This commit is contained in:
Phil Palmer 2020-12-30 22:38:31 -05:00
parent a95d29d327
commit c5fe49bc30
2 changed files with 76 additions and 33 deletions

View file

@ -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);
}
}
}

View file

@ -1634,7 +1634,7 @@ public:
* @function MyAvatar.getAvatarScale
* @returns {number} The target scale for the avatar, range <code>0.005</code> &ndash; <code>1000.0</code>.
*/
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<bool> _forceActivateVertical { false };
std::atomic<bool> _forceActivateHorizontal { false };
std::atomic<bool> _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;