From ff0d938d3793e80d9e5c699115981ea96af453ba Mon Sep 17 00:00:00 2001 From: amantley Date: Mon, 17 Sep 2018 16:53:15 -0700 Subject: [PATCH 01/54] initial changes to stop the squatty potty from happening when users are sitting down in vr mode --- interface/resources/qml/AnimStats.qml | 2 +- interface/src/avatar/MyAvatar.cpp | 84 +++++++++++++++++++++--- interface/src/avatar/MyAvatar.h | 6 +- interface/src/avatar/MySkeletonModel.cpp | 2 +- 4 files changed, 81 insertions(+), 13 deletions(-) diff --git a/interface/resources/qml/AnimStats.qml b/interface/resources/qml/AnimStats.qml index 35ed3799a6..fd0a280dad 100644 --- a/interface/resources/qml/AnimStats.qml +++ b/interface/resources/qml/AnimStats.qml @@ -53,7 +53,7 @@ Item { ListView { width: firstCol.width height: root.animStateMachines.length * 15 - visible: root.animStateMchines.length > 0; + visible: root.animStateMachines.length > 0; model: root.animStateMachines delegate: StatText { text: { diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index c47cfdb383..b626fb6c2a 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -3589,9 +3589,11 @@ glm::vec3 MyAvatar::computeCounterBalance() { // if the height is higher than default hips, clamp to default hips counterBalancedCg.y = tposeHips.y + 0.05f; } else if (counterBalancedCg.y < sitSquatThreshold) { - //do a height reset + // do a height reset setResetMode(true); _follow.activate(FollowHelper::Vertical); + // disable cg behaviour in this case. + _isInSittingState = true; } return counterBalancedCg; } @@ -3832,6 +3834,10 @@ bool MyAvatar::getIsInWalkingState() const { return _isInWalkingState; } +bool MyAvatar::getIsInSittingState() const { + return _isInSittingState; +} + float MyAvatar::getWalkSpeed() const { return _walkSpeed.get() * _walkSpeedScalar; } @@ -3852,6 +3858,10 @@ void MyAvatar::setIsInWalkingState(bool isWalking) { _isInWalkingState = isWalking; } +void MyAvatar::setIsInSittingState(bool isSitting) { + _isInSittingState = isSitting; +} + void MyAvatar::setWalkSpeed(float value) { _walkSpeed.set(value); } @@ -4029,6 +4039,33 @@ bool MyAvatar::FollowHelper::shouldActivateHorizontal(const MyAvatar& myAvatar, return fabs(lateralLeanAmount) > MAX_LATERAL_LEAN; } +bool MyAvatar::FollowHelper::shouldActivateHorizontalSitting(MyAvatar& myAvatar) const { + + // get the current readings + controller::Pose currentHeadPose = myAvatar.getControllerPoseInAvatarFrame(controller::Action::HEAD); + controller::Pose currentLeftHandPose = myAvatar.getControllerPoseInAvatarFrame(controller::Action::LEFT_HAND); + controller::Pose currentRightHandPose = myAvatar.getControllerPoseInAvatarFrame(controller::Action::RIGHT_HAND); + + bool stepDetected = false; + float myScale = myAvatar.getAvatarScale(); + + if (!withinBaseOfSupport(currentHeadPose)) { + // a step is detected + stepDetected = true; + } else { + glm::vec3 defaultHipsPosition = myAvatar.getAbsoluteDefaultJointTranslationInObjectFrame(myAvatar.getJointIndex("Hips")); + glm::vec3 defaultHeadPosition = myAvatar.getAbsoluteDefaultJointTranslationInObjectFrame(myAvatar.getJointIndex("Head")); + glm::vec3 currentHeadPosition = currentHeadPose.getTranslation(); + float anatomicalHeadToHipsDistance = glm::length(defaultHeadPosition - defaultHipsPosition); + if (!isActive(Horizontal) && + (glm::length(currentHeadPosition - defaultHipsPosition) > (anatomicalHeadToHipsDistance + (DEFAULT_AVATAR_SPINE_STRETCH_LIMIT * anatomicalHeadToHipsDistance)))) { + myAvatar.setResetMode(true); + stepDetected = true; + } + } + return stepDetected; +} + bool MyAvatar::FollowHelper::shouldActivateHorizontalCG(MyAvatar& myAvatar) const { // get the current readings @@ -4072,33 +4109,60 @@ bool MyAvatar::FollowHelper::shouldActivateHorizontalCG(MyAvatar& myAvatar) cons return stepDetected; } -bool MyAvatar::FollowHelper::shouldActivateVertical(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const { +bool MyAvatar::FollowHelper::shouldActivateVertical(MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const { const float CYLINDER_TOP = 0.1f; const float CYLINDER_BOTTOM = -1.5f; + const float SITTING_BOTTOM = -0.02f; glm::vec3 offset = extractTranslation(desiredBodyMatrix) - extractTranslation(currentBodyMatrix); - return (offset.y > CYLINDER_TOP) || (offset.y < CYLINDER_BOTTOM); + if (myAvatar.getIsInSittingState()) { + if (offset.y < SITTING_BOTTOM) { + // we recenter when sitting. + return true; + } else if (offset.y > CYLINDER_TOP) { + // if we recenter upwards then no longer in sitting state + myAvatar.setIsInSittingState(false); + return true; + } else { + return false; + } + } else { + return (offset.y > CYLINDER_TOP) || (offset.y < CYLINDER_BOTTOM); + } } void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix, bool hasDriveInput) { - if (myAvatar.getHMDLeanRecenterEnabled() && - qApp->getCamera().getMode() != CAMERA_MODE_MIRROR) { + qCDebug(interfaceapp) << "in sitting state: " << myAvatar.getIsInSittingState(); + + if (myAvatar.getHMDLeanRecenterEnabled() && qApp->getCamera().getMode() != CAMERA_MODE_MIRROR) { if (!isActive(Rotation) && (shouldActivateRotation(myAvatar, desiredBodyMatrix, currentBodyMatrix) || hasDriveInput)) { activate(Rotation); myAvatar.setHeadControllerFacingMovingAverage(myAvatar.getHeadControllerFacing()); } if (myAvatar.getCenterOfGravityModelEnabled()) { - if (!isActive(Horizontal) && (shouldActivateHorizontalCG(myAvatar) || hasDriveInput)) { - activate(Horizontal); - if (myAvatar.getEnableStepResetRotation()) { - activate(Rotation); - myAvatar.setHeadControllerFacingMovingAverage(myAvatar.getHeadControllerFacing()); + if (!(myAvatar.getIsInSittingState())) { + if (!isActive(Horizontal) && (shouldActivateHorizontalCG(myAvatar) || hasDriveInput)) { + activate(Horizontal); + if (myAvatar.getEnableStepResetRotation()) { + activate(Rotation); + myAvatar.setHeadControllerFacingMovingAverage(myAvatar.getHeadControllerFacing()); + } + } + } else { + // you are in the sitting state with cg model enabled + if (!isActive(Horizontal) && (shouldActivateHorizontalSitting(myAvatar) || hasDriveInput)) { + activate(Horizontal); + if (myAvatar.getEnableStepResetRotation()) { + activate(Rotation); + myAvatar.setHeadControllerFacingMovingAverage(myAvatar.getHeadControllerFacing()); + } } } } else { + // center of gravity model is not enabled if (!isActive(Horizontal) && (shouldActivateHorizontal(myAvatar, desiredBodyMatrix, currentBodyMatrix) || hasDriveInput)) { activate(Horizontal); if (myAvatar.getEnableStepResetRotation()) { diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 139f1f6ea2..a7fdf964d0 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -1094,6 +1094,8 @@ public: void setIsInWalkingState(bool isWalking); bool getIsInWalkingState() const; + void setIsInSittingState(bool isSitting); + bool getIsInSittingState() const; void setWalkSpeed(float value); float getWalkSpeed() const; void setWalkBackwardSpeed(float value); @@ -1708,9 +1710,10 @@ private: float getMaxTimeRemaining() const; void decrementTimeRemaining(float dt); bool shouldActivateRotation(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const; - bool shouldActivateVertical(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const; + bool shouldActivateVertical(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 shouldActivateHorizontalSitting(MyAvatar& myAvatar) const; void prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat4& bodySensorMatrix, const glm::mat4& currentBodyMatrix, bool hasDriveInput); glm::mat4 postPhysicsUpdate(const MyAvatar& myAvatar, const glm::mat4& currentBodyMatrix); bool getForceActivateRotation() const; @@ -1800,6 +1803,7 @@ private: ThreadSafeValueCache _sprintSpeed { AVATAR_SPRINT_SPEED_SCALAR }; float _walkSpeedScalar { AVATAR_WALK_SPEED_SCALAR }; bool _isInWalkingState { false }; + bool _isInSittingState{ false }; // load avatar scripts once when rig is ready bool _shouldLoadScripts { false }; diff --git a/interface/src/avatar/MySkeletonModel.cpp b/interface/src/avatar/MySkeletonModel.cpp index 3084542472..42ec582c47 100644 --- a/interface/src/avatar/MySkeletonModel.cpp +++ b/interface/src/avatar/MySkeletonModel.cpp @@ -46,7 +46,7 @@ static AnimPose computeHipsInSensorFrame(MyAvatar* myAvatar, bool isFlying) { } glm::mat4 hipsMat; - if (myAvatar->getCenterOfGravityModelEnabled() && !isFlying && !(myAvatar->getIsInWalkingState())) { + if (myAvatar->getCenterOfGravityModelEnabled() && !isFlying && !(myAvatar->getIsInWalkingState()) && !(myAvatar->getIsInSittingState())) { // then we use center of gravity model hipsMat = myAvatar->deriveBodyUsingCgModel(); } else { From 14fb7e1d44f8e52fbc91f8810f48d78b776b3005 Mon Sep 17 00:00:00 2001 From: amantley Date: Mon, 17 Sep 2018 17:53:08 -0700 Subject: [PATCH 02/54] removed redundant code --- interface/src/avatar/MyAvatar.cpp | 52 ++++++------------------------- 1 file changed, 9 insertions(+), 43 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index b626fb6c2a..d4168616c3 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -4039,33 +4039,6 @@ bool MyAvatar::FollowHelper::shouldActivateHorizontal(const MyAvatar& myAvatar, return fabs(lateralLeanAmount) > MAX_LATERAL_LEAN; } -bool MyAvatar::FollowHelper::shouldActivateHorizontalSitting(MyAvatar& myAvatar) const { - - // get the current readings - controller::Pose currentHeadPose = myAvatar.getControllerPoseInAvatarFrame(controller::Action::HEAD); - controller::Pose currentLeftHandPose = myAvatar.getControllerPoseInAvatarFrame(controller::Action::LEFT_HAND); - controller::Pose currentRightHandPose = myAvatar.getControllerPoseInAvatarFrame(controller::Action::RIGHT_HAND); - - bool stepDetected = false; - float myScale = myAvatar.getAvatarScale(); - - if (!withinBaseOfSupport(currentHeadPose)) { - // a step is detected - stepDetected = true; - } else { - glm::vec3 defaultHipsPosition = myAvatar.getAbsoluteDefaultJointTranslationInObjectFrame(myAvatar.getJointIndex("Hips")); - glm::vec3 defaultHeadPosition = myAvatar.getAbsoluteDefaultJointTranslationInObjectFrame(myAvatar.getJointIndex("Head")); - glm::vec3 currentHeadPosition = currentHeadPose.getTranslation(); - float anatomicalHeadToHipsDistance = glm::length(defaultHeadPosition - defaultHipsPosition); - if (!isActive(Horizontal) && - (glm::length(currentHeadPosition - defaultHipsPosition) > (anatomicalHeadToHipsDistance + (DEFAULT_AVATAR_SPINE_STRETCH_LIMIT * anatomicalHeadToHipsDistance)))) { - myAvatar.setResetMode(true); - stepDetected = true; - } - } - return stepDetected; -} - bool MyAvatar::FollowHelper::shouldActivateHorizontalCG(MyAvatar& myAvatar) const { // get the current readings @@ -4078,6 +4051,10 @@ bool MyAvatar::FollowHelper::shouldActivateHorizontalCG(MyAvatar& myAvatar) cons if (myAvatar.getIsInWalkingState()) { stepDetected = true; + } else if (myAvatar.getIsInSittingState()) { + if (!withinBaseOfSupport(currentHeadPose)) { + stepDetected = true; + } } else { if (!withinBaseOfSupport(currentHeadPose) && headAngularVelocityBelowThreshold(currentHeadPose) && @@ -4143,22 +4120,11 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat myAvatar.setHeadControllerFacingMovingAverage(myAvatar.getHeadControllerFacing()); } if (myAvatar.getCenterOfGravityModelEnabled()) { - if (!(myAvatar.getIsInSittingState())) { - if (!isActive(Horizontal) && (shouldActivateHorizontalCG(myAvatar) || hasDriveInput)) { - activate(Horizontal); - if (myAvatar.getEnableStepResetRotation()) { - activate(Rotation); - myAvatar.setHeadControllerFacingMovingAverage(myAvatar.getHeadControllerFacing()); - } - } - } else { - // you are in the sitting state with cg model enabled - if (!isActive(Horizontal) && (shouldActivateHorizontalSitting(myAvatar) || hasDriveInput)) { - activate(Horizontal); - if (myAvatar.getEnableStepResetRotation()) { - activate(Rotation); - myAvatar.setHeadControllerFacingMovingAverage(myAvatar.getHeadControllerFacing()); - } + if (!isActive(Horizontal) && (shouldActivateHorizontalCG(myAvatar) || hasDriveInput)) { + activate(Horizontal); + if (myAvatar.getEnableStepResetRotation()) { + activate(Rotation); + myAvatar.setHeadControllerFacingMovingAverage(myAvatar.getHeadControllerFacing()); } } } else { From 96da9b7e54ddaec7e976527059e878d0e3e27b89 Mon Sep 17 00:00:00 2001 From: amantley Date: Tue, 18 Sep 2018 10:31:19 -0700 Subject: [PATCH 03/54] cleaned up code for squatty fix --- interface/resources/qml/AnimStats.qml | 2 +- interface/src/avatar/MyAvatar.cpp | 6 +++--- interface/src/avatar/MyAvatar.h | 3 +-- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/interface/resources/qml/AnimStats.qml b/interface/resources/qml/AnimStats.qml index fd0a280dad..35ed3799a6 100644 --- a/interface/resources/qml/AnimStats.qml +++ b/interface/resources/qml/AnimStats.qml @@ -53,7 +53,7 @@ Item { ListView { width: firstCol.width height: root.animStateMachines.length * 15 - visible: root.animStateMachines.length > 0; + visible: root.animStateMchines.length > 0; model: root.animStateMachines delegate: StatText { text: { diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index d4168616c3..8eceb19e09 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -4074,6 +4074,7 @@ bool MyAvatar::FollowHelper::shouldActivateHorizontalCG(MyAvatar& myAvatar) cons glm::vec3 currentHeadPosition = currentHeadPose.getTranslation(); float anatomicalHeadToHipsDistance = glm::length(defaultHeadPosition - defaultHipsPosition); if (!isActive(Horizontal) && + (!isActive(Vertical)) && (glm::length(currentHeadPosition - defaultHipsPosition) > (anatomicalHeadToHipsDistance + (DEFAULT_AVATAR_SPINE_STRETCH_LIMIT * anatomicalHeadToHipsDistance)))) { myAvatar.setResetMode(true); stepDetected = true; @@ -4112,9 +4113,8 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(MyAvatar& myAvatar, const gl void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix, bool hasDriveInput) { - qCDebug(interfaceapp) << "in sitting state: " << myAvatar.getIsInSittingState(); - - if (myAvatar.getHMDLeanRecenterEnabled() && qApp->getCamera().getMode() != CAMERA_MODE_MIRROR) { + if (myAvatar.getHMDLeanRecenterEnabled() && + qApp->getCamera().getMode() != CAMERA_MODE_MIRROR) { if (!isActive(Rotation) && (shouldActivateRotation(myAvatar, desiredBodyMatrix, currentBodyMatrix) || hasDriveInput)) { activate(Rotation); myAvatar.setHeadControllerFacingMovingAverage(myAvatar.getHeadControllerFacing()); diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index a7fdf964d0..6f3858c5bf 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -1713,7 +1713,6 @@ private: bool shouldActivateVertical(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 shouldActivateHorizontalSitting(MyAvatar& myAvatar) const; void prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat4& bodySensorMatrix, const glm::mat4& currentBodyMatrix, bool hasDriveInput); glm::mat4 postPhysicsUpdate(const MyAvatar& myAvatar, const glm::mat4& currentBodyMatrix); bool getForceActivateRotation() const; @@ -1803,7 +1802,7 @@ private: ThreadSafeValueCache _sprintSpeed { AVATAR_SPRINT_SPEED_SCALAR }; float _walkSpeedScalar { AVATAR_WALK_SPEED_SCALAR }; bool _isInWalkingState { false }; - bool _isInSittingState{ false }; + bool _isInSittingState { false }; // load avatar scripts once when rig is ready bool _shouldLoadScripts { false }; From 42e248ef84ca8207ca92885f04768935e8457062 Mon Sep 17 00:00:00 2001 From: amantley Date: Tue, 18 Sep 2018 17:37:44 -0700 Subject: [PATCH 04/54] maded more changes to support sitting state to do: add option for stuck pose reset --- interface/src/avatar/MyAvatar.cpp | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 8eceb19e09..bf684ccd9a 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -453,6 +453,16 @@ void MyAvatar::update(float deltaTime) { float tau = deltaTime / HMD_FACING_TIMESCALE; setHipToHandController(computeHandAzimuth()); + // qCDebug(interfaceapp) << "sitting state is " << getIsInSittingState(); + // debug setting for sitting state if you start in the chair. + // if the head is close to the floor in sensor space + // and the up of the head is close to sensor up then try switching us to sitting state. + auto sensorHeadPoseDebug = getControllerPoseInSensorFrame(controller::Action::HEAD); + glm::vec3 upHead = transformVectorFast(sensorHeadPoseDebug.getMatrix(), glm::vec3(0.0f, 1.0f, 0.0f)); + float acosHead = glm::dot(upHead, glm::vec3(0.0f, 1.0f, 0.0f)); + if ((acosHead > 0.98f) && !getIsInSittingState() && (sensorHeadPoseDebug.getTranslation().y < -0.5f)) { + qCDebug(interfaceapp) << "we are going to sitting state because it looks like we should" << sensorHeadPoseDebug.getTranslation().y; + } // put the average hand azimuth into sensor space. // then mix it with head facing direction to determine rotation recenter if (getControllerPoseInAvatarFrame(controller::Action::LEFT_HAND).isValid() && getControllerPoseInAvatarFrame(controller::Action::RIGHT_HAND).isValid()) { @@ -3593,7 +3603,7 @@ glm::vec3 MyAvatar::computeCounterBalance() { setResetMode(true); _follow.activate(FollowHelper::Vertical); // disable cg behaviour in this case. - _isInSittingState = true; + setIsInSittingState(true); } return counterBalancedCg; } @@ -4049,6 +4059,12 @@ bool MyAvatar::FollowHelper::shouldActivateHorizontalCG(MyAvatar& myAvatar) cons bool stepDetected = false; float myScale = myAvatar.getAvatarScale(); + + // debug head hips angle + //glm::vec3 hipsPos = myAvatar.getAbsoluteDefaultJointTranslationInObjectFrame(myAvatar.getJointIndex("Hips")); + //glm::vec3 headHipsBody = currentHeadPose.getTranslation() - hipsPos; + //qCDebug(interfaceapp) << "head in sensor space " << withinBaseOfSupport(currentHeadPose); + if (myAvatar.getIsInWalkingState()) { stepDetected = true; } else if (myAvatar.getIsInSittingState()) { @@ -4094,6 +4110,12 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(MyAvatar& myAvatar, const gl glm::vec3 offset = extractTranslation(desiredBodyMatrix) - extractTranslation(currentBodyMatrix); + auto sensorHeadPose = myAvatar.getControllerPoseInSensorFrame(controller::Action::HEAD); + glm::vec3 headWorldSpace = myAvatar.getHead()->getPosition(); + glm::mat4 worldToSensorMatrix = glm::inverse(myAvatar.getSensorToWorldMatrix()); + glm::vec3 headSensorSpace = transformVectorFast(myAvatar.getSensorToWorldMatrix(), headWorldSpace); + //qCDebug(interfaceapp) << "sensor space position " << extractTranslation(currentBodyMatrix) << " head position sensor " << sensorHeadPose.getTranslation(); + if (myAvatar.getIsInSittingState()) { if (offset.y < SITTING_BOTTOM) { // we recenter when sitting. From ad6bbc7ff6954461c35da6ddbdef7b71bf7c5c55 Mon Sep 17 00:00:00 2001 From: amantley Date: Tue, 25 Sep 2018 11:22:44 -0700 Subject: [PATCH 05/54] latest squatty changes --- interface/src/avatar/MyAvatar.cpp | 25 +++++++++++++++++-------- interface/src/avatar/MyAvatar.h | 1 + plugins/oculus/src/OculusHelpers.cpp | 6 ++++++ 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index bf684ccd9a..c52e029d94 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -463,6 +463,7 @@ void MyAvatar::update(float deltaTime) { if ((acosHead > 0.98f) && !getIsInSittingState() && (sensorHeadPoseDebug.getTranslation().y < -0.5f)) { qCDebug(interfaceapp) << "we are going to sitting state because it looks like we should" << sensorHeadPoseDebug.getTranslation().y; } + // put the average hand azimuth into sensor space. // then mix it with head facing direction to determine rotation recenter if (getControllerPoseInAvatarFrame(controller::Action::LEFT_HAND).isValid() && getControllerPoseInAvatarFrame(controller::Action::RIGHT_HAND).isValid()) { @@ -3601,9 +3602,9 @@ glm::vec3 MyAvatar::computeCounterBalance() { } else if (counterBalancedCg.y < sitSquatThreshold) { // do a height reset setResetMode(true); - _follow.activate(FollowHelper::Vertical); + //_follow.activate(FollowHelper::Vertical); // disable cg behaviour in this case. - setIsInSittingState(true); + //setIsInSittingState(true); } return counterBalancedCg; } @@ -4059,12 +4060,6 @@ bool MyAvatar::FollowHelper::shouldActivateHorizontalCG(MyAvatar& myAvatar) cons bool stepDetected = false; float myScale = myAvatar.getAvatarScale(); - - // debug head hips angle - //glm::vec3 hipsPos = myAvatar.getAbsoluteDefaultJointTranslationInObjectFrame(myAvatar.getJointIndex("Hips")); - //glm::vec3 headHipsBody = currentHeadPose.getTranslation() - hipsPos; - //qCDebug(interfaceapp) << "head in sensor space " << withinBaseOfSupport(currentHeadPose); - if (myAvatar.getIsInWalkingState()) { stepDetected = true; } else if (myAvatar.getIsInSittingState()) { @@ -4137,6 +4132,20 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat if (myAvatar.getHMDLeanRecenterEnabled() && qApp->getCamera().getMode() != CAMERA_MODE_MIRROR) { + + // debug head hips angle + glm::vec3 headDefaultPos = myAvatar.getAbsoluteDefaultJointTranslationInObjectFrame(myAvatar.getJointIndex("Head")); + if (myAvatar.getControllerPoseInAvatarFrame(controller::Action::HEAD).getTranslation().y < (headDefaultPos.y - 0.05f)) { + _squatCount++; + if ((_squatCount > 300) && !isActive(Vertical) && !isActive(Horizontal)) { + activate(Horizontal); + activate(Vertical); + _squatCount = 0; + } + } else { + _squatCount = 0; + } + if (!isActive(Rotation) && (shouldActivateRotation(myAvatar, desiredBodyMatrix, currentBodyMatrix) || hasDriveInput)) { activate(Rotation); myAvatar.setHeadControllerFacingMovingAverage(myAvatar.getHeadControllerFacing()); diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 6f3858c5bf..78dc6307e8 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -1727,6 +1727,7 @@ private: std::atomic _forceActivateVertical { false }; std::atomic _forceActivateHorizontal { false }; std::atomic _toggleHipsFollowing { true }; + int _squatCount{ 0 }; }; FollowHelper _follow; diff --git a/plugins/oculus/src/OculusHelpers.cpp b/plugins/oculus/src/OculusHelpers.cpp index 511984c657..e543d3ca00 100644 --- a/plugins/oculus/src/OculusHelpers.cpp +++ b/plugins/oculus/src/OculusHelpers.cpp @@ -79,6 +79,12 @@ private: if (!OVR_SUCCESS(ovr_Initialize(&initParams))) { qCWarning(oculusLog) << "Failed to initialze Oculus SDK" << ovr::getError(); return; + } else { + qCWarning(oculusLog) << "successful init of oculus!!!!!!!!"; + ovrTrackingOrigin fred; + fred = ovr_GetTrackingOriginType(session); + qCWarning(oculusLog) << (int)fred; + } ovrGraphicsLuid luid; From fa9abf0fff45ba8205a8647bdb28f18bc068e676 Mon Sep 17 00:00:00 2001 From: amantley Date: Wed, 26 Sep 2018 18:08:00 -0700 Subject: [PATCH 06/54] added the floor at 0.0 in sensor space for oculus. to do: vive --- interface/src/avatar/MyAvatar.cpp | 35 ++++++++++++++++++++-------- interface/src/avatar/MyAvatar.h | 5 ++-- plugins/oculus/src/OculusHelpers.cpp | 13 ++++++----- 3 files changed, 35 insertions(+), 18 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 6394631484..2152c12b64 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -477,10 +477,20 @@ void MyAvatar::update(float deltaTime) { auto sensorHeadPoseDebug = getControllerPoseInSensorFrame(controller::Action::HEAD); glm::vec3 upHead = transformVectorFast(sensorHeadPoseDebug.getMatrix(), glm::vec3(0.0f, 1.0f, 0.0f)); float acosHead = glm::dot(upHead, glm::vec3(0.0f, 1.0f, 0.0f)); + qCDebug(interfaceapp) << "sensor space head pos " << sensorHeadPoseDebug.getTranslation().y; if ((acosHead > 0.98f) && !getIsInSittingState() && (sensorHeadPoseDebug.getTranslation().y < -0.5f)) { - qCDebug(interfaceapp) << "we are going to sitting state because it looks like we should" << sensorHeadPoseDebug.getTranslation().y; + //qCDebug(interfaceapp) << "we are going to sitting state because it looks like we should" << sensorHeadPoseDebug.getTranslation().y; } - + if (!_lastFrameHMDMode && qApp->isHMDMode()) { + // we have entered hmd mode, so make the best guess about sitting or standing + if (sensorHeadPoseDebug.getTranslation().y < 1.3f) { + // then we are sitting. + // setIsInSittingState(true); + } else { + // setIsInSittingState(false); + } + } + // put the average hand azimuth into sensor space. // then mix it with head facing direction to determine rotation recenter if (getControllerPoseInAvatarFrame(controller::Action::LEFT_HAND).isValid() && getControllerPoseInAvatarFrame(controller::Action::RIGHT_HAND).isValid()) { @@ -3575,9 +3585,9 @@ glm::vec3 MyAvatar::computeCounterBalance() { } else if (counterBalancedCg.y < sitSquatThreshold) { // do a height reset setResetMode(true); - //_follow.activate(FollowHelper::Vertical); + // _follow.activate(FollowHelper::Vertical); // disable cg behaviour in this case. - //setIsInSittingState(true); + // setIsInSittingState(true); } return counterBalancedCg; } @@ -4090,7 +4100,7 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(MyAvatar& myAvatar, const gl return true; } else if (offset.y > CYLINDER_TOP) { // if we recenter upwards then no longer in sitting state - myAvatar.setIsInSittingState(false); + // myAvatar.setIsInSittingState(false); return true; } else { return false; @@ -4110,15 +4120,20 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat glm::vec3 headDefaultPos = myAvatar.getAbsoluteDefaultJointTranslationInObjectFrame(myAvatar.getJointIndex("Head")); if (myAvatar.getControllerPoseInAvatarFrame(controller::Action::HEAD).getTranslation().y < (headDefaultPos.y - 0.05f)) { _squatCount++; - if ((_squatCount > 300) && !isActive(Vertical) && !isActive(Horizontal)) { - activate(Horizontal); - activate(Vertical); - _squatCount = 0; + if ((_squatCount > 600) && !isActive(Vertical) && !isActive(Horizontal)) { + if (myAvatar.getIsInSittingState()) { + // activate(Horizontal); + activate(Vertical); + _squatCount = 0; + } else { + activate(Horizontal); + _squatCount = 0; + } } } else { _squatCount = 0; } - + if (!isActive(Rotation) && (shouldActivateRotation(myAvatar, desiredBodyMatrix, currentBodyMatrix) || hasDriveInput)) { activate(Rotation); myAvatar.setHeadControllerFacingMovingAverage(myAvatar.getHeadControllerFacing()); diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 1dabe38116..4ccb1a8d75 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -1728,7 +1728,7 @@ private: std::atomic _forceActivateVertical { false }; std::atomic _forceActivateHorizontal { false }; std::atomic _toggleHipsFollowing { true }; - int _squatCount{ 0 }; + int _squatCount { 0 }; }; FollowHelper _follow; @@ -1760,6 +1760,7 @@ private: glm::quat _customListenOrientation; AtRestDetector _hmdAtRestDetector; + bool _lastFrameHMDMode { false } ; bool _lastIsMoving { false }; // all poses are in sensor-frame @@ -1804,7 +1805,7 @@ private: ThreadSafeValueCache _sprintSpeed { AVATAR_SPRINT_SPEED_SCALAR }; float _walkSpeedScalar { AVATAR_WALK_SPEED_SCALAR }; bool _isInWalkingState { false }; - bool _isInSittingState { false }; + bool _isInSittingState { true }; // load avatar scripts once when rig is ready bool _shouldLoadScripts { false }; diff --git a/plugins/oculus/src/OculusHelpers.cpp b/plugins/oculus/src/OculusHelpers.cpp index e543d3ca00..38d93d088d 100644 --- a/plugins/oculus/src/OculusHelpers.cpp +++ b/plugins/oculus/src/OculusHelpers.cpp @@ -79,18 +79,19 @@ private: if (!OVR_SUCCESS(ovr_Initialize(&initParams))) { qCWarning(oculusLog) << "Failed to initialze Oculus SDK" << ovr::getError(); return; - } else { - qCWarning(oculusLog) << "successful init of oculus!!!!!!!!"; - ovrTrackingOrigin fred; - fred = ovr_GetTrackingOriginType(session); - qCWarning(oculusLog) << (int)fred; - } ovrGraphicsLuid luid; if (!OVR_SUCCESS(ovr_Create(&session, &luid))) { qCWarning(oculusLog) << "Failed to acquire Oculus session" << ovr::getError(); return; + } else { + qCWarning(oculusLog) << "successful init of oculus!!!!!!!!"; + ovrTrackingOrigin fred; + //fred = ovr_GetTrackingOriginType(session); + ovrResult retTrackingType = ovr_SetTrackingOriginType(session, ovrTrackingOrigin::ovrTrackingOrigin_FloorLevel); + fred = ovr_GetTrackingOriginType(session); + qCWarning(oculusLog) << OVR_SUCCESS(retTrackingType) << (int)fred; } } From 52355e53f1e69ff4032813c13b229c04c6cfdb0d Mon Sep 17 00:00:00 2001 From: amantley Date: Thu, 27 Sep 2018 16:44:55 -0700 Subject: [PATCH 07/54] adding the menu item to the avatar app for the sit state. --- interface/resources/qml/hifi/AvatarApp.qml | 1 + .../resources/qml/hifi/avatarapp/Settings.qml | 57 +- interface/src/avatar/MyAvatar.cpp | 14 +- interface/src/avatar/MyAvatar.h | 9 + .../src/avatars-renderer/Avatar.cpp | 1 + scripts/developer/objectOrientedStep.js | 688 ++++++++++++++++++ scripts/system/avatarapp.js | 15 +- 7 files changed, 778 insertions(+), 7 deletions(-) create mode 100644 scripts/developer/objectOrientedStep.js diff --git a/interface/resources/qml/hifi/AvatarApp.qml b/interface/resources/qml/hifi/AvatarApp.qml index aea5931627..b06a2ca67c 100644 --- a/interface/resources/qml/hifi/AvatarApp.qml +++ b/interface/resources/qml/hifi/AvatarApp.qml @@ -252,6 +252,7 @@ Rectangle { var avatarSettings = { dominantHand : settings.dominantHandIsLeft ? 'left' : 'right', collisionsEnabled : settings.avatarCollisionsOn, + sittingEnabled : settings.avatarSittingOn, animGraphOverrideUrl : settings.avatarAnimationOverrideJSON, collisionSoundUrl : settings.avatarCollisionSoundUrl }; diff --git a/interface/resources/qml/hifi/avatarapp/Settings.qml b/interface/resources/qml/hifi/avatarapp/Settings.qml index 71bfbb084d..af76ba04d6 100644 --- a/interface/resources/qml/hifi/avatarapp/Settings.qml +++ b/interface/resources/qml/hifi/avatarapp/Settings.qml @@ -20,6 +20,7 @@ Rectangle { property real scaleValue: scaleSlider.value / 10 property alias dominantHandIsLeft: leftHandRadioButton.checked property alias avatarCollisionsOn: collisionsEnabledRadiobutton.checked + property alias avatarSittingOn: sitRadiobutton.checked property alias avatarAnimationOverrideJSON: avatarAnimationUrlInputText.text property alias avatarAnimationJSON: avatarAnimationUrlInputText.placeholderText property alias avatarCollisionSoundUrl: avatarCollisionSoundUrlInputText.text @@ -45,6 +46,12 @@ Rectangle { collisionsDisabledRadioButton.checked = true; } + if (settings.sittingEnabled) { + sitRadiobutton.checked = true; + } else { + standRadioButton.checked = true; + } + avatarAnimationJSON = settings.animGraphUrl; avatarAnimationOverrideJSON = settings.animGraphOverrideUrl; avatarCollisionSoundUrl = settings.collisionSoundUrl; @@ -289,8 +296,56 @@ Rectangle { text: "OFF" boxSize: 20 } - } + + // TextStyle9 + + RalewaySemiBold { + size: 17; + Layout.row: 2 + Layout.column: 0 + + text: "Sitting State" + } + + ButtonGroup { + id: sitStand + } + + HifiControlsUit.RadioButton { + id: sitRadiobutton + + Layout.row: 2 + Layout.column: 1 + Layout.leftMargin: -40 + + ButtonGroup.group: sitStand + checked: true + + colorScheme: hifi.colorSchemes.light + fontSize: 17 + letterSpacing: 1.4 + text: "Sit" + boxSize: 20 + } + + HifiControlsUit.RadioButton { + id: standRadioButton + + Layout.row: 2 + Layout.column: 2 + Layout.rightMargin: 20 + + ButtonGroup.group: sitStand + + colorScheme: hifi.colorSchemes.light + fontSize: 17 + letterSpacing: 1.4 + text: "Stand" + boxSize: 20 + } + } + ColumnLayout { id: avatarAnimationLayout anchors.top: handAndCollisions.bottom diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 2152c12b64..631a4b0670 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -477,7 +477,7 @@ void MyAvatar::update(float deltaTime) { auto sensorHeadPoseDebug = getControllerPoseInSensorFrame(controller::Action::HEAD); glm::vec3 upHead = transformVectorFast(sensorHeadPoseDebug.getMatrix(), glm::vec3(0.0f, 1.0f, 0.0f)); float acosHead = glm::dot(upHead, glm::vec3(0.0f, 1.0f, 0.0f)); - qCDebug(interfaceapp) << "sensor space head pos " << sensorHeadPoseDebug.getTranslation().y; + // qCDebug(interfaceapp) << "sensor space head pos " << sensorHeadPoseDebug.getTranslation().y; if ((acosHead > 0.98f) && !getIsInSittingState() && (sensorHeadPoseDebug.getTranslation().y < -0.5f)) { //qCDebug(interfaceapp) << "we are going to sitting state because it looks like we should" << sensorHeadPoseDebug.getTranslation().y; } @@ -3854,6 +3854,7 @@ void MyAvatar::setIsInWalkingState(bool isWalking) { void MyAvatar::setIsInSittingState(bool isSitting) { _isInSittingState = isSitting; + emit sittingEnabledChanged(isSitting); } void MyAvatar::setWalkSpeed(float value) { @@ -4098,9 +4099,9 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(MyAvatar& myAvatar, const gl if (offset.y < SITTING_BOTTOM) { // we recenter when sitting. return true; - } else if (offset.y > CYLINDER_TOP) { + } else if (offset.y > 2.0*CYLINDER_TOP) { // if we recenter upwards then no longer in sitting state - // myAvatar.setIsInSittingState(false); + myAvatar.setIsInSittingState(false); return true; } else { return false; @@ -4126,7 +4127,12 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat activate(Vertical); _squatCount = 0; } else { - activate(Horizontal); + if (myAvatar.getControllerPoseInAvatarFrame(controller::Action::HEAD).getTranslation().y < (headDefaultPos.y - 0.20f)) { + myAvatar.setIsInSittingState(true); + activate(Vertical); + } else { + activate(Horizontal); + } _squatCount = 0; } } diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 4ccb1a8d75..d9744e93fe 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -239,6 +239,7 @@ class MyAvatar : public Avatar { Q_PROPERTY(float walkSpeed READ getWalkSpeed WRITE setWalkSpeed); Q_PROPERTY(float walkBackwardSpeed READ getWalkBackwardSpeed WRITE setWalkBackwardSpeed); Q_PROPERTY(float sprintSpeed READ getSprintSpeed WRITE setSprintSpeed); + Q_PROPERTY(bool isInSittingState READ getIsInSittingState WRITE setIsInSittingState); const QString DOMINANT_LEFT_HAND = "left"; const QString DOMINANT_RIGHT_HAND = "right"; @@ -1506,6 +1507,14 @@ signals: */ void disableHandTouchForIDChanged(const QUuid& entityID, bool disable); + /**jsdoc + * Triggered when the sit state is enabled or disabled + * @function MyAvatar.sittingEnabledChanged + * @param {boolean} enabled + * @returns {Signal} + */ + void sittingEnabledChanged(bool enabled); + private slots: void leaveDomain(); void updateCollisionCapsuleCache(); diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp index 914a3b7c6e..51c51b6a20 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp @@ -1618,6 +1618,7 @@ void Avatar::getCapsule(glm::vec3& start, glm::vec3& end, float& radius) { glm::vec3 Avatar::getWorldFeetPosition() { ShapeInfo shapeInfo; + computeShapeInfo(shapeInfo); glm::vec3 halfExtents = shapeInfo.getHalfExtents(); // x = radius, y = halfHeight glm::vec3 localFeet(0.0f, shapeInfo.getOffset().y - halfExtents.y - halfExtents.x, 0.0f); diff --git a/scripts/developer/objectOrientedStep.js b/scripts/developer/objectOrientedStep.js new file mode 100644 index 0000000000..a5c27e36b9 --- /dev/null +++ b/scripts/developer/objectOrientedStep.js @@ -0,0 +1,688 @@ +/* jslint bitwise: true */ + +/* global Script, Vec3, MyAvatar, Tablet, Messages, Quat, +DebugDraw, Mat4, Entities, Xform, Controller, Camera, console, document*/ + +Script.registerValue("STEPAPP", true); +var CENTIMETERSPERMETER = 100.0; +var LEFT = 0; +var RIGHT = 1; +var INCREASING = 1.0; +var DECREASING = -1.0; +var DEFAULT_AVATAR_HEIGHT = 1.64; +var TABLET_BUTTON_NAME = "STEP"; +var CHANGE_OF_BASIS_ROTATION = { x: 0, y: 1, z: 0, w: 0 }; +// in meters (mostly) +var DEFAULT_ANTERIOR = 0.04; +var DEFAULT_POSTERIOR = 0.06; +var DEFAULT_LATERAL = 0.10; +var DEFAULT_HEIGHT_DIFFERENCE = 0.02; +var DEFAULT_ANGULAR_VELOCITY = 0.3; +var DEFAULT_HAND_VELOCITY = 0.4; +var DEFAULT_ANGULAR_HAND_VELOCITY = 3.3; +var DEFAULT_HEAD_VELOCITY = 0.14; +var DEFAULT_LEVEL_PITCH = 7; +var DEFAULT_LEVEL_ROLL = 7; +var DEFAULT_DIFF = 0.0; +var DEFAULT_DIFF_EULERS = { x: 0.0, y: 0.0, z: 0.0 }; +var DEFAULT_HIPS_POSITION; +var DEFAULT_HEAD_POSITION; +var DEFAULT_TORSO_LENGTH; +var SPINE_STRETCH_LIMIT = 0.02; + +var VELOCITY_EPSILON = 0.02; +var AVERAGING_RATE = 0.03; +var HEIGHT_AVERAGING_RATE = 0.01; +var STEP_TIME_SECS = 0.2; +var MODE_SAMPLE_LENGTH = 100; +var RESET_MODE = false; +var HEAD_TURN_THRESHOLD = 25.0; +var NO_SHARED_DIRECTION = -0.98; +var LOADING_DELAY = 500; +var FAILSAFE_TIMEOUT = 2.5; + +var debugDrawBase = true; +var activated = false; +var documentLoaded = false; +var failsafeFlag = false; +var failsafeSignalTimer = -1.0; +var stepTimer = -1.0; + + +var modeArray = new Array(MODE_SAMPLE_LENGTH); +var modeHeight = -10.0; + +var handPosition; +var handOrientation; +var hands = []; +var hipToHandAverage = []; +var handDotHead = []; +var headAverageOrientation = MyAvatar.orientation; +var headPoseAverageOrientation = { x: 0, y: 0, z: 0, w: 1 }; +var averageHeight = 1.0; +var headEulers = { x: 0.0, y: 0.0, z: 0.0 }; +var headAverageEulers = { x: 0.0, y: 0.0, z: 0.0 }; +var headAveragePosition = { x: 0, y: 0.4, z: 0 }; +var frontLeft = { x: -DEFAULT_LATERAL, y: 0, z: -DEFAULT_ANTERIOR }; +var frontRight = { x: DEFAULT_LATERAL, y: 0, z: -DEFAULT_ANTERIOR }; +var backLeft = { x: -DEFAULT_LATERAL, y: 0, z: DEFAULT_POSTERIOR }; +var backRight = { x: DEFAULT_LATERAL, y: 0, z: DEFAULT_POSTERIOR }; + + +// define state readings constructor +function StateReading(headPose, rhandPose, lhandPose, backLength, diffFromMode, diffFromAverageHeight, diffFromAveragePosition, + diffFromAverageEulers) { + this.headPose = headPose; + this.rhandPose = rhandPose; + this.lhandPose = lhandPose; + this.backLength = backLength; + this.diffFromMode = diffFromMode; + this.diffFromAverageHeight = diffFromAverageHeight; + this.diffFromAveragePosition = diffFromAveragePosition; + this.diffFromAverageEulers = diffFromAverageEulers; +} + +// define current state readings object for holding tracker readings and current differences from averages +var currentStateReadings = new StateReading(Controller.getPoseValue(Controller.Standard.Head), + Controller.getPoseValue(Controller.Standard.RightHand), Controller.getPoseValue(Controller.Standard.LeftHand), + DEFAULT_TORSO_LENGTH, DEFAULT_DIFF, DEFAULT_DIFF, DEFAULT_DIFF, DEFAULT_DIFF_EULERS); + +// declare the checkbox constructor +function AppCheckbox(type,id,eventType,isChecked) { + this.type = type; + this.id = id; + this.eventType = eventType; + this.data = {value: isChecked}; +} + +// define the checkboxes in the html file +var usingAverageHeight = new AppCheckbox("checkboxtick", "runningAverageHeightCheck", "onRunningAverageHeightCheckBox", + false); +var usingModeHeight = new AppCheckbox("checkboxtick","modeCheck","onModeCheckBox",true); +var usingBaseOfSupport = new AppCheckbox("checkboxtick","baseOfSupportCheck","onBaseOfSupportCheckBox",true); +var usingAverageHeadPosition = new AppCheckbox("checkboxtick", "headAveragePositionCheck", "onHeadAveragePositionCheckBox", + false); + +var checkBoxArray = new Array(usingAverageHeight,usingModeHeight,usingBaseOfSupport,usingAverageHeadPosition); + +// declare the html slider constructor +function AppProperty(name, type, eventType, signalType, setFunction, initValue, convertToThreshold, convertToSlider, signalOn) { + this.name = name; + this.type = type; + this.eventType = eventType; + this.signalType = signalType; + this.setValue = setFunction; + this.value = initValue; + this.get = function () { + return this.value; + }; + this.convertToThreshold = convertToThreshold; + this.convertToSlider = convertToSlider; + this.signalOn = signalOn; +} + +// define the sliders +var frontBaseProperty = new AppProperty("#anteriorBase-slider", "slider", "onAnteriorBaseSlider", "frontSignal", + setAnteriorDistance, DEFAULT_ANTERIOR, function (num) { + return convertToMeters(num); + }, function (num) { + return convertToCentimeters(num); + },true); +var backBaseProperty = new AppProperty("#posteriorBase-slider", "slider", "onPosteriorBaseSlider", "backSignal", + setPosteriorDistance, DEFAULT_POSTERIOR, function (num) { + return convertToMeters(num); + }, function (num) { + return convertToCentimeters(num); + }, true); +var lateralBaseProperty = new AppProperty("#lateralBase-slider", "slider", "onLateralBaseSlider", "lateralSignal", + setLateralDistance, DEFAULT_LATERAL, function (num) { + return convertToMeters(num); + }, function (num) { + return convertToCentimeters(num); + }, true); +var headAngularVelocityProperty = new AppProperty("#angularVelocityHead-slider", "slider", "onAngularVelocitySlider", + "angularHeadSignal", setAngularThreshold, DEFAULT_ANGULAR_VELOCITY, function (num) { + var base = 4; + var shift = 2; + return convertExponential(base, num, DECREASING, shift); + }, function (num) { + var base = 4; + var shift = 2; + return convertLog(base, num, DECREASING, shift); + }, true); +var heightDifferenceProperty = new AppProperty("#heightDifference-slider", "slider", "onHeightDifferenceSlider", "heightSignal", + setHeightThreshold, DEFAULT_HEIGHT_DIFFERENCE, function (num) { + return convertToMeters(-num); + }, function (num) { + return convertToCentimeters(-num); + }, true); +var handsVelocityProperty = new AppProperty("#handsVelocity-slider", "slider", "onHandsVelocitySlider", "handVelocitySignal", + setHandVelocityThreshold, DEFAULT_HAND_VELOCITY, function (num) { + return num; + }, function (num) { + return num; + }, true); +var handsAngularVelocityProperty = new AppProperty("#handsAngularVelocity-slider", "slider", "onHandsAngularVelocitySlider", + "handAngularSignal", setHandAngularVelocityThreshold, DEFAULT_ANGULAR_HAND_VELOCITY, function (num) { + var base = 7; + var shift = 2; + return convertExponential(base, num, DECREASING, shift); + }, function (num) { + var base = 7; + var shift = 2; + return convertLog(base, num, DECREASING, shift); + }, true); +var headVelocityProperty = new AppProperty("#headVelocity-slider", "slider", "onHeadVelocitySlider", "headVelocitySignal", + setHeadVelocityThreshold, DEFAULT_HEAD_VELOCITY, function (num) { + var base = 2; + var shift = 0; + return convertExponential(base, num, INCREASING, shift); + }, function (num) { + var base = 2; + var shift = 0; + return convertLog(base, num, INCREASING, shift); + }, true); +var headPitchProperty = new AppProperty("#headPitch-slider", "slider", "onHeadPitchSlider", "headPitchSignal", + setHeadPitchThreshold, DEFAULT_LEVEL_PITCH, function (num) { + var base = 2.5; + var shift = 5; + return convertExponential(base, num, DECREASING, shift); + }, function (num) { + var base = 2.5; + var shift = 5; + return convertLog(base, num, DECREASING, shift); + }, true); +var headRollProperty = new AppProperty("#headRoll-slider", "slider", "onHeadRollSlider", "headRollSignal", setHeadRollThreshold, + DEFAULT_LEVEL_ROLL, function (num) { + var base = 2.5; + var shift = 5; + return convertExponential(base, num, DECREASING, shift); + }, function (num) { + var base = 2.5; + var shift = 5; + return convertLog(base, num, DECREASING, shift); + }, true); + +var propArray = new Array(frontBaseProperty, backBaseProperty, lateralBaseProperty, headAngularVelocityProperty, + heightDifferenceProperty, handsVelocityProperty, handsAngularVelocityProperty, headVelocityProperty, headPitchProperty, + headRollProperty); + +// var HTML_URL = Script.resolvePath("http://hifi-content.s3.amazonaws.com/angus/stepApp/stepApp.html"); +var HTML_URL = Script.resolvePath("http://hifi-content.s3.amazonaws.com/angus/stepApp/stepAppExtra.html"); +var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + +function manageClick() { + if (activated) { + tablet.gotoHomeScreen(); + } else { + tablet.gotoWebScreen(HTML_URL); + } +} + +var tabletButton = tablet.addButton({ + text: TABLET_BUTTON_NAME, + icon: Script.resolvePath("http://hifi-content.s3.amazonaws.com/angus/stepApp/foot.svg"), + activeIcon: Script.resolvePath("http://hifi-content.s3.amazonaws.com/angus/stepApp/foot.svg") +}); + +function drawBase() { + // transform corners into world space, for rendering. + var worldPointLf = Vec3.sum(MyAvatar.position,Vec3.multiplyQbyV(MyAvatar.orientation, frontLeft)); + var worldPointRf = Vec3.sum(MyAvatar.position,Vec3.multiplyQbyV(MyAvatar.orientation, frontRight)); + var worldPointLb = Vec3.sum(MyAvatar.position,Vec3.multiplyQbyV(MyAvatar.orientation, backLeft)); + var worldPointRb = Vec3.sum(MyAvatar.position,Vec3.multiplyQbyV(MyAvatar.orientation, backRight)); + + var GREEN = { r: 0, g: 1, b: 0, a: 1 }; + // draw border + DebugDraw.drawRay(worldPointLf, worldPointRf, GREEN); + DebugDraw.drawRay(worldPointRf, worldPointRb, GREEN); + DebugDraw.drawRay(worldPointRb, worldPointLb, GREEN); + DebugDraw.drawRay(worldPointLb, worldPointLf, GREEN); +} + +function onKeyPress(event) { + if (event.text === "'") { + // when the sensors are reset, then reset the mode. + RESET_MODE = false; + } +} + +function onWebEventReceived(msg) { + var message = JSON.parse(msg); + print(" we have a message from html dialog " + message.type); + propArray.forEach(function (prop) { + if (prop.eventType === message.type) { + prop.setValue(prop.convertToThreshold(message.data.value)); + print("message from " + prop.name); + // break; + } + }); + checkBoxArray.forEach(function(cbox) { + if (cbox.eventType === message.type) { + cbox.data.value = message.data.value; + // break; + } + }); + if (message.type === "onCreateStepApp") { + print("document loaded"); + documentLoaded = true; + Script.setTimeout(initAppForm, LOADING_DELAY); + } +} + +function initAppForm() { + print("step app is loaded: " + documentLoaded); + if (documentLoaded === true) { + propArray.forEach(function (prop) { + tablet.emitScriptEvent(JSON.stringify({ + "type": "trigger", + "id": prop.signalType, + "data": { "value": "green" } + })); + tablet.emitScriptEvent(JSON.stringify({ + "type": "slider", + "id": prop.name, + "data": { "value": prop.convertToSlider(prop.value) } + })); + }); + checkBoxArray.forEach(function (cbox) { + tablet.emitScriptEvent(JSON.stringify({ + "type": "checkboxtick", + "id": cbox.id, + "data": { "value": cbox.data.value } + })); + }); + } +} + +function updateSignalColors() { + + // force the updates by running the threshold comparisons + withinBaseOfSupport(currentStateReadings.headPose.translation); + withinThresholdOfStandingHeightMode(currentStateReadings.diffFromMode); + headAngularVelocityBelowThreshold(currentStateReadings.headPose.angularVelocity); + handDirectionMatchesHeadDirection(currentStateReadings.lhandPose, currentStateReadings.rhandPose); + handAngularVelocityBelowThreshold(currentStateReadings.lhandPose, currentStateReadings.rhandPose); + headVelocityGreaterThanThreshold(Vec3.length(currentStateReadings.headPose.velocity)); + headMovedAwayFromAveragePosition(currentStateReadings.diffFromAveragePosition); + headLowerThanHeightAverage(currentStateReadings.diffFromAverageHeight); + isHeadLevel(currentStateReadings.diffFromAverageEulers); + + propArray.forEach(function (prop) { + if (prop.signalOn) { + tablet.emitScriptEvent(JSON.stringify({ "type": "trigger", "id": prop.signalType, "data": { "value": "green" } })); + } else { + tablet.emitScriptEvent(JSON.stringify({ "type": "trigger", "id": prop.signalType, "data": { "value": "red" } })); + } + }); +} + +function onScreenChanged(type, url) { + print("Screen changed"); + if (type === "Web" && url === HTML_URL) { + if (!activated) { + // hook up to event bridge + tablet.webEventReceived.connect(onWebEventReceived); + print("after connect web event"); + MyAvatar.hmdLeanRecenterEnabled = false; + + } + activated = true; + } else { + if (activated) { + // disconnect from event bridge + tablet.webEventReceived.disconnect(onWebEventReceived); + documentLoaded = false; + } + activated = false; + } +} + +function getLog(x, y) { + return Math.log(y) / Math.log(x); +} + +function noConversion(num) { + return num; +} + +function convertLog(base, num, direction, shift) { + return direction * getLog(base, (num + 1.0)) + shift; +} + +function convertExponential(base, num, direction, shift) { + return Math.pow(base, (direction*num + shift)) - 1.0; +} + +function convertToCentimeters(num) { + return num * CENTIMETERSPERMETER; +} + +function convertToMeters(num) { + print("convert to meters " + num); + return num / CENTIMETERSPERMETER; +} + +function isInsideLine(a, b, c) { + return (((b.x - a.x)*(c.z - a.z) - (b.z - a.z)*(c.x - a.x)) > 0); +} + +function setAngularThreshold(num) { + headAngularVelocityProperty.value = num; + print("angular threshold " + headAngularVelocityProperty.get()); +} + +function setHeadRollThreshold(num) { + headRollProperty.value = num; + print("head roll threshold " + headRollProperty.get()); +} + +function setHeadPitchThreshold(num) { + headPitchProperty.value = num; + print("head pitch threshold " + headPitchProperty.get()); +} + +function setHeightThreshold(num) { + heightDifferenceProperty.value = num; + print("height threshold " + heightDifferenceProperty.get()); +} + +function setLateralDistance(num) { + lateralBaseProperty.value = num; + frontLeft.x = -lateralBaseProperty.get(); + frontRight.x = lateralBaseProperty.get(); + backLeft.x = -lateralBaseProperty.get(); + backRight.x = lateralBaseProperty.get(); + print("lateral distance " + lateralBaseProperty.get()); +} + +function setAnteriorDistance(num) { + frontBaseProperty.value = num; + frontLeft.z = -frontBaseProperty.get(); + frontRight.z = -frontBaseProperty.get(); + print("anterior distance " + frontBaseProperty.get()); +} + +function setPosteriorDistance(num) { + backBaseProperty.value = num; + backLeft.z = backBaseProperty.get(); + backRight.z = backBaseProperty.get(); + print("posterior distance " + backBaseProperty.get()); +} + +function setHandAngularVelocityThreshold(num) { + handsAngularVelocityProperty.value = num; + print("hand angular velocity threshold " + handsAngularVelocityProperty.get()); +} + +function setHandVelocityThreshold(num) { + handsVelocityProperty.value = num; + print("hand velocity threshold " + handsVelocityProperty.get()); +} + +function setHeadVelocityThreshold(num) { + headVelocityProperty.value = num; + print("headvelocity threshold " + headVelocityProperty.get()); +} + +function withinBaseOfSupport(pos) { + var userScale = 1.0; + frontBaseProperty.signalOn = !(isInsideLine(Vec3.multiply(userScale, frontLeft), Vec3.multiply(userScale, frontRight), pos)); + backBaseProperty.signalOn = !(isInsideLine(Vec3.multiply(userScale, backRight), Vec3.multiply(userScale, backLeft), pos)); + lateralBaseProperty.signalOn = !(isInsideLine(Vec3.multiply(userScale, frontRight), Vec3.multiply(userScale, backRight), pos) + && isInsideLine(Vec3.multiply(userScale, backLeft), Vec3.multiply(userScale, frontLeft), pos)); + return (!frontBaseProperty.signalOn && !backBaseProperty.signalOn && !lateralBaseProperty.signalOn); +} + +function withinThresholdOfStandingHeightMode(heightDiff) { + if (usingModeHeight.data.value) { + heightDifferenceProperty.signalOn = heightDiff < heightDifferenceProperty.get(); + return heightDifferenceProperty.signalOn; + } else { + return true; + } +} + +function headAngularVelocityBelowThreshold(headAngularVelocity) { + var angVel = Vec3.length({ x: headAngularVelocity.x, y: 0, z: headAngularVelocity.z }); + headAngularVelocityProperty.signalOn = angVel < headAngularVelocityProperty.get(); + return headAngularVelocityProperty.signalOn; +} + +function handDirectionMatchesHeadDirection(lhPose, rhPose) { + handsVelocityProperty.signalOn = ((handsVelocityProperty.get() < NO_SHARED_DIRECTION) || + ((!lhPose.valid || ((handDotHead[LEFT] > handsVelocityProperty.get()) && + (Vec3.length(lhPose.velocity) > VELOCITY_EPSILON))) && + (!rhPose.valid || ((handDotHead[RIGHT] > handsVelocityProperty.get()) && + (Vec3.length(rhPose.velocity) > VELOCITY_EPSILON))))); + return handsVelocityProperty.signalOn; +} + +function handAngularVelocityBelowThreshold(lhPose, rhPose) { + var xzRHandAngularVelocity = Vec3.length({ x: rhPose.angularVelocity.x, y: 0.0, z: rhPose.angularVelocity.z }); + var xzLHandAngularVelocity = Vec3.length({ x: lhPose.angularVelocity.x, y: 0.0, z: lhPose.angularVelocity.z }); + handsAngularVelocityProperty.signalOn = ((!rhPose.valid ||(xzRHandAngularVelocity < handsAngularVelocityProperty.get())) + && (!lhPose.valid || (xzLHandAngularVelocity < handsAngularVelocityProperty.get()))); + return handsAngularVelocityProperty.signalOn; +} + +function headVelocityGreaterThanThreshold(headVel) { + headVelocityProperty.signalOn = (headVel > headVelocityProperty.get()) || (headVelocityProperty.get() < VELOCITY_EPSILON); + return headVelocityProperty.signalOn; +} + +function headMovedAwayFromAveragePosition(headDelta) { + return !withinBaseOfSupport(headDelta) || !usingAverageHeadPosition.data.value; +} + +function headLowerThanHeightAverage(heightDiff) { + if (usingAverageHeight.data.value) { + print("head lower than height average"); + heightDifferenceProperty.signalOn = heightDiff < heightDifferenceProperty.get(); + return heightDifferenceProperty.signalOn; + } else { + return true; + } +} + +function isHeadLevel(diffEulers) { + headRollProperty.signalOn = Math.abs(diffEulers.z) < headRollProperty.get(); + headPitchProperty.signalOn = Math.abs(diffEulers.x) < headPitchProperty.get(); + return (headRollProperty.signalOn && headPitchProperty.signalOn); +} + +function findAverage(arr) { + var sum = arr.reduce(function (acc, val) { + return acc + val; + },0); + return sum / arr.length; +} + +function addToModeArray(arr,num) { + for (var i = 0 ;i < (arr.length - 1); i++) { + arr[i] = arr[i+1]; + } + arr[arr.length - 1] = (Math.floor(num*CENTIMETERSPERMETER))/CENTIMETERSPERMETER; +} + +function findMode(ary, currentMode, backLength, defaultBack, currentHeight) { + var numMapping = {}; + var greatestFreq = 0; + var mode; + ary.forEach(function (number) { + numMapping[number] = (numMapping[number] || 0) + 1; + if ((greatestFreq < numMapping[number]) || ((numMapping[number] === MODE_SAMPLE_LENGTH) && (number > currentMode) )) { + greatestFreq = numMapping[number]; + mode = number; + } + }); + if (mode > currentMode) { + return Number(mode); + } else { + if (!RESET_MODE && HMD.active) { + print("resetting the mode............................................. "); + print("resetting the mode............................................. "); + RESET_MODE = true; + var correction = 0.02; + return currentHeight - correction; + } else { + return currentMode; + } + } +} + +function update(dt) { + if (debugDrawBase) { + drawBase(); + } + // Update current state information + currentStateReadings.headPose = Controller.getPoseValue(Controller.Standard.Head); + currentStateReadings.rhandPose = Controller.getPoseValue(Controller.Standard.RightHand); + currentStateReadings.lhandPose = Controller.getPoseValue(Controller.Standard.LeftHand); + + // back length + var headMinusHipLean = Vec3.subtract(currentStateReadings.headPose.translation, DEFAULT_HIPS_POSITION); + currentStateReadings.backLength = Vec3.length(headMinusHipLean); + // print("back length and default " + currentStateReadings.backLength + " " + DEFAULT_TORSO_LENGTH); + + // mode height + addToModeArray(modeArray, currentStateReadings.headPose.translation.y); + modeHeight = findMode(modeArray, modeHeight, currentStateReadings.backLength, DEFAULT_TORSO_LENGTH, + currentStateReadings.headPose.translation.y); + currentStateReadings.diffFromMode = modeHeight - currentStateReadings.headPose.translation.y; + + // hand direction + var leftHandLateralPoseVelocity = currentStateReadings.lhandPose.velocity; + leftHandLateralPoseVelocity.y = 0.0; + var rightHandLateralPoseVelocity = currentStateReadings.rhandPose.velocity; + rightHandLateralPoseVelocity.y = 0.0; + var headLateralPoseVelocity = currentStateReadings.headPose.velocity; + headLateralPoseVelocity.y = 0.0; + handDotHead[LEFT] = Vec3.dot(Vec3.normalize(leftHandLateralPoseVelocity), Vec3.normalize(headLateralPoseVelocity)); + handDotHead[RIGHT] = Vec3.dot(Vec3.normalize(rightHandLateralPoseVelocity), Vec3.normalize(headLateralPoseVelocity)); + + // average head position + headAveragePosition = Vec3.mix(headAveragePosition, currentStateReadings.headPose.translation, AVERAGING_RATE); + currentStateReadings.diffFromAveragePosition = Vec3.subtract(currentStateReadings.headPose.translation, + headAveragePosition); + + // average height + averageHeight = currentStateReadings.headPose.translation.y * HEIGHT_AVERAGING_RATE + + averageHeight * (1.0 - HEIGHT_AVERAGING_RATE); + currentStateReadings.diffFromAverageHeight = Math.abs(currentStateReadings.headPose.translation.y - averageHeight); + + // eulers diff + headEulers = Quat.safeEulerAngles(currentStateReadings.headPose.rotation); + headAverageOrientation = Quat.slerp(headAverageOrientation, currentStateReadings.headPose.rotation, AVERAGING_RATE); + headAverageEulers = Quat.safeEulerAngles(headAverageOrientation); + currentStateReadings.diffFromAverageEulers = Vec3.subtract(headAverageEulers, headEulers); + + // headpose rig space is for determining when to recenter rotation. + var headPoseRigSpace = Quat.multiply(CHANGE_OF_BASIS_ROTATION, currentStateReadings.headPose.rotation); + headPoseAverageOrientation = Quat.slerp(headPoseAverageOrientation, headPoseRigSpace, AVERAGING_RATE); + var headPoseAverageEulers = Quat.safeEulerAngles(headPoseAverageOrientation); + + // make the signal colors reflect the current thresholds that have been crossed + updateSignalColors(); + + SPINE_STRETCH_LIMIT = (0.04) * DEFAULT_TORSO_LENGTH * MyAvatar.scale; + + //print("the spine stretch limit is " + SPINE_STRETCH_LIMIT + " head avatar space is " + currentStateReadings.headPose.translation.y); + //print("the current back length is " + currentStateReadings.backLength + " " + DEFAULT_TORSO_LENGTH); + // Conditions for taking a step. + // 1. off the base of support. front, lateral, back edges. + // 2. head is not lower than the height mode value by more than the maxHeightChange tolerance + // 3. the angular velocity of the head is not greater than the threshold value + // ie this reflects the speed the head is rotating away from having up = (0,1,0) in Avatar frame.. + // 4. the hands velocity vector has the same direction as the head, within the given tolerance + // the tolerance is an acos value, -1 means the hands going in any direction will not block translating + // up to 1 where the hands velocity direction must exactly match that of the head. -1 threshold disables this condition. + // 5. the angular velocity xz magnitude for each hand is below the threshold value + // ie here this reflects the speed that each hand is rotating away from having up = (0,1,0) in Avatar frame. + // 6. head velocity is below step threshold + // 7. head has moved further than the threshold from the running average position of the head. + // 8. head height is not lower than the running average head height with a difference of maxHeightChange. + // 9. head's rotation in avatar space is not pitching or rolling greater than the pitch or roll thresholds + if (!withinBaseOfSupport(currentStateReadings.headPose.translation) && + withinThresholdOfStandingHeightMode(currentStateReadings.diffFromMode) && + headAngularVelocityBelowThreshold(currentStateReadings.headPose.angularVelocity) && + handDirectionMatchesHeadDirection(currentStateReadings.lhandPose, currentStateReadings.rhandPose) && + handAngularVelocityBelowThreshold(currentStateReadings.lhandPose, currentStateReadings.rhandPose) && + headVelocityGreaterThanThreshold(Vec3.length(currentStateReadings.headPose.velocity)) && + headMovedAwayFromAveragePosition(currentStateReadings.diffFromAveragePosition) && + headLowerThanHeightAverage(currentStateReadings.diffFromAverageHeight) && + isHeadLevel(currentStateReadings.diffFromAverageEulers)) { + + if (stepTimer < 0.0) { //!MyAvatar.isRecenteringHorizontally() + print("trigger recenter========================================================"); + MyAvatar.triggerHorizontalRecenter(); + stepTimer = STEP_TIME_SECS; + } + } else if ((currentStateReadings.backLength > (DEFAULT_TORSO_LENGTH + SPINE_STRETCH_LIMIT)) && + (failsafeSignalTimer < 0.0) && HMD.active) { + // do the failsafe recenter. + // failsafeFlag stops repeated setting of failsafe button color. + // RESET_MODE false forces a reset of the height + RESET_MODE = false; + failsafeFlag = true; + failsafeSignalTimer = FAILSAFE_TIMEOUT; + MyAvatar.triggerHorizontalRecenter(); + tablet.emitScriptEvent(JSON.stringify({ "type": "failsafe", "id": "failsafeSignal", "data": { "value": "green" } })); + // in fail safe we debug print the values that were blocking us. + print("failsafe debug---------------------------------------------------------------"); + propArray.forEach(function (prop) { + print(prop.name); + if (!prop.signalOn) { + print(prop.signalType + " contributed to failsafe call"); + } + }); + print("end failsafe debug---------------------------------------------------------------"); + + } + + if ((failsafeSignalTimer < 0.0) && failsafeFlag) { + failsafeFlag = false; + tablet.emitScriptEvent(JSON.stringify({ "type": "failsafe", "id": "failsafeSignal", "data": { "value": "orange" } })); + } + + stepTimer -= dt; + failsafeSignalTimer -= dt; + + if (!HMD.active) { + RESET_MODE = false; + } + + if (Math.abs(headPoseAverageEulers.y) > HEAD_TURN_THRESHOLD) { + // Turn feet + // MyAvatar.triggerRotationRecenter(); + // headPoseAverageOrientation = { x: 0, y: 0, z: 0, w: 1 }; + } +} + +function shutdownTabletApp() { + // GlobalDebugger.stop(); + tablet.removeButton(tabletButton); + if (activated) { + tablet.webEventReceived.disconnect(onWebEventReceived); + tablet.gotoHomeScreen(); + } + tablet.screenChanged.disconnect(onScreenChanged); +} + +tabletButton.clicked.connect(manageClick); +tablet.screenChanged.connect(onScreenChanged); + +Script.setTimeout(function() { + DEFAULT_HIPS_POSITION = MyAvatar.getAbsoluteDefaultJointTranslationInObjectFrame(MyAvatar.getJointIndex("Hips")); + DEFAULT_HEAD_POSITION = MyAvatar.getAbsoluteDefaultJointTranslationInObjectFrame(MyAvatar.getJointIndex("Head")); + DEFAULT_TORSO_LENGTH = Vec3.length(Vec3.subtract(DEFAULT_HEAD_POSITION, DEFAULT_HIPS_POSITION)); + SPINE_STRETCH_LIMIT = (0.04) * DEFAULT_TORSO_LENGTH * MyAvatar.scale; +},(4*LOADING_DELAY)); + +Script.update.connect(update); +Controller.keyPressEvent.connect(onKeyPress); +Script.scriptEnding.connect(function () { + MyAvatar.hmdLeanRecenterEnabled = true; + Script.update.disconnect(update); + shutdownTabletApp(); +}); diff --git a/scripts/system/avatarapp.js b/scripts/system/avatarapp.js index 10ccb66d96..ee4c6736a2 100644 --- a/scripts/system/avatarapp.js +++ b/scripts/system/avatarapp.js @@ -63,7 +63,8 @@ function getMyAvatar() { function getMyAvatarSettings() { return { dominantHand: MyAvatar.getDominantHand(), - collisionsEnabled : MyAvatar.getCollisionsEnabled(), + collisionsEnabled: MyAvatar.getCollisionsEnabled(), + sittingEnabled: MyAvatar.isInSittingState, collisionSoundUrl : MyAvatar.collisionSoundURL, animGraphUrl: MyAvatar.getAnimGraphUrl(), animGraphOverrideUrl : MyAvatar.getAnimGraphOverrideUrl(), @@ -136,6 +137,13 @@ function onCollisionsEnabledChanged(enabled) { } } +function onSittingEnabledChanged(isSitting) { + if (currentAvatarSettings.sittingEnabled !== isSitting) { + currentAvatarSettings.sittingEnabled = isSitting; + sendToQml({ 'method': 'settingChanged', 'name': 'sittingEnabled', 'value': isSitting }) + } +} + function onNewCollisionSoundUrl(url) { if(currentAvatarSettings.collisionSoundUrl !== url) { currentAvatarSettings.collisionSoundUrl = url; @@ -314,9 +322,10 @@ function fromQml(message) { // messages are {method, params}, like json-rpc. See MyAvatar.setDominantHand(message.settings.dominantHand); MyAvatar.setCollisionsEnabled(message.settings.collisionsEnabled); + MyAvatar.isInSittingState = message.settings.sittingEnabled; MyAvatar.collisionSoundURL = message.settings.collisionSoundUrl; MyAvatar.setAnimGraphOverrideUrl(message.settings.animGraphOverrideUrl); - + print("save settings"); settings = getMyAvatarSettings(); break; default: @@ -507,6 +516,7 @@ function off() { MyAvatar.skeletonModelURLChanged.disconnect(onSkeletonModelURLChanged); MyAvatar.dominantHandChanged.disconnect(onDominantHandChanged); MyAvatar.collisionsEnabledChanged.disconnect(onCollisionsEnabledChanged); + MyAvatar.sittingEnabledChanged.disconnect(onSittingEnabledChanged); MyAvatar.newCollisionSoundURL.disconnect(onNewCollisionSoundUrl); MyAvatar.animGraphUrlChanged.disconnect(onAnimGraphUrlChanged); MyAvatar.targetScaleChanged.disconnect(onTargetScaleChanged); @@ -521,6 +531,7 @@ function on() { MyAvatar.skeletonModelURLChanged.connect(onSkeletonModelURLChanged); MyAvatar.dominantHandChanged.connect(onDominantHandChanged); MyAvatar.collisionsEnabledChanged.connect(onCollisionsEnabledChanged); + MyAvatar.sittingEnabledChanged.connect(onSittingEnabledChanged); MyAvatar.newCollisionSoundURL.connect(onNewCollisionSoundUrl); MyAvatar.animGraphUrlChanged.connect(onAnimGraphUrlChanged); MyAvatar.targetScaleChanged.connect(onTargetScaleChanged); From 42cb8a7ef0159f130c65d6a424bf8b54ae14323e Mon Sep 17 00:00:00 2001 From: amantley Date: Thu, 27 Sep 2018 16:59:54 -0700 Subject: [PATCH 08/54] avatar app changes --- interface/src/avatar/MyAvatar.cpp | 2 +- scripts/system/avatarapp.js | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 631a4b0670..d54616f245 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -477,7 +477,7 @@ void MyAvatar::update(float deltaTime) { auto sensorHeadPoseDebug = getControllerPoseInSensorFrame(controller::Action::HEAD); glm::vec3 upHead = transformVectorFast(sensorHeadPoseDebug.getMatrix(), glm::vec3(0.0f, 1.0f, 0.0f)); float acosHead = glm::dot(upHead, glm::vec3(0.0f, 1.0f, 0.0f)); - // qCDebug(interfaceapp) << "sensor space head pos " << sensorHeadPoseDebug.getTranslation().y; + // qCDebug(interfaceapp) << "sensor space head pos " << sensorHeadPoseDebug.getTranslation().y; if ((acosHead > 0.98f) && !getIsInSittingState() && (sensorHeadPoseDebug.getTranslation().y < -0.5f)) { //qCDebug(interfaceapp) << "we are going to sitting state because it looks like we should" << sensorHeadPoseDebug.getTranslation().y; } diff --git a/scripts/system/avatarapp.js b/scripts/system/avatarapp.js index ee4c6736a2..16761f29a6 100644 --- a/scripts/system/avatarapp.js +++ b/scripts/system/avatarapp.js @@ -140,6 +140,7 @@ function onCollisionsEnabledChanged(enabled) { function onSittingEnabledChanged(isSitting) { if (currentAvatarSettings.sittingEnabled !== isSitting) { currentAvatarSettings.sittingEnabled = isSitting; + print("emit sitting changed"); sendToQml({ 'method': 'settingChanged', 'name': 'sittingEnabled', 'value': isSitting }) } } From 884ad66a146541fba08975af43e8cbfe1e46cd16 Mon Sep 17 00:00:00 2001 From: amantley Date: Fri, 28 Sep 2018 17:18:24 -0700 Subject: [PATCH 09/54] added sensor space detection of height of the user in MyAvatar.cpp 1.2 * average sensor space height changes to standing. .833 sensorspace height changes to sitting. there is also a manual override in the avatar app settings now --- interface/src/avatar/MyAvatar.cpp | 38 +++++++++++++++++++++++++------ interface/src/avatar/MyAvatar.h | 4 +++- 2 files changed, 34 insertions(+), 8 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index d54616f245..819778b1e7 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -475,6 +475,12 @@ void MyAvatar::update(float deltaTime) { // if the head is close to the floor in sensor space // and the up of the head is close to sensor up then try switching us to sitting state. auto sensorHeadPoseDebug = getControllerPoseInSensorFrame(controller::Action::HEAD); + if (sensorHeadPoseDebug.isValid()) { + _sumUserHeightSensorSpace += sensorHeadPoseDebug.getTranslation().y; + _averageUserHeightCount++; + } + qCDebug(interfaceapp) << sensorHeadPoseDebug.isValid() << " valid. sensor space average " << (_sumUserHeightSensorSpace / _averageUserHeightCount) << " head position sensor y value " << sensorHeadPoseDebug.getTranslation().y; + glm::vec3 upHead = transformVectorFast(sensorHeadPoseDebug.getMatrix(), glm::vec3(0.0f, 1.0f, 0.0f)); float acosHead = glm::dot(upHead, glm::vec3(0.0f, 1.0f, 0.0f)); // qCDebug(interfaceapp) << "sensor space head pos " << sensorHeadPoseDebug.getTranslation().y; @@ -3854,6 +3860,9 @@ void MyAvatar::setIsInWalkingState(bool isWalking) { void MyAvatar::setIsInSittingState(bool isSitting) { _isInSittingState = isSitting; + controller::Pose sensorHeadPoseDebug = getControllerPoseInSensorFrame(controller::Action::HEAD); + _sumUserHeightSensorSpace = sensorHeadPoseDebug.getTranslation().y; + _averageUserHeightCount = 1; emit sittingEnabledChanged(isSitting); } @@ -4093,21 +4102,36 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(MyAvatar& myAvatar, const gl glm::vec3 headWorldSpace = myAvatar.getHead()->getPosition(); glm::mat4 worldToSensorMatrix = glm::inverse(myAvatar.getSensorToWorldMatrix()); glm::vec3 headSensorSpace = transformVectorFast(myAvatar.getSensorToWorldMatrix(), headWorldSpace); - //qCDebug(interfaceapp) << "sensor space position " << extractTranslation(currentBodyMatrix) << " head position sensor " << sensorHeadPose.getTranslation(); + //get the mode. + //put it in sensor space. + // if we are 20% higher switch to standing. + // 16.6% lower then switch to sitting. + // add this !!!! And the head is upright. + float averageSensorSpaceHeight = myAvatar._sumUserHeightSensorSpace / myAvatar._averageUserHeightCount; if (myAvatar.getIsInSittingState()) { if (offset.y < SITTING_BOTTOM) { // we recenter when sitting. return true; - } else if (offset.y > 2.0*CYLINDER_TOP) { + } else if (sensorHeadPose.getTranslation().y > (1.2f * averageSensorSpaceHeight)) { // if we recenter upwards then no longer in sitting state myAvatar.setIsInSittingState(false); + //myAvatar._sumUserHeightSensorSpace = 1.2f * averageSensorSpaceHeight; + // myAvatar._averageUserHeightCount = 1; return true; } else { return false; } } else { - return (offset.y > CYLINDER_TOP) || (offset.y < CYLINDER_BOTTOM); + // in the standing state + if (sensorHeadPose.getTranslation().y < (0.83f * averageSensorSpaceHeight)) { + myAvatar.setIsInSittingState(true); + // myAvatar._sumUserHeightSensorSpace = 0.83f * averageSensorSpaceHeight; + // myAvatar._averageUserHeightCount = 1; + return true; + } else { + return (offset.y > CYLINDER_TOP) || (offset.y < CYLINDER_BOTTOM); + } } } @@ -4124,14 +4148,14 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat if ((_squatCount > 600) && !isActive(Vertical) && !isActive(Horizontal)) { if (myAvatar.getIsInSittingState()) { // activate(Horizontal); - activate(Vertical); + //activate(Vertical); _squatCount = 0; } else { if (myAvatar.getControllerPoseInAvatarFrame(controller::Action::HEAD).getTranslation().y < (headDefaultPos.y - 0.20f)) { - myAvatar.setIsInSittingState(true); - activate(Vertical); + //myAvatar.setIsInSittingState(true); + //activate(Vertical); } else { - activate(Horizontal); + //activate(Horizontal); } _squatCount = 0; } diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index d9744e93fe..628c358202 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -1805,6 +1805,8 @@ private: // height of user in sensor space, when standing erect. ThreadSafeValueCache _userHeight { DEFAULT_AVATAR_HEIGHT }; + float _sumUserHeightSensorSpace { DEFAULT_AVATAR_HEIGHT }; + int _averageUserHeightCount { 1 }; void updateChildCauterization(SpatiallyNestablePointer object, bool cauterize); @@ -1814,7 +1816,7 @@ private: ThreadSafeValueCache _sprintSpeed { AVATAR_SPRINT_SPEED_SCALAR }; float _walkSpeedScalar { AVATAR_WALK_SPEED_SCALAR }; bool _isInWalkingState { false }; - bool _isInSittingState { true }; + bool _isInSittingState { false }; // load avatar scripts once when rig is ready bool _shouldLoadScripts { false }; From 3a2a8fe4f8d4dfa7eb965fa4dff59d2914b207d3 Mon Sep 17 00:00:00 2001 From: amantley Date: Sat, 29 Sep 2018 15:49:11 -0700 Subject: [PATCH 10/54] adjusted openvr to use 0.0 for the floor instead of -1.6 --- plugins/openvr/src/OpenVrDisplayPlugin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/openvr/src/OpenVrDisplayPlugin.cpp b/plugins/openvr/src/OpenVrDisplayPlugin.cpp index fae2144caf..1638a17631 100644 --- a/plugins/openvr/src/OpenVrDisplayPlugin.cpp +++ b/plugins/openvr/src/OpenVrDisplayPlugin.cpp @@ -463,7 +463,7 @@ bool OpenVrDisplayPlugin::internalActivate() { auto chaperone = vr::VRChaperone(); if (chaperone) { float const UI_RADIUS = 1.0f; - float const UI_HEIGHT = 1.6f; + float const UI_HEIGHT = 0.0f; float const UI_Z_OFFSET = 0.5; float xSize, zSize; From 9e400459270ad90fd896d75025ca7cf5c60a109d Mon Sep 17 00:00:00 2001 From: amantley Date: Sun, 30 Sep 2018 17:13:34 -0700 Subject: [PATCH 11/54] added criteria to stop false positive for sit down --- interface/src/avatar/MyAvatar.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 02ea49cda0..f281d8c87d 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -4079,13 +4079,21 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(MyAvatar& myAvatar, const gl // if we are 20% higher switch to standing. // 16.6% lower then switch to sitting. // add this !!!! And the head is upright. + glm::vec3 upHead = transformVectorFast(sensorHeadPose.getMatrix(), glm::vec3(0.0f, 1.0f, 0.0f)); + float acosHead = glm::dot(upHead, glm::vec3(0.0f, 1.0f, 0.0f)); + glm::vec3 avatarHips = myAvatar.getAbsoluteJointTranslationInObjectFrame(myAvatar.getJointIndex("Hips")); + glm::vec3 worldHips = transformVectorFast(myAvatar.getTransform().getMatrix(),avatarHips); + glm::vec3 sensorHips = transformVectorFast(myAvatar.getSensorToWorldMatrix(), worldHips); float averageSensorSpaceHeight = myAvatar._sumUserHeightSensorSpace / myAvatar._averageUserHeightCount; + // we could add a counting here to make sure that a lean forward doesn't accidentally put you in sitting mode. + // but maybe so what. + // the real test is... can I pick something up in standing mode? if (myAvatar.getIsInSittingState()) { if (offset.y < SITTING_BOTTOM) { // we recenter when sitting. return true; - } else if (sensorHeadPose.getTranslation().y > (1.2f * averageSensorSpaceHeight)) { + } else if (sensorHeadPose.getTranslation().y > (1.2f * averageSensorSpaceHeight)) { // if we recenter upwards then no longer in sitting state myAvatar.setIsInSittingState(false); //myAvatar._sumUserHeightSensorSpace = 1.2f * averageSensorSpaceHeight; @@ -4096,7 +4104,7 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(MyAvatar& myAvatar, const gl } } else { // in the standing state - if (sensorHeadPose.getTranslation().y < (0.83f * averageSensorSpaceHeight)) { + if ((sensorHeadPose.getTranslation().y < (0.83f * averageSensorSpaceHeight)) && (acosHead > 0.98f) && !(sensorHips.y > (0.4f * averageSensorSpaceHeight)) { myAvatar.setIsInSittingState(true); // myAvatar._sumUserHeightSensorSpace = 0.83f * averageSensorSpaceHeight; // myAvatar._averageUserHeightCount = 1; From fe7c14e5cf3523beb1be9cb1d5b0feb23188deb5 Mon Sep 17 00:00:00 2001 From: amantley Date: Sun, 30 Sep 2018 17:15:07 -0700 Subject: [PATCH 12/54] removed extraneous script --- scripts/developer/objectOrientedStep.js | 688 ------------------------ 1 file changed, 688 deletions(-) delete mode 100644 scripts/developer/objectOrientedStep.js diff --git a/scripts/developer/objectOrientedStep.js b/scripts/developer/objectOrientedStep.js deleted file mode 100644 index a5c27e36b9..0000000000 --- a/scripts/developer/objectOrientedStep.js +++ /dev/null @@ -1,688 +0,0 @@ -/* jslint bitwise: true */ - -/* global Script, Vec3, MyAvatar, Tablet, Messages, Quat, -DebugDraw, Mat4, Entities, Xform, Controller, Camera, console, document*/ - -Script.registerValue("STEPAPP", true); -var CENTIMETERSPERMETER = 100.0; -var LEFT = 0; -var RIGHT = 1; -var INCREASING = 1.0; -var DECREASING = -1.0; -var DEFAULT_AVATAR_HEIGHT = 1.64; -var TABLET_BUTTON_NAME = "STEP"; -var CHANGE_OF_BASIS_ROTATION = { x: 0, y: 1, z: 0, w: 0 }; -// in meters (mostly) -var DEFAULT_ANTERIOR = 0.04; -var DEFAULT_POSTERIOR = 0.06; -var DEFAULT_LATERAL = 0.10; -var DEFAULT_HEIGHT_DIFFERENCE = 0.02; -var DEFAULT_ANGULAR_VELOCITY = 0.3; -var DEFAULT_HAND_VELOCITY = 0.4; -var DEFAULT_ANGULAR_HAND_VELOCITY = 3.3; -var DEFAULT_HEAD_VELOCITY = 0.14; -var DEFAULT_LEVEL_PITCH = 7; -var DEFAULT_LEVEL_ROLL = 7; -var DEFAULT_DIFF = 0.0; -var DEFAULT_DIFF_EULERS = { x: 0.0, y: 0.0, z: 0.0 }; -var DEFAULT_HIPS_POSITION; -var DEFAULT_HEAD_POSITION; -var DEFAULT_TORSO_LENGTH; -var SPINE_STRETCH_LIMIT = 0.02; - -var VELOCITY_EPSILON = 0.02; -var AVERAGING_RATE = 0.03; -var HEIGHT_AVERAGING_RATE = 0.01; -var STEP_TIME_SECS = 0.2; -var MODE_SAMPLE_LENGTH = 100; -var RESET_MODE = false; -var HEAD_TURN_THRESHOLD = 25.0; -var NO_SHARED_DIRECTION = -0.98; -var LOADING_DELAY = 500; -var FAILSAFE_TIMEOUT = 2.5; - -var debugDrawBase = true; -var activated = false; -var documentLoaded = false; -var failsafeFlag = false; -var failsafeSignalTimer = -1.0; -var stepTimer = -1.0; - - -var modeArray = new Array(MODE_SAMPLE_LENGTH); -var modeHeight = -10.0; - -var handPosition; -var handOrientation; -var hands = []; -var hipToHandAverage = []; -var handDotHead = []; -var headAverageOrientation = MyAvatar.orientation; -var headPoseAverageOrientation = { x: 0, y: 0, z: 0, w: 1 }; -var averageHeight = 1.0; -var headEulers = { x: 0.0, y: 0.0, z: 0.0 }; -var headAverageEulers = { x: 0.0, y: 0.0, z: 0.0 }; -var headAveragePosition = { x: 0, y: 0.4, z: 0 }; -var frontLeft = { x: -DEFAULT_LATERAL, y: 0, z: -DEFAULT_ANTERIOR }; -var frontRight = { x: DEFAULT_LATERAL, y: 0, z: -DEFAULT_ANTERIOR }; -var backLeft = { x: -DEFAULT_LATERAL, y: 0, z: DEFAULT_POSTERIOR }; -var backRight = { x: DEFAULT_LATERAL, y: 0, z: DEFAULT_POSTERIOR }; - - -// define state readings constructor -function StateReading(headPose, rhandPose, lhandPose, backLength, diffFromMode, diffFromAverageHeight, diffFromAveragePosition, - diffFromAverageEulers) { - this.headPose = headPose; - this.rhandPose = rhandPose; - this.lhandPose = lhandPose; - this.backLength = backLength; - this.diffFromMode = diffFromMode; - this.diffFromAverageHeight = diffFromAverageHeight; - this.diffFromAveragePosition = diffFromAveragePosition; - this.diffFromAverageEulers = diffFromAverageEulers; -} - -// define current state readings object for holding tracker readings and current differences from averages -var currentStateReadings = new StateReading(Controller.getPoseValue(Controller.Standard.Head), - Controller.getPoseValue(Controller.Standard.RightHand), Controller.getPoseValue(Controller.Standard.LeftHand), - DEFAULT_TORSO_LENGTH, DEFAULT_DIFF, DEFAULT_DIFF, DEFAULT_DIFF, DEFAULT_DIFF_EULERS); - -// declare the checkbox constructor -function AppCheckbox(type,id,eventType,isChecked) { - this.type = type; - this.id = id; - this.eventType = eventType; - this.data = {value: isChecked}; -} - -// define the checkboxes in the html file -var usingAverageHeight = new AppCheckbox("checkboxtick", "runningAverageHeightCheck", "onRunningAverageHeightCheckBox", - false); -var usingModeHeight = new AppCheckbox("checkboxtick","modeCheck","onModeCheckBox",true); -var usingBaseOfSupport = new AppCheckbox("checkboxtick","baseOfSupportCheck","onBaseOfSupportCheckBox",true); -var usingAverageHeadPosition = new AppCheckbox("checkboxtick", "headAveragePositionCheck", "onHeadAveragePositionCheckBox", - false); - -var checkBoxArray = new Array(usingAverageHeight,usingModeHeight,usingBaseOfSupport,usingAverageHeadPosition); - -// declare the html slider constructor -function AppProperty(name, type, eventType, signalType, setFunction, initValue, convertToThreshold, convertToSlider, signalOn) { - this.name = name; - this.type = type; - this.eventType = eventType; - this.signalType = signalType; - this.setValue = setFunction; - this.value = initValue; - this.get = function () { - return this.value; - }; - this.convertToThreshold = convertToThreshold; - this.convertToSlider = convertToSlider; - this.signalOn = signalOn; -} - -// define the sliders -var frontBaseProperty = new AppProperty("#anteriorBase-slider", "slider", "onAnteriorBaseSlider", "frontSignal", - setAnteriorDistance, DEFAULT_ANTERIOR, function (num) { - return convertToMeters(num); - }, function (num) { - return convertToCentimeters(num); - },true); -var backBaseProperty = new AppProperty("#posteriorBase-slider", "slider", "onPosteriorBaseSlider", "backSignal", - setPosteriorDistance, DEFAULT_POSTERIOR, function (num) { - return convertToMeters(num); - }, function (num) { - return convertToCentimeters(num); - }, true); -var lateralBaseProperty = new AppProperty("#lateralBase-slider", "slider", "onLateralBaseSlider", "lateralSignal", - setLateralDistance, DEFAULT_LATERAL, function (num) { - return convertToMeters(num); - }, function (num) { - return convertToCentimeters(num); - }, true); -var headAngularVelocityProperty = new AppProperty("#angularVelocityHead-slider", "slider", "onAngularVelocitySlider", - "angularHeadSignal", setAngularThreshold, DEFAULT_ANGULAR_VELOCITY, function (num) { - var base = 4; - var shift = 2; - return convertExponential(base, num, DECREASING, shift); - }, function (num) { - var base = 4; - var shift = 2; - return convertLog(base, num, DECREASING, shift); - }, true); -var heightDifferenceProperty = new AppProperty("#heightDifference-slider", "slider", "onHeightDifferenceSlider", "heightSignal", - setHeightThreshold, DEFAULT_HEIGHT_DIFFERENCE, function (num) { - return convertToMeters(-num); - }, function (num) { - return convertToCentimeters(-num); - }, true); -var handsVelocityProperty = new AppProperty("#handsVelocity-slider", "slider", "onHandsVelocitySlider", "handVelocitySignal", - setHandVelocityThreshold, DEFAULT_HAND_VELOCITY, function (num) { - return num; - }, function (num) { - return num; - }, true); -var handsAngularVelocityProperty = new AppProperty("#handsAngularVelocity-slider", "slider", "onHandsAngularVelocitySlider", - "handAngularSignal", setHandAngularVelocityThreshold, DEFAULT_ANGULAR_HAND_VELOCITY, function (num) { - var base = 7; - var shift = 2; - return convertExponential(base, num, DECREASING, shift); - }, function (num) { - var base = 7; - var shift = 2; - return convertLog(base, num, DECREASING, shift); - }, true); -var headVelocityProperty = new AppProperty("#headVelocity-slider", "slider", "onHeadVelocitySlider", "headVelocitySignal", - setHeadVelocityThreshold, DEFAULT_HEAD_VELOCITY, function (num) { - var base = 2; - var shift = 0; - return convertExponential(base, num, INCREASING, shift); - }, function (num) { - var base = 2; - var shift = 0; - return convertLog(base, num, INCREASING, shift); - }, true); -var headPitchProperty = new AppProperty("#headPitch-slider", "slider", "onHeadPitchSlider", "headPitchSignal", - setHeadPitchThreshold, DEFAULT_LEVEL_PITCH, function (num) { - var base = 2.5; - var shift = 5; - return convertExponential(base, num, DECREASING, shift); - }, function (num) { - var base = 2.5; - var shift = 5; - return convertLog(base, num, DECREASING, shift); - }, true); -var headRollProperty = new AppProperty("#headRoll-slider", "slider", "onHeadRollSlider", "headRollSignal", setHeadRollThreshold, - DEFAULT_LEVEL_ROLL, function (num) { - var base = 2.5; - var shift = 5; - return convertExponential(base, num, DECREASING, shift); - }, function (num) { - var base = 2.5; - var shift = 5; - return convertLog(base, num, DECREASING, shift); - }, true); - -var propArray = new Array(frontBaseProperty, backBaseProperty, lateralBaseProperty, headAngularVelocityProperty, - heightDifferenceProperty, handsVelocityProperty, handsAngularVelocityProperty, headVelocityProperty, headPitchProperty, - headRollProperty); - -// var HTML_URL = Script.resolvePath("http://hifi-content.s3.amazonaws.com/angus/stepApp/stepApp.html"); -var HTML_URL = Script.resolvePath("http://hifi-content.s3.amazonaws.com/angus/stepApp/stepAppExtra.html"); -var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); - -function manageClick() { - if (activated) { - tablet.gotoHomeScreen(); - } else { - tablet.gotoWebScreen(HTML_URL); - } -} - -var tabletButton = tablet.addButton({ - text: TABLET_BUTTON_NAME, - icon: Script.resolvePath("http://hifi-content.s3.amazonaws.com/angus/stepApp/foot.svg"), - activeIcon: Script.resolvePath("http://hifi-content.s3.amazonaws.com/angus/stepApp/foot.svg") -}); - -function drawBase() { - // transform corners into world space, for rendering. - var worldPointLf = Vec3.sum(MyAvatar.position,Vec3.multiplyQbyV(MyAvatar.orientation, frontLeft)); - var worldPointRf = Vec3.sum(MyAvatar.position,Vec3.multiplyQbyV(MyAvatar.orientation, frontRight)); - var worldPointLb = Vec3.sum(MyAvatar.position,Vec3.multiplyQbyV(MyAvatar.orientation, backLeft)); - var worldPointRb = Vec3.sum(MyAvatar.position,Vec3.multiplyQbyV(MyAvatar.orientation, backRight)); - - var GREEN = { r: 0, g: 1, b: 0, a: 1 }; - // draw border - DebugDraw.drawRay(worldPointLf, worldPointRf, GREEN); - DebugDraw.drawRay(worldPointRf, worldPointRb, GREEN); - DebugDraw.drawRay(worldPointRb, worldPointLb, GREEN); - DebugDraw.drawRay(worldPointLb, worldPointLf, GREEN); -} - -function onKeyPress(event) { - if (event.text === "'") { - // when the sensors are reset, then reset the mode. - RESET_MODE = false; - } -} - -function onWebEventReceived(msg) { - var message = JSON.parse(msg); - print(" we have a message from html dialog " + message.type); - propArray.forEach(function (prop) { - if (prop.eventType === message.type) { - prop.setValue(prop.convertToThreshold(message.data.value)); - print("message from " + prop.name); - // break; - } - }); - checkBoxArray.forEach(function(cbox) { - if (cbox.eventType === message.type) { - cbox.data.value = message.data.value; - // break; - } - }); - if (message.type === "onCreateStepApp") { - print("document loaded"); - documentLoaded = true; - Script.setTimeout(initAppForm, LOADING_DELAY); - } -} - -function initAppForm() { - print("step app is loaded: " + documentLoaded); - if (documentLoaded === true) { - propArray.forEach(function (prop) { - tablet.emitScriptEvent(JSON.stringify({ - "type": "trigger", - "id": prop.signalType, - "data": { "value": "green" } - })); - tablet.emitScriptEvent(JSON.stringify({ - "type": "slider", - "id": prop.name, - "data": { "value": prop.convertToSlider(prop.value) } - })); - }); - checkBoxArray.forEach(function (cbox) { - tablet.emitScriptEvent(JSON.stringify({ - "type": "checkboxtick", - "id": cbox.id, - "data": { "value": cbox.data.value } - })); - }); - } -} - -function updateSignalColors() { - - // force the updates by running the threshold comparisons - withinBaseOfSupport(currentStateReadings.headPose.translation); - withinThresholdOfStandingHeightMode(currentStateReadings.diffFromMode); - headAngularVelocityBelowThreshold(currentStateReadings.headPose.angularVelocity); - handDirectionMatchesHeadDirection(currentStateReadings.lhandPose, currentStateReadings.rhandPose); - handAngularVelocityBelowThreshold(currentStateReadings.lhandPose, currentStateReadings.rhandPose); - headVelocityGreaterThanThreshold(Vec3.length(currentStateReadings.headPose.velocity)); - headMovedAwayFromAveragePosition(currentStateReadings.diffFromAveragePosition); - headLowerThanHeightAverage(currentStateReadings.diffFromAverageHeight); - isHeadLevel(currentStateReadings.diffFromAverageEulers); - - propArray.forEach(function (prop) { - if (prop.signalOn) { - tablet.emitScriptEvent(JSON.stringify({ "type": "trigger", "id": prop.signalType, "data": { "value": "green" } })); - } else { - tablet.emitScriptEvent(JSON.stringify({ "type": "trigger", "id": prop.signalType, "data": { "value": "red" } })); - } - }); -} - -function onScreenChanged(type, url) { - print("Screen changed"); - if (type === "Web" && url === HTML_URL) { - if (!activated) { - // hook up to event bridge - tablet.webEventReceived.connect(onWebEventReceived); - print("after connect web event"); - MyAvatar.hmdLeanRecenterEnabled = false; - - } - activated = true; - } else { - if (activated) { - // disconnect from event bridge - tablet.webEventReceived.disconnect(onWebEventReceived); - documentLoaded = false; - } - activated = false; - } -} - -function getLog(x, y) { - return Math.log(y) / Math.log(x); -} - -function noConversion(num) { - return num; -} - -function convertLog(base, num, direction, shift) { - return direction * getLog(base, (num + 1.0)) + shift; -} - -function convertExponential(base, num, direction, shift) { - return Math.pow(base, (direction*num + shift)) - 1.0; -} - -function convertToCentimeters(num) { - return num * CENTIMETERSPERMETER; -} - -function convertToMeters(num) { - print("convert to meters " + num); - return num / CENTIMETERSPERMETER; -} - -function isInsideLine(a, b, c) { - return (((b.x - a.x)*(c.z - a.z) - (b.z - a.z)*(c.x - a.x)) > 0); -} - -function setAngularThreshold(num) { - headAngularVelocityProperty.value = num; - print("angular threshold " + headAngularVelocityProperty.get()); -} - -function setHeadRollThreshold(num) { - headRollProperty.value = num; - print("head roll threshold " + headRollProperty.get()); -} - -function setHeadPitchThreshold(num) { - headPitchProperty.value = num; - print("head pitch threshold " + headPitchProperty.get()); -} - -function setHeightThreshold(num) { - heightDifferenceProperty.value = num; - print("height threshold " + heightDifferenceProperty.get()); -} - -function setLateralDistance(num) { - lateralBaseProperty.value = num; - frontLeft.x = -lateralBaseProperty.get(); - frontRight.x = lateralBaseProperty.get(); - backLeft.x = -lateralBaseProperty.get(); - backRight.x = lateralBaseProperty.get(); - print("lateral distance " + lateralBaseProperty.get()); -} - -function setAnteriorDistance(num) { - frontBaseProperty.value = num; - frontLeft.z = -frontBaseProperty.get(); - frontRight.z = -frontBaseProperty.get(); - print("anterior distance " + frontBaseProperty.get()); -} - -function setPosteriorDistance(num) { - backBaseProperty.value = num; - backLeft.z = backBaseProperty.get(); - backRight.z = backBaseProperty.get(); - print("posterior distance " + backBaseProperty.get()); -} - -function setHandAngularVelocityThreshold(num) { - handsAngularVelocityProperty.value = num; - print("hand angular velocity threshold " + handsAngularVelocityProperty.get()); -} - -function setHandVelocityThreshold(num) { - handsVelocityProperty.value = num; - print("hand velocity threshold " + handsVelocityProperty.get()); -} - -function setHeadVelocityThreshold(num) { - headVelocityProperty.value = num; - print("headvelocity threshold " + headVelocityProperty.get()); -} - -function withinBaseOfSupport(pos) { - var userScale = 1.0; - frontBaseProperty.signalOn = !(isInsideLine(Vec3.multiply(userScale, frontLeft), Vec3.multiply(userScale, frontRight), pos)); - backBaseProperty.signalOn = !(isInsideLine(Vec3.multiply(userScale, backRight), Vec3.multiply(userScale, backLeft), pos)); - lateralBaseProperty.signalOn = !(isInsideLine(Vec3.multiply(userScale, frontRight), Vec3.multiply(userScale, backRight), pos) - && isInsideLine(Vec3.multiply(userScale, backLeft), Vec3.multiply(userScale, frontLeft), pos)); - return (!frontBaseProperty.signalOn && !backBaseProperty.signalOn && !lateralBaseProperty.signalOn); -} - -function withinThresholdOfStandingHeightMode(heightDiff) { - if (usingModeHeight.data.value) { - heightDifferenceProperty.signalOn = heightDiff < heightDifferenceProperty.get(); - return heightDifferenceProperty.signalOn; - } else { - return true; - } -} - -function headAngularVelocityBelowThreshold(headAngularVelocity) { - var angVel = Vec3.length({ x: headAngularVelocity.x, y: 0, z: headAngularVelocity.z }); - headAngularVelocityProperty.signalOn = angVel < headAngularVelocityProperty.get(); - return headAngularVelocityProperty.signalOn; -} - -function handDirectionMatchesHeadDirection(lhPose, rhPose) { - handsVelocityProperty.signalOn = ((handsVelocityProperty.get() < NO_SHARED_DIRECTION) || - ((!lhPose.valid || ((handDotHead[LEFT] > handsVelocityProperty.get()) && - (Vec3.length(lhPose.velocity) > VELOCITY_EPSILON))) && - (!rhPose.valid || ((handDotHead[RIGHT] > handsVelocityProperty.get()) && - (Vec3.length(rhPose.velocity) > VELOCITY_EPSILON))))); - return handsVelocityProperty.signalOn; -} - -function handAngularVelocityBelowThreshold(lhPose, rhPose) { - var xzRHandAngularVelocity = Vec3.length({ x: rhPose.angularVelocity.x, y: 0.0, z: rhPose.angularVelocity.z }); - var xzLHandAngularVelocity = Vec3.length({ x: lhPose.angularVelocity.x, y: 0.0, z: lhPose.angularVelocity.z }); - handsAngularVelocityProperty.signalOn = ((!rhPose.valid ||(xzRHandAngularVelocity < handsAngularVelocityProperty.get())) - && (!lhPose.valid || (xzLHandAngularVelocity < handsAngularVelocityProperty.get()))); - return handsAngularVelocityProperty.signalOn; -} - -function headVelocityGreaterThanThreshold(headVel) { - headVelocityProperty.signalOn = (headVel > headVelocityProperty.get()) || (headVelocityProperty.get() < VELOCITY_EPSILON); - return headVelocityProperty.signalOn; -} - -function headMovedAwayFromAveragePosition(headDelta) { - return !withinBaseOfSupport(headDelta) || !usingAverageHeadPosition.data.value; -} - -function headLowerThanHeightAverage(heightDiff) { - if (usingAverageHeight.data.value) { - print("head lower than height average"); - heightDifferenceProperty.signalOn = heightDiff < heightDifferenceProperty.get(); - return heightDifferenceProperty.signalOn; - } else { - return true; - } -} - -function isHeadLevel(diffEulers) { - headRollProperty.signalOn = Math.abs(diffEulers.z) < headRollProperty.get(); - headPitchProperty.signalOn = Math.abs(diffEulers.x) < headPitchProperty.get(); - return (headRollProperty.signalOn && headPitchProperty.signalOn); -} - -function findAverage(arr) { - var sum = arr.reduce(function (acc, val) { - return acc + val; - },0); - return sum / arr.length; -} - -function addToModeArray(arr,num) { - for (var i = 0 ;i < (arr.length - 1); i++) { - arr[i] = arr[i+1]; - } - arr[arr.length - 1] = (Math.floor(num*CENTIMETERSPERMETER))/CENTIMETERSPERMETER; -} - -function findMode(ary, currentMode, backLength, defaultBack, currentHeight) { - var numMapping = {}; - var greatestFreq = 0; - var mode; - ary.forEach(function (number) { - numMapping[number] = (numMapping[number] || 0) + 1; - if ((greatestFreq < numMapping[number]) || ((numMapping[number] === MODE_SAMPLE_LENGTH) && (number > currentMode) )) { - greatestFreq = numMapping[number]; - mode = number; - } - }); - if (mode > currentMode) { - return Number(mode); - } else { - if (!RESET_MODE && HMD.active) { - print("resetting the mode............................................. "); - print("resetting the mode............................................. "); - RESET_MODE = true; - var correction = 0.02; - return currentHeight - correction; - } else { - return currentMode; - } - } -} - -function update(dt) { - if (debugDrawBase) { - drawBase(); - } - // Update current state information - currentStateReadings.headPose = Controller.getPoseValue(Controller.Standard.Head); - currentStateReadings.rhandPose = Controller.getPoseValue(Controller.Standard.RightHand); - currentStateReadings.lhandPose = Controller.getPoseValue(Controller.Standard.LeftHand); - - // back length - var headMinusHipLean = Vec3.subtract(currentStateReadings.headPose.translation, DEFAULT_HIPS_POSITION); - currentStateReadings.backLength = Vec3.length(headMinusHipLean); - // print("back length and default " + currentStateReadings.backLength + " " + DEFAULT_TORSO_LENGTH); - - // mode height - addToModeArray(modeArray, currentStateReadings.headPose.translation.y); - modeHeight = findMode(modeArray, modeHeight, currentStateReadings.backLength, DEFAULT_TORSO_LENGTH, - currentStateReadings.headPose.translation.y); - currentStateReadings.diffFromMode = modeHeight - currentStateReadings.headPose.translation.y; - - // hand direction - var leftHandLateralPoseVelocity = currentStateReadings.lhandPose.velocity; - leftHandLateralPoseVelocity.y = 0.0; - var rightHandLateralPoseVelocity = currentStateReadings.rhandPose.velocity; - rightHandLateralPoseVelocity.y = 0.0; - var headLateralPoseVelocity = currentStateReadings.headPose.velocity; - headLateralPoseVelocity.y = 0.0; - handDotHead[LEFT] = Vec3.dot(Vec3.normalize(leftHandLateralPoseVelocity), Vec3.normalize(headLateralPoseVelocity)); - handDotHead[RIGHT] = Vec3.dot(Vec3.normalize(rightHandLateralPoseVelocity), Vec3.normalize(headLateralPoseVelocity)); - - // average head position - headAveragePosition = Vec3.mix(headAveragePosition, currentStateReadings.headPose.translation, AVERAGING_RATE); - currentStateReadings.diffFromAveragePosition = Vec3.subtract(currentStateReadings.headPose.translation, - headAveragePosition); - - // average height - averageHeight = currentStateReadings.headPose.translation.y * HEIGHT_AVERAGING_RATE + - averageHeight * (1.0 - HEIGHT_AVERAGING_RATE); - currentStateReadings.diffFromAverageHeight = Math.abs(currentStateReadings.headPose.translation.y - averageHeight); - - // eulers diff - headEulers = Quat.safeEulerAngles(currentStateReadings.headPose.rotation); - headAverageOrientation = Quat.slerp(headAverageOrientation, currentStateReadings.headPose.rotation, AVERAGING_RATE); - headAverageEulers = Quat.safeEulerAngles(headAverageOrientation); - currentStateReadings.diffFromAverageEulers = Vec3.subtract(headAverageEulers, headEulers); - - // headpose rig space is for determining when to recenter rotation. - var headPoseRigSpace = Quat.multiply(CHANGE_OF_BASIS_ROTATION, currentStateReadings.headPose.rotation); - headPoseAverageOrientation = Quat.slerp(headPoseAverageOrientation, headPoseRigSpace, AVERAGING_RATE); - var headPoseAverageEulers = Quat.safeEulerAngles(headPoseAverageOrientation); - - // make the signal colors reflect the current thresholds that have been crossed - updateSignalColors(); - - SPINE_STRETCH_LIMIT = (0.04) * DEFAULT_TORSO_LENGTH * MyAvatar.scale; - - //print("the spine stretch limit is " + SPINE_STRETCH_LIMIT + " head avatar space is " + currentStateReadings.headPose.translation.y); - //print("the current back length is " + currentStateReadings.backLength + " " + DEFAULT_TORSO_LENGTH); - // Conditions for taking a step. - // 1. off the base of support. front, lateral, back edges. - // 2. head is not lower than the height mode value by more than the maxHeightChange tolerance - // 3. the angular velocity of the head is not greater than the threshold value - // ie this reflects the speed the head is rotating away from having up = (0,1,0) in Avatar frame.. - // 4. the hands velocity vector has the same direction as the head, within the given tolerance - // the tolerance is an acos value, -1 means the hands going in any direction will not block translating - // up to 1 where the hands velocity direction must exactly match that of the head. -1 threshold disables this condition. - // 5. the angular velocity xz magnitude for each hand is below the threshold value - // ie here this reflects the speed that each hand is rotating away from having up = (0,1,0) in Avatar frame. - // 6. head velocity is below step threshold - // 7. head has moved further than the threshold from the running average position of the head. - // 8. head height is not lower than the running average head height with a difference of maxHeightChange. - // 9. head's rotation in avatar space is not pitching or rolling greater than the pitch or roll thresholds - if (!withinBaseOfSupport(currentStateReadings.headPose.translation) && - withinThresholdOfStandingHeightMode(currentStateReadings.diffFromMode) && - headAngularVelocityBelowThreshold(currentStateReadings.headPose.angularVelocity) && - handDirectionMatchesHeadDirection(currentStateReadings.lhandPose, currentStateReadings.rhandPose) && - handAngularVelocityBelowThreshold(currentStateReadings.lhandPose, currentStateReadings.rhandPose) && - headVelocityGreaterThanThreshold(Vec3.length(currentStateReadings.headPose.velocity)) && - headMovedAwayFromAveragePosition(currentStateReadings.diffFromAveragePosition) && - headLowerThanHeightAverage(currentStateReadings.diffFromAverageHeight) && - isHeadLevel(currentStateReadings.diffFromAverageEulers)) { - - if (stepTimer < 0.0) { //!MyAvatar.isRecenteringHorizontally() - print("trigger recenter========================================================"); - MyAvatar.triggerHorizontalRecenter(); - stepTimer = STEP_TIME_SECS; - } - } else if ((currentStateReadings.backLength > (DEFAULT_TORSO_LENGTH + SPINE_STRETCH_LIMIT)) && - (failsafeSignalTimer < 0.0) && HMD.active) { - // do the failsafe recenter. - // failsafeFlag stops repeated setting of failsafe button color. - // RESET_MODE false forces a reset of the height - RESET_MODE = false; - failsafeFlag = true; - failsafeSignalTimer = FAILSAFE_TIMEOUT; - MyAvatar.triggerHorizontalRecenter(); - tablet.emitScriptEvent(JSON.stringify({ "type": "failsafe", "id": "failsafeSignal", "data": { "value": "green" } })); - // in fail safe we debug print the values that were blocking us. - print("failsafe debug---------------------------------------------------------------"); - propArray.forEach(function (prop) { - print(prop.name); - if (!prop.signalOn) { - print(prop.signalType + " contributed to failsafe call"); - } - }); - print("end failsafe debug---------------------------------------------------------------"); - - } - - if ((failsafeSignalTimer < 0.0) && failsafeFlag) { - failsafeFlag = false; - tablet.emitScriptEvent(JSON.stringify({ "type": "failsafe", "id": "failsafeSignal", "data": { "value": "orange" } })); - } - - stepTimer -= dt; - failsafeSignalTimer -= dt; - - if (!HMD.active) { - RESET_MODE = false; - } - - if (Math.abs(headPoseAverageEulers.y) > HEAD_TURN_THRESHOLD) { - // Turn feet - // MyAvatar.triggerRotationRecenter(); - // headPoseAverageOrientation = { x: 0, y: 0, z: 0, w: 1 }; - } -} - -function shutdownTabletApp() { - // GlobalDebugger.stop(); - tablet.removeButton(tabletButton); - if (activated) { - tablet.webEventReceived.disconnect(onWebEventReceived); - tablet.gotoHomeScreen(); - } - tablet.screenChanged.disconnect(onScreenChanged); -} - -tabletButton.clicked.connect(manageClick); -tablet.screenChanged.connect(onScreenChanged); - -Script.setTimeout(function() { - DEFAULT_HIPS_POSITION = MyAvatar.getAbsoluteDefaultJointTranslationInObjectFrame(MyAvatar.getJointIndex("Hips")); - DEFAULT_HEAD_POSITION = MyAvatar.getAbsoluteDefaultJointTranslationInObjectFrame(MyAvatar.getJointIndex("Head")); - DEFAULT_TORSO_LENGTH = Vec3.length(Vec3.subtract(DEFAULT_HEAD_POSITION, DEFAULT_HIPS_POSITION)); - SPINE_STRETCH_LIMIT = (0.04) * DEFAULT_TORSO_LENGTH * MyAvatar.scale; -},(4*LOADING_DELAY)); - -Script.update.connect(update); -Controller.keyPressEvent.connect(onKeyPress); -Script.scriptEnding.connect(function () { - MyAvatar.hmdLeanRecenterEnabled = true; - Script.update.disconnect(update); - shutdownTabletApp(); -}); From 1a0e2c6ea181bbae814554967ed8b60729eb56b8 Mon Sep 17 00:00:00 2001 From: amantley Date: Mon, 1 Oct 2018 08:30:51 -0700 Subject: [PATCH 13/54] clean up for pr --- interface/resources/qml/hifi/avatarapp/Settings.qml | 3 +-- interface/src/avatar/MyAvatar.cpp | 12 ------------ 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/interface/resources/qml/hifi/avatarapp/Settings.qml b/interface/resources/qml/hifi/avatarapp/Settings.qml index af76ba04d6..c4289ca650 100644 --- a/interface/resources/qml/hifi/avatarapp/Settings.qml +++ b/interface/resources/qml/hifi/avatarapp/Settings.qml @@ -296,7 +296,6 @@ Rectangle { text: "OFF" boxSize: 20 } - // TextStyle9 @@ -345,7 +344,7 @@ Rectangle { boxSize: 20 } } - + ColumnLayout { id: avatarAnimationLayout anchors.top: handAndCollisions.bottom diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index f281d8c87d..1bd8d4b2f0 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -485,18 +485,6 @@ void MyAvatar::update(float deltaTime) { glm::vec3 upHead = transformVectorFast(sensorHeadPoseDebug.getMatrix(), glm::vec3(0.0f, 1.0f, 0.0f)); float acosHead = glm::dot(upHead, glm::vec3(0.0f, 1.0f, 0.0f)); // qCDebug(interfaceapp) << "sensor space head pos " << sensorHeadPoseDebug.getTranslation().y; - if ((acosHead > 0.98f) && !getIsInSittingState() && (sensorHeadPoseDebug.getTranslation().y < -0.5f)) { - //qCDebug(interfaceapp) << "we are going to sitting state because it looks like we should" << sensorHeadPoseDebug.getTranslation().y; - } - if (!_lastFrameHMDMode && qApp->isHMDMode()) { - // we have entered hmd mode, so make the best guess about sitting or standing - if (sensorHeadPoseDebug.getTranslation().y < 1.3f) { - // then we are sitting. - // setIsInSittingState(true); - } else { - // setIsInSittingState(false); - } - } // put the average hand azimuth into sensor space. // then mix it with head facing direction to determine rotation recenter From 90feeffa9db5076f3ca7e2bf8012d60ad11b2c1e Mon Sep 17 00:00:00 2001 From: amantley Date: Mon, 1 Oct 2018 14:21:00 -0700 Subject: [PATCH 14/54] cleaning up. putting squat fix in vertical recenter --- interface/src/avatar/MyAvatar.cpp | 70 +++++++++++++--------------- interface/src/avatar/MyAvatar.h | 6 +-- plugins/oculus/src/OculusHelpers.cpp | 10 ++-- scripts/system/avatarapp.js | 6 +-- 4 files changed, 43 insertions(+), 49 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 1bd8d4b2f0..278d2703ab 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -484,6 +484,19 @@ void MyAvatar::update(float deltaTime) { glm::vec3 upHead = transformVectorFast(sensorHeadPoseDebug.getMatrix(), glm::vec3(0.0f, 1.0f, 0.0f)); float acosHead = glm::dot(upHead, glm::vec3(0.0f, 1.0f, 0.0f)); + + glm::vec3 headDefaultPositionAvatarSpace = getAbsoluteDefaultJointTranslationInObjectFrame(getJointIndex("Head")); + glm::quat spine2OrientationAvatarSpace = getAbsoluteJointRotationInObjectFrame(getJointIndex("Spine2")); + glm::vec3 headCurrentPositionAvatarSpace = getControllerPoseInAvatarFrame(controller::Action::HEAD).getTranslation(); + glm::vec3 upSpine2 = spine2OrientationAvatarSpace * glm::vec3(0.0f, 1.0f, 0.0f); + float angleSpine2 = glm::dot(upSpine2, glm::vec3(0.0f, 1.0f, 0.0f)); + if (headCurrentPositionAvatarSpace.y < (headDefaultPositionAvatarSpace.y - 0.05) && (angleSpine2 > 0.98f)) { + _squatCount++; + } else { + _squatCount = 0; + } + + // qCDebug(interfaceapp) << "sensor space head pos " << sensorHeadPoseDebug.getTranslation().y; // put the average hand azimuth into sensor space. @@ -3795,7 +3808,7 @@ bool MyAvatar::getIsInWalkingState() const { } bool MyAvatar::getIsInSittingState() const { - return _isInSittingState; + return _isInSittingState.get(); } float MyAvatar::getWalkSpeed() const { @@ -3819,7 +3832,7 @@ void MyAvatar::setIsInWalkingState(bool isWalking) { } void MyAvatar::setIsInSittingState(bool isSitting) { - _isInSittingState = isSitting; + _isInSittingState.set(isSitting); controller::Pose sensorHeadPoseDebug = getControllerPoseInSensorFrame(controller::Action::HEAD); _sumUserHeightSensorSpace = sensorHeadPoseDebug.getTranslation().y; _averageUserHeightCount = 1; @@ -4064,8 +4077,8 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(MyAvatar& myAvatar, const gl glm::vec3 headSensorSpace = transformVectorFast(myAvatar.getSensorToWorldMatrix(), headWorldSpace); //get the mode. //put it in sensor space. - // if we are 20% higher switch to standing. - // 16.6% lower then switch to sitting. + // if we are 20% higher switch to standing. + // 16.6% lower then switch to sitting. // add this !!!! And the head is upright. glm::vec3 upHead = transformVectorFast(sensorHeadPose.getMatrix(), glm::vec3(0.0f, 1.0f, 0.0f)); float acosHead = glm::dot(upHead, glm::vec3(0.0f, 1.0f, 0.0f)); @@ -4074,8 +4087,9 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(MyAvatar& myAvatar, const gl glm::vec3 sensorHips = transformVectorFast(myAvatar.getSensorToWorldMatrix(), worldHips); float averageSensorSpaceHeight = myAvatar._sumUserHeightSensorSpace / myAvatar._averageUserHeightCount; // we could add a counting here to make sure that a lean forward doesn't accidentally put you in sitting mode. - // but maybe so what. + // but maybe so what. // the real test is... can I pick something up in standing mode? + if (myAvatar.getIsInSittingState()) { if (offset.y < SITTING_BOTTOM) { @@ -4084,22 +4098,27 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(MyAvatar& myAvatar, const gl } else if (sensorHeadPose.getTranslation().y > (1.2f * averageSensorSpaceHeight)) { // if we recenter upwards then no longer in sitting state myAvatar.setIsInSittingState(false); - //myAvatar._sumUserHeightSensorSpace = 1.2f * averageSensorSpaceHeight; - // myAvatar._averageUserHeightCount = 1; return true; } else { return false; } } else { - // in the standing state - if ((sensorHeadPose.getTranslation().y < (0.83f * averageSensorSpaceHeight)) && (acosHead > 0.98f) && !(sensorHips.y > (0.4f * averageSensorSpaceHeight)) { - myAvatar.setIsInSittingState(true); - // myAvatar._sumUserHeightSensorSpace = 0.83f * averageSensorSpaceHeight; - // myAvatar._averageUserHeightCount = 1; - return true; + // in the standing state + if ((sensorHeadPose.getTranslation().y < (0.83f * averageSensorSpaceHeight)) && (acosHead > 0.98f) && !(sensorHips.y > (0.4f * averageSensorSpaceHeight))) { + myAvatar._sitStandStateCount++; + if (myAvatar._sitStandStateCount > 300) { + myAvatar.setIsInSittingState(true); + myAvatar._sitStandStateCount = 0; + myAvatar._squatCount = 0; + return true; + } } else { - return (offset.y > CYLINDER_TOP) || (offset.y < CYLINDER_BOTTOM); + if (myAvatar._squatCount > 600) { + return true; + myAvatar._squatCount = 0; + } } + return (offset.y > CYLINDER_TOP) || (offset.y < CYLINDER_BOTTOM); } } @@ -4109,29 +4128,6 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat if (myAvatar.getHMDLeanRecenterEnabled() && qApp->getCamera().getMode() != CAMERA_MODE_MIRROR) { - // debug head hips angle - glm::vec3 headDefaultPos = myAvatar.getAbsoluteDefaultJointTranslationInObjectFrame(myAvatar.getJointIndex("Head")); - if (myAvatar.getControllerPoseInAvatarFrame(controller::Action::HEAD).getTranslation().y < (headDefaultPos.y - 0.05f)) { - _squatCount++; - if ((_squatCount > 600) && !isActive(Vertical) && !isActive(Horizontal)) { - if (myAvatar.getIsInSittingState()) { - // activate(Horizontal); - //activate(Vertical); - _squatCount = 0; - } else { - if (myAvatar.getControllerPoseInAvatarFrame(controller::Action::HEAD).getTranslation().y < (headDefaultPos.y - 0.20f)) { - //myAvatar.setIsInSittingState(true); - //activate(Vertical); - } else { - //activate(Horizontal); - } - _squatCount = 0; - } - } - } else { - _squatCount = 0; - } - if (!isActive(Rotation) && (shouldActivateRotation(myAvatar, desiredBodyMatrix, currentBodyMatrix) || hasDriveInput)) { activate(Rotation); myAvatar.setHeadControllerFacingMovingAverage(myAvatar.getHeadControllerFacing()); diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 62ba8d68b1..c7f6fa89ae 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -1737,7 +1737,6 @@ private: std::atomic _forceActivateVertical { false }; std::atomic _forceActivateHorizontal { false }; std::atomic _toggleHipsFollowing { true }; - int _squatCount { 0 }; }; FollowHelper _follow; @@ -1770,7 +1769,6 @@ private: glm::quat _customListenOrientation; AtRestDetector _hmdAtRestDetector; - bool _lastFrameHMDMode { false } ; bool _lastIsMoving { false }; // all poses are in sensor-frame @@ -1817,7 +1815,9 @@ private: ThreadSafeValueCache _sprintSpeed { AVATAR_SPRINT_SPEED_SCALAR }; float _walkSpeedScalar { AVATAR_WALK_SPEED_SCALAR }; bool _isInWalkingState { false }; - bool _isInSittingState { false }; + ThreadSafeValueCache _isInSittingState { false }; + int _sitStandStateCount { 0 }; + int _squatCount { 0 }; // load avatar scripts once when rig is ready bool _shouldLoadScripts { false }; diff --git a/plugins/oculus/src/OculusHelpers.cpp b/plugins/oculus/src/OculusHelpers.cpp index 38d93d088d..402b05f39c 100644 --- a/plugins/oculus/src/OculusHelpers.cpp +++ b/plugins/oculus/src/OculusHelpers.cpp @@ -86,12 +86,10 @@ private: qCWarning(oculusLog) << "Failed to acquire Oculus session" << ovr::getError(); return; } else { - qCWarning(oculusLog) << "successful init of oculus!!!!!!!!"; - ovrTrackingOrigin fred; - //fred = ovr_GetTrackingOriginType(session); - ovrResult retTrackingType = ovr_SetTrackingOriginType(session, ovrTrackingOrigin::ovrTrackingOrigin_FloorLevel); - fred = ovr_GetTrackingOriginType(session); - qCWarning(oculusLog) << OVR_SUCCESS(retTrackingType) << (int)fred; + ovrResult setFloorLevelOrigin = ovr_SetTrackingOriginType(session, ovrTrackingOrigin::ovrTrackingOrigin_FloorLevel); + if (!OVR_SUCCESS(setFloorLevelOrigin)) { + qCWarning(oculusLog) << "Failed to set the Oculus tracking origin to floor level" << ovr::getError(); + } } } diff --git a/scripts/system/avatarapp.js b/scripts/system/avatarapp.js index 16761f29a6..faf624392a 100644 --- a/scripts/system/avatarapp.js +++ b/scripts/system/avatarapp.js @@ -63,8 +63,8 @@ function getMyAvatar() { function getMyAvatarSettings() { return { dominantHand: MyAvatar.getDominantHand(), - collisionsEnabled: MyAvatar.getCollisionsEnabled(), - sittingEnabled: MyAvatar.isInSittingState, + collisionsEnabled : MyAvatar.getCollisionsEnabled(), + sittingEnabled : MyAvatar.isInSittingState, collisionSoundUrl : MyAvatar.collisionSoundURL, animGraphUrl: MyAvatar.getAnimGraphUrl(), animGraphOverrideUrl : MyAvatar.getAnimGraphOverrideUrl(), @@ -326,7 +326,7 @@ function fromQml(message) { // messages are {method, params}, like json-rpc. See MyAvatar.isInSittingState = message.settings.sittingEnabled; MyAvatar.collisionSoundURL = message.settings.collisionSoundUrl; MyAvatar.setAnimGraphOverrideUrl(message.settings.animGraphOverrideUrl); - print("save settings"); + settings = getMyAvatarSettings(); break; default: From f0676d796c74a8464954bf1a8b7aae3e40df00a0 Mon Sep 17 00:00:00 2001 From: amantley Date: Mon, 1 Oct 2018 17:57:00 -0700 Subject: [PATCH 15/54] added constants and tipping point for running average. this should be replaced by the mode --- interface/src/avatar/MyAvatar.cpp | 86 +++++++++++++------------------ interface/src/avatar/MyAvatar.h | 2 + 2 files changed, 38 insertions(+), 50 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 278d2703ab..4f28ae8e90 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -471,34 +471,6 @@ void MyAvatar::update(float deltaTime) { float tau = deltaTime / HMD_FACING_TIMESCALE; setHipToHandController(computeHandAzimuth()); - // qCDebug(interfaceapp) << "sitting state is " << getIsInSittingState(); - // debug setting for sitting state if you start in the chair. - // if the head is close to the floor in sensor space - // and the up of the head is close to sensor up then try switching us to sitting state. - auto sensorHeadPoseDebug = getControllerPoseInSensorFrame(controller::Action::HEAD); - if (sensorHeadPoseDebug.isValid()) { - _sumUserHeightSensorSpace += sensorHeadPoseDebug.getTranslation().y; - _averageUserHeightCount++; - } - qCDebug(interfaceapp) << sensorHeadPoseDebug.isValid() << " valid. sensor space average " << (_sumUserHeightSensorSpace / _averageUserHeightCount) << " head position sensor y value " << sensorHeadPoseDebug.getTranslation().y; - - glm::vec3 upHead = transformVectorFast(sensorHeadPoseDebug.getMatrix(), glm::vec3(0.0f, 1.0f, 0.0f)); - float acosHead = glm::dot(upHead, glm::vec3(0.0f, 1.0f, 0.0f)); - - glm::vec3 headDefaultPositionAvatarSpace = getAbsoluteDefaultJointTranslationInObjectFrame(getJointIndex("Head")); - glm::quat spine2OrientationAvatarSpace = getAbsoluteJointRotationInObjectFrame(getJointIndex("Spine2")); - glm::vec3 headCurrentPositionAvatarSpace = getControllerPoseInAvatarFrame(controller::Action::HEAD).getTranslation(); - glm::vec3 upSpine2 = spine2OrientationAvatarSpace * glm::vec3(0.0f, 1.0f, 0.0f); - float angleSpine2 = glm::dot(upSpine2, glm::vec3(0.0f, 1.0f, 0.0f)); - if (headCurrentPositionAvatarSpace.y < (headDefaultPositionAvatarSpace.y - 0.05) && (angleSpine2 > 0.98f)) { - _squatCount++; - } else { - _squatCount = 0; - } - - - // qCDebug(interfaceapp) << "sensor space head pos " << sensorHeadPoseDebug.getTranslation().y; - // put the average hand azimuth into sensor space. // then mix it with head facing direction to determine rotation recenter if (getControllerPoseInAvatarFrame(controller::Action::LEFT_HAND).isValid() && getControllerPoseInAvatarFrame(controller::Action::RIGHT_HAND).isValid()) { @@ -527,6 +499,29 @@ void MyAvatar::update(float deltaTime) { setCurrentStandingHeight(computeStandingHeightMode(getControllerPoseInAvatarFrame(controller::Action::HEAD))); setAverageHeadRotation(computeAverageHeadRotation(getControllerPoseInAvatarFrame(controller::Action::HEAD))); + // if the head tracker reading is valid then add it to the running average. + auto sensorHeadPoseDebug = getControllerPoseInSensorFrame(controller::Action::HEAD); + if (sensorHeadPoseDebug.isValid()) { + _sumUserHeightSensorSpace += sensorHeadPoseDebug.getTranslation().y; + _averageUserHeightCount++; + } + + // if the spine is straight and the head is below the default position by 5 cm then increment squatty count. + const float SQUAT_THRESHOLD = 0.05f; + const float COSINE_TEN_DEGREES = 0.98f; + glm::vec3 headDefaultPositionAvatarSpace = getAbsoluteDefaultJointTranslationInObjectFrame(getJointIndex("Head")); + glm::quat spine2OrientationAvatarSpace = getAbsoluteJointRotationInObjectFrame(getJointIndex("Spine2")); + glm::vec3 upSpine2 = spine2OrientationAvatarSpace * glm::vec3(0.0f, 1.0f, 0.0f); + if (glm::length(upSpine2) > 0.0f) { + upSpine2 = glm::normalize(upSpine2); + } + float angleSpine2 = glm::dot(upSpine2, glm::vec3(0.0f, 1.0f, 0.0f)); + if (newHeightReading < (headDefaultPositionAvatarSpace.y - SQUAT_THRESHOLD) && (angleSpine2 > COSINE_TEN_DEGREES)) { + _squatCount++; + } else { + _squatCount = 0; + } + if (_drawAverageFacingEnabled) { auto sensorHeadPose = getControllerPoseInSensorFrame(controller::Action::HEAD); glm::vec3 worldHeadPos = transformPoint(getSensorToWorldMatrix(), sensorHeadPose.getTranslation()); @@ -3561,12 +3556,6 @@ glm::vec3 MyAvatar::computeCounterBalance() { if (counterBalancedCg.y > (tposeHips.y + 0.05f)) { // if the height is higher than default hips, clamp to default hips counterBalancedCg.y = tposeHips.y + 0.05f; - } else if (counterBalancedCg.y < sitSquatThreshold) { - // do a height reset - setResetMode(true); - // _follow.activate(FollowHelper::Vertical); - // disable cg behaviour in this case. - // setIsInSittingState(true); } return counterBalancedCg; } @@ -4068,34 +4057,29 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(MyAvatar& myAvatar, const gl const float CYLINDER_TOP = 0.1f; const float CYLINDER_BOTTOM = -1.5f; const float SITTING_BOTTOM = -0.02f; + const float STANDING_HEIGHT_MULTIPLE = 1.2f; + const float SITTING_HEIGHT_MULTIPLE = 0.833f; + const float COSINE_TEN_DEGREES = 0.98f; + const int SITTING_COUNT_THRESHOLD = 300; + const int SQUATTY_COUNT_THRESHOLD = 600; glm::vec3 offset = extractTranslation(desiredBodyMatrix) - extractTranslation(currentBodyMatrix); auto sensorHeadPose = myAvatar.getControllerPoseInSensorFrame(controller::Action::HEAD); - glm::vec3 headWorldSpace = myAvatar.getHead()->getPosition(); - glm::mat4 worldToSensorMatrix = glm::inverse(myAvatar.getSensorToWorldMatrix()); - glm::vec3 headSensorSpace = transformVectorFast(myAvatar.getSensorToWorldMatrix(), headWorldSpace); - //get the mode. - //put it in sensor space. - // if we are 20% higher switch to standing. - // 16.6% lower then switch to sitting. - // add this !!!! And the head is upright. glm::vec3 upHead = transformVectorFast(sensorHeadPose.getMatrix(), glm::vec3(0.0f, 1.0f, 0.0f)); float acosHead = glm::dot(upHead, glm::vec3(0.0f, 1.0f, 0.0f)); + glm::vec3 avatarHips = myAvatar.getAbsoluteJointTranslationInObjectFrame(myAvatar.getJointIndex("Hips")); glm::vec3 worldHips = transformVectorFast(myAvatar.getTransform().getMatrix(),avatarHips); glm::vec3 sensorHips = transformVectorFast(myAvatar.getSensorToWorldMatrix(), worldHips); + float averageSensorSpaceHeight = myAvatar._sumUserHeightSensorSpace / myAvatar._averageUserHeightCount; - // we could add a counting here to make sure that a lean forward doesn't accidentally put you in sitting mode. - // but maybe so what. - // the real test is... can I pick something up in standing mode? - if (myAvatar.getIsInSittingState()) { if (offset.y < SITTING_BOTTOM) { // we recenter when sitting. return true; - } else if (sensorHeadPose.getTranslation().y > (1.2f * averageSensorSpaceHeight)) { + } else if (sensorHeadPose.getTranslation().y > (STANDING_HEIGHT_MULTIPLE * averageSensorSpaceHeight)) { // if we recenter upwards then no longer in sitting state myAvatar.setIsInSittingState(false); return true; @@ -4104,16 +4088,18 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(MyAvatar& myAvatar, const gl } } else { // in the standing state - if ((sensorHeadPose.getTranslation().y < (0.83f * averageSensorSpaceHeight)) && (acosHead > 0.98f) && !(sensorHips.y > (0.4f * averageSensorSpaceHeight))) { + if ((sensorHeadPose.getTranslation().y < (SITTING_HEIGHT_MULTIPLE * myAvatar._tippingPoint)) && (acosHead > COSINE_TEN_DEGREES)) { //&& !(sensorHips.y > (0.4f * averageSensorSpaceHeight) myAvatar._sitStandStateCount++; - if (myAvatar._sitStandStateCount > 300) { + if (myAvatar._sitStandStateCount > SITTING_COUNT_THRESHOLD) { myAvatar.setIsInSittingState(true); + myAvatar._tippingPoint = averageSensorSpaceHeight; myAvatar._sitStandStateCount = 0; myAvatar._squatCount = 0; return true; } } else { - if (myAvatar._squatCount > 600) { + myAvatar._tippingPoint = averageSensorSpaceHeight; + if (myAvatar._squatCount > SQUATTY_COUNT_THRESHOLD) { return true; myAvatar._squatCount = 0; } diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index c7f6fa89ae..6fe5aeda47 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -140,6 +140,7 @@ class MyAvatar : public Avatar { * @property {number} walkSpeed * @property {number} walkBackwardSpeed * @property {number} sprintSpeed + * @property {number} isInSittingState * * @property {Vec3} skeletonOffset - Can be used to apply a translation offset between the avatar's position and the * registration point of the 3D model. @@ -1818,6 +1819,7 @@ private: ThreadSafeValueCache _isInSittingState { false }; int _sitStandStateCount { 0 }; int _squatCount { 0 }; + float _tippingPoint { DEFAULT_AVATAR_HEIGHT }; // load avatar scripts once when rig is ready bool _shouldLoadScripts { false }; From 8a0fbc3fe9049e3322fd88e42024d698ae344d18 Mon Sep 17 00:00:00 2001 From: amantley Date: Tue, 2 Oct 2018 17:47:56 -0700 Subject: [PATCH 16/54] changed the height to use the mode . to do fix sensor space bug. --- interface/src/avatar/MyAvatar.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 4f28ae8e90..4892f98da1 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -4074,12 +4074,18 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(MyAvatar& myAvatar, const gl glm::vec3 sensorHips = transformVectorFast(myAvatar.getSensorToWorldMatrix(), worldHips); float averageSensorSpaceHeight = myAvatar._sumUserHeightSensorSpace / myAvatar._averageUserHeightCount; + glm::vec3 modeWorldSpace = myAvatar.getTransform().getRotation() * glm::vec3(0.0f,myAvatar.getCurrentStandingHeight(),0.0f); + glm::vec3 modeSensorSpace = extractRotation(myAvatar.getSensorToWorldMatrix()) * modeWorldSpace; + glm::vec3 bodyInSensorSpace = transformPoint(glm::inverse(myAvatar.getSensorToWorldMatrix()), myAvatar.getTransform().getTranslation()); + modeSensorSpace.y = modeSensorSpace.y + bodyInSensorSpace.y; + qCDebug(interfaceapp) << "mode world sensor " << myAvatar.getCurrentStandingHeight() << " " << modeWorldSpace << " " << modeSensorSpace << " " << bodyInSensorSpace; if (myAvatar.getIsInSittingState()) { if (offset.y < SITTING_BOTTOM) { // we recenter when sitting. return true; - } else if (sensorHeadPose.getTranslation().y > (STANDING_HEIGHT_MULTIPLE * averageSensorSpaceHeight)) { + // } else if (sensorHeadPose.getTranslation().y > (STANDING_HEIGHT_MULTIPLE * averageSensorSpaceHeight)) { + } else if (sensorHeadPose.getTranslation().y > (STANDING_HEIGHT_MULTIPLE * modeSensorSpace.y)) { // if we recenter upwards then no longer in sitting state myAvatar.setIsInSittingState(false); return true; @@ -4088,10 +4094,12 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(MyAvatar& myAvatar, const gl } } else { // in the standing state - if ((sensorHeadPose.getTranslation().y < (SITTING_HEIGHT_MULTIPLE * myAvatar._tippingPoint)) && (acosHead > COSINE_TEN_DEGREES)) { //&& !(sensorHips.y > (0.4f * averageSensorSpaceHeight) + // if ((sensorHeadPose.getTranslation().y < (SITTING_HEIGHT_MULTIPLE * myAvatar._tippingPoint)) && (acosHead > COSINE_TEN_DEGREES)) { //&& !(sensorHips.y > (0.4f * averageSensorSpaceHeight) + if ((sensorHeadPose.getTranslation().y < (SITTING_HEIGHT_MULTIPLE * modeSensorSpace.y)) && (acosHead > COSINE_TEN_DEGREES)) { myAvatar._sitStandStateCount++; if (myAvatar._sitStandStateCount > SITTING_COUNT_THRESHOLD) { myAvatar.setIsInSittingState(true); + myAvatar.setResetMode(true); myAvatar._tippingPoint = averageSensorSpaceHeight; myAvatar._sitStandStateCount = 0; myAvatar._squatCount = 0; From 809ca0e51266ee8b25edb2ceeb5ce4e8b5491cd0 Mon Sep 17 00:00:00 2001 From: amantley Date: Wed, 3 Oct 2018 18:05:30 -0700 Subject: [PATCH 17/54] vive hmd input is implemented. not using mode --- interface/src/avatar/MyAvatar.cpp | 45 ++++++++++++++++++------------- 1 file changed, 26 insertions(+), 19 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 4892f98da1..9db07347c3 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -3821,10 +3821,14 @@ void MyAvatar::setIsInWalkingState(bool isWalking) { } void MyAvatar::setIsInSittingState(bool isSitting) { - _isInSittingState.set(isSitting); + _sitStandStateCount = 0; + _squatCount = 0; controller::Pose sensorHeadPoseDebug = getControllerPoseInSensorFrame(controller::Action::HEAD); _sumUserHeightSensorSpace = sensorHeadPoseDebug.getTranslation().y; + _tippingPoint = sensorHeadPoseDebug.getTranslation().y; _averageUserHeightCount = 1; + setResetMode(true); + _isInSittingState.set(isSitting); emit sittingEnabledChanged(isSitting); } @@ -4070,45 +4074,48 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(MyAvatar& myAvatar, const gl float acosHead = glm::dot(upHead, glm::vec3(0.0f, 1.0f, 0.0f)); glm::vec3 avatarHips = myAvatar.getAbsoluteJointTranslationInObjectFrame(myAvatar.getJointIndex("Hips")); - glm::vec3 worldHips = transformVectorFast(myAvatar.getTransform().getMatrix(),avatarHips); - glm::vec3 sensorHips = transformVectorFast(myAvatar.getSensorToWorldMatrix(), worldHips); + glm::vec3 worldHips = transformPoint(myAvatar.getTransform().getMatrix(),avatarHips); + glm::vec3 sensorHips = transformPoint(glm::inverse(myAvatar.getSensorToWorldMatrix()), worldHips); float averageSensorSpaceHeight = myAvatar._sumUserHeightSensorSpace / myAvatar._averageUserHeightCount; - glm::vec3 modeWorldSpace = myAvatar.getTransform().getRotation() * glm::vec3(0.0f,myAvatar.getCurrentStandingHeight(),0.0f); - glm::vec3 modeSensorSpace = extractRotation(myAvatar.getSensorToWorldMatrix()) * modeWorldSpace; - glm::vec3 bodyInSensorSpace = transformPoint(glm::inverse(myAvatar.getSensorToWorldMatrix()), myAvatar.getTransform().getTranslation()); - modeSensorSpace.y = modeSensorSpace.y + bodyInSensorSpace.y; - qCDebug(interfaceapp) << "mode world sensor " << myAvatar.getCurrentStandingHeight() << " " << modeWorldSpace << " " << modeSensorSpace << " " << bodyInSensorSpace; + glm::vec3 modeWorldSpace = transformPoint(myAvatar.getTransform().getMatrix(), glm::vec3(0.0f,myAvatar.getCurrentStandingHeight(),0.0f)); + glm::vec3 modeSensorSpace = transformPoint(glm::inverse(myAvatar.getSensorToWorldMatrix()), modeWorldSpace); + //qCDebug(interfaceapp) << "mode reading avatar " << myAvatar.getCurrentStandingHeight() << "mode w " << modeWorldSpace << "mode s " << modeSensorSpace << "sensor pose " < (STANDING_HEIGHT_MULTIPLE * averageSensorSpaceHeight)) { - } else if (sensorHeadPose.getTranslation().y > (STANDING_HEIGHT_MULTIPLE * modeSensorSpace.y)) { + } else if (sensorHeadPose.getTranslation().y > (STANDING_HEIGHT_MULTIPLE * averageSensorSpaceHeight)) { + // } else if (sensorHeadPose.getTranslation().y > (STANDING_HEIGHT_MULTIPLE * modeSensorSpace.y)) { // if we recenter upwards then no longer in sitting state - myAvatar.setIsInSittingState(false); - return true; + //myAvatar._sitStandStateCount++; + //if (myAvatar._sitStandStateCount > SITTING_COUNT_THRESHOLD) { + myAvatar.setIsInSittingState(false); + return true; + //} } else { + myAvatar._sitStandStateCount = 0; + myAvatar._tippingPoint = averageSensorSpaceHeight; return false; } } else { // in the standing state // if ((sensorHeadPose.getTranslation().y < (SITTING_HEIGHT_MULTIPLE * myAvatar._tippingPoint)) && (acosHead > COSINE_TEN_DEGREES)) { //&& !(sensorHips.y > (0.4f * averageSensorSpaceHeight) - if ((sensorHeadPose.getTranslation().y < (SITTING_HEIGHT_MULTIPLE * modeSensorSpace.y)) && (acosHead > COSINE_TEN_DEGREES)) { + if ((sensorHeadPose.getTranslation().y < (SITTING_HEIGHT_MULTIPLE * myAvatar._tippingPoint))) { myAvatar._sitStandStateCount++; if (myAvatar._sitStandStateCount > SITTING_COUNT_THRESHOLD) { myAvatar.setIsInSittingState(true); - myAvatar.setResetMode(true); - myAvatar._tippingPoint = averageSensorSpaceHeight; - myAvatar._sitStandStateCount = 0; - myAvatar._squatCount = 0; return true; } } else { myAvatar._tippingPoint = averageSensorSpaceHeight; + myAvatar._sitStandStateCount = 0; if (myAvatar._squatCount > SQUATTY_COUNT_THRESHOLD) { - return true; + // return true; myAvatar._squatCount = 0; } } @@ -4145,7 +4152,7 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat } } if (!isActive(Vertical) && (shouldActivateVertical(myAvatar, desiredBodyMatrix, currentBodyMatrix) || hasDriveInput)) { - activate(Vertical); + //activate(Vertical); } } else { if (!isActive(Rotation) && getForceActivateRotation()) { From acce675efc4280740508d8e3562e6d39ea85bf40 Mon Sep 17 00:00:00 2001 From: amantley Date: Thu, 4 Oct 2018 14:53:51 -0700 Subject: [PATCH 18/54] added snap for recentering with sit stand state change. using average height with tipping point for thresholds --- interface/src/avatar/MyAvatar.cpp | 41 ++++++++++++++++++++----------- interface/src/avatar/MyAvatar.h | 1 + 2 files changed, 28 insertions(+), 14 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 9db07347c3..55536748c7 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -4081,26 +4081,26 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(MyAvatar& myAvatar, const gl glm::vec3 modeWorldSpace = transformPoint(myAvatar.getTransform().getMatrix(), glm::vec3(0.0f,myAvatar.getCurrentStandingHeight(),0.0f)); glm::vec3 modeSensorSpace = transformPoint(glm::inverse(myAvatar.getSensorToWorldMatrix()), modeWorldSpace); - //qCDebug(interfaceapp) << "mode reading avatar " << myAvatar.getCurrentStandingHeight() << "mode w " << modeWorldSpace << "mode s " << modeSensorSpace << "sensor pose " < (STANDING_HEIGHT_MULTIPLE * averageSensorSpaceHeight)) { + //returnValue = true; + } else if (sensorHeadPose.getTranslation().y > (STANDING_HEIGHT_MULTIPLE * myAvatar._tippingPoint)) { // } else if (sensorHeadPose.getTranslation().y > (STANDING_HEIGHT_MULTIPLE * modeSensorSpace.y)) { // if we recenter upwards then no longer in sitting state - //myAvatar._sitStandStateCount++; - //if (myAvatar._sitStandStateCount > SITTING_COUNT_THRESHOLD) { + myAvatar._sitStandStateCount++; + if (myAvatar._sitStandStateCount > SITTING_COUNT_THRESHOLD) { myAvatar.setIsInSittingState(false); - return true; - //} + myAvatar._sitStandStateChange = true; + returnValue = true; + } } else { myAvatar._sitStandStateCount = 0; myAvatar._tippingPoint = averageSensorSpaceHeight; - return false; } } else { // in the standing state @@ -4109,7 +4109,8 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(MyAvatar& myAvatar, const gl myAvatar._sitStandStateCount++; if (myAvatar._sitStandStateCount > SITTING_COUNT_THRESHOLD) { myAvatar.setIsInSittingState(true); - return true; + myAvatar._sitStandStateChange = true; + returnValue = true; } } else { myAvatar._tippingPoint = averageSensorSpaceHeight; @@ -4119,8 +4120,9 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(MyAvatar& myAvatar, const gl myAvatar._squatCount = 0; } } - return (offset.y > CYLINDER_TOP) || (offset.y < CYLINDER_BOTTOM); + // returnValue = (offset.y > CYLINDER_TOP) || (offset.y < CYLINDER_BOTTOM); } + return returnValue; } void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, @@ -4152,7 +4154,9 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat } } if (!isActive(Vertical) && (shouldActivateVertical(myAvatar, desiredBodyMatrix, currentBodyMatrix) || hasDriveInput)) { - //activate(Vertical); + activate(Vertical); + _timeRemaining[(int)Vertical] = 0.1f; + qCDebug(interfaceapp) << "recenter vertically!!!!!! " << hasDriveInput; } } else { if (!isActive(Rotation) && getForceActivateRotation()) { @@ -4209,6 +4213,9 @@ glm::mat4 MyAvatar::FollowHelper::postPhysicsUpdate(const MyAvatar& myAvatar, co // apply follow displacement to the body matrix. glm::vec3 worldLinearDisplacement = myAvatar.getCharacterController()->getFollowLinearDisplacement(); + if (worldLinearDisplacement.y > 0.0001f) { + qCDebug(interfaceapp) << "linear displacement " << worldLinearDisplacement << " time remaining " << getMaxTimeRemaining(); + } glm::quat worldAngularDisplacement = myAvatar.getCharacterController()->getFollowAngularDisplacement(); glm::mat4 sensorToWorldMatrix = myAvatar.getSensorToWorldMatrix(); @@ -4219,6 +4226,12 @@ glm::mat4 MyAvatar::FollowHelper::postPhysicsUpdate(const MyAvatar& myAvatar, co glm::mat4 newBodyMat = createMatFromQuatAndPos(sensorAngularDisplacement * glmExtractRotation(currentBodyMatrix), sensorLinearDisplacement + extractTranslation(currentBodyMatrix)); + if (isActive(Vertical)) { + deactivate(Vertical); + return myAvatar.deriveBodyFromHMDSensor(); + } else { + return newBodyMat; + } return newBodyMat; } else { return currentBodyMatrix; diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 6fe5aeda47..7854f5cb41 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -1807,6 +1807,7 @@ private: ThreadSafeValueCache _userHeight { DEFAULT_AVATAR_HEIGHT }; float _sumUserHeightSensorSpace { DEFAULT_AVATAR_HEIGHT }; int _averageUserHeightCount { 1 }; + bool _sitStandStateChange { false }; void updateChildCauterization(SpatiallyNestablePointer object, bool cauterize); From 82f8c6743678527e6c14ae8b13b66038f2bc6143 Mon Sep 17 00:00:00 2001 From: amantley Date: Thu, 4 Oct 2018 15:37:01 -0700 Subject: [PATCH 19/54] put the mode in sensor space for cg --- interface/src/avatar/MyAvatar.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 55536748c7..db37b5003b 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -493,7 +493,7 @@ void MyAvatar::update(float deltaTime) { _smoothOrientationTimer += deltaTime; } - float newHeightReading = getControllerPoseInAvatarFrame(controller::Action::HEAD).getTranslation().y; + float newHeightReading = getControllerPoseInSensorFrame(controller::Action::HEAD).getTranslation().y; int newHeightReadingInCentimeters = glm::floor(newHeightReading * CENTIMETERS_PER_METER); _recentModeReadings.insert(newHeightReadingInCentimeters); setCurrentStandingHeight(computeStandingHeightMode(getControllerPoseInAvatarFrame(controller::Action::HEAD))); @@ -4015,6 +4015,7 @@ bool MyAvatar::FollowHelper::shouldActivateHorizontalCG(MyAvatar& myAvatar) cons controller::Pose currentHeadPose = myAvatar.getControllerPoseInAvatarFrame(controller::Action::HEAD); controller::Pose currentLeftHandPose = myAvatar.getControllerPoseInAvatarFrame(controller::Action::LEFT_HAND); controller::Pose currentRightHandPose = myAvatar.getControllerPoseInAvatarFrame(controller::Action::RIGHT_HAND); + controller::Pose currentHeadSensorPose = myAvatar.getControllerPoseInSensorFrame(controller::Action::HEAD); bool stepDetected = false; float myScale = myAvatar.getAvatarScale(); @@ -4028,7 +4029,7 @@ bool MyAvatar::FollowHelper::shouldActivateHorizontalCG(MyAvatar& myAvatar) cons } else { if (!withinBaseOfSupport(currentHeadPose) && headAngularVelocityBelowThreshold(currentHeadPose) && - isWithinThresholdHeightMode(currentHeadPose, myAvatar.getCurrentStandingHeight(), myScale) && + isWithinThresholdHeightMode(currentHeadSensorPose, myAvatar.getCurrentStandingHeight(), myScale) && handDirectionMatchesHeadDirection(currentLeftHandPose, currentRightHandPose, currentHeadPose) && handAngularVelocityBelowThreshold(currentLeftHandPose, currentRightHandPose) && headVelocityGreaterThanThreshold(currentHeadPose) && @@ -4083,7 +4084,7 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(MyAvatar& myAvatar, const gl // qCDebug(interfaceapp) << "mode reading avatar " << myAvatar.getCurrentStandingHeight() << "mode w " << modeWorldSpace << "mode s " << modeSensorSpace << "sensor pose " < Date: Thu, 4 Oct 2018 18:05:05 -0700 Subject: [PATCH 20/54] changed pre physics to use cg for desired body when in cg mode --- interface/src/avatar/MyAvatar.cpp | 58 +++++++++++++------------------ interface/src/avatar/MyAvatar.h | 4 +-- 2 files changed, 27 insertions(+), 35 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index db37b5003b..09896e66c3 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -493,17 +493,14 @@ void MyAvatar::update(float deltaTime) { _smoothOrientationTimer += deltaTime; } - float newHeightReading = getControllerPoseInSensorFrame(controller::Action::HEAD).getTranslation().y; - int newHeightReadingInCentimeters = glm::floor(newHeightReading * CENTIMETERS_PER_METER); - _recentModeReadings.insert(newHeightReadingInCentimeters); - setCurrentStandingHeight(computeStandingHeightMode(getControllerPoseInAvatarFrame(controller::Action::HEAD))); - setAverageHeadRotation(computeAverageHeadRotation(getControllerPoseInAvatarFrame(controller::Action::HEAD))); - - // if the head tracker reading is valid then add it to the running average. - auto sensorHeadPoseDebug = getControllerPoseInSensorFrame(controller::Action::HEAD); - if (sensorHeadPoseDebug.isValid()) { - _sumUserHeightSensorSpace += sensorHeadPoseDebug.getTranslation().y; + controller::Pose newHeightReading = getControllerPoseInSensorFrame(controller::Action::HEAD); + if (newHeightReading.isValid()) { + int newHeightReadingInCentimeters = glm::floor(newHeightReading.getTranslation().y * CENTIMETERS_PER_METER); + _sumUserHeightSensorSpace += newHeightReading.getTranslation().y; _averageUserHeightCount++; + _recentModeReadings.insert(newHeightReadingInCentimeters); + setCurrentStandingHeight(computeStandingHeightMode(newHeightReading)); + setAverageHeadRotation(computeAverageHeadRotation(getControllerPoseInAvatarFrame(controller::Action::HEAD))); } // if the spine is straight and the head is below the default position by 5 cm then increment squatty count. @@ -516,7 +513,7 @@ void MyAvatar::update(float deltaTime) { upSpine2 = glm::normalize(upSpine2); } float angleSpine2 = glm::dot(upSpine2, glm::vec3(0.0f, 1.0f, 0.0f)); - if (newHeightReading < (headDefaultPositionAvatarSpace.y - SQUAT_THRESHOLD) && (angleSpine2 > COSINE_TEN_DEGREES)) { + if (getControllerPoseInAvatarFrame(controller::Action::HEAD).getTranslation().y < (headDefaultPositionAvatarSpace.y - SQUAT_THRESHOLD) && (angleSpine2 > COSINE_TEN_DEGREES)) { _squatCount++; } else { _squatCount = 0; @@ -2031,6 +2028,11 @@ void MyAvatar::prepareForPhysicsSimulation() { _characterController.setPositionAndOrientation(getWorldPosition(), getWorldOrientation()); auto headPose = getControllerPoseInAvatarFrame(controller::Action::HEAD); if (headPose.isValid()) { + if (getCenterOfGravityModelEnabled() && !getIsInSittingState()) { + _follow.prePhysicsUpdate(*this, deriveBodyUsingCgModel(), _bodySensorMatrix, hasDriveInput()); + } else { + _follow.prePhysicsUpdate(*this, deriveBodyFromHMDSensor(), _bodySensorMatrix, hasDriveInput()); + } _follow.prePhysicsUpdate(*this, deriveBodyFromHMDSensor(), _bodySensorMatrix, hasDriveInput()); } else { _follow.deactivate(); @@ -3823,9 +3825,11 @@ void MyAvatar::setIsInWalkingState(bool isWalking) { void MyAvatar::setIsInSittingState(bool isSitting) { _sitStandStateCount = 0; _squatCount = 0; - controller::Pose sensorHeadPoseDebug = getControllerPoseInSensorFrame(controller::Action::HEAD); - _sumUserHeightSensorSpace = sensorHeadPoseDebug.getTranslation().y; - _tippingPoint = sensorHeadPoseDebug.getTranslation().y; + controller::Pose sensorHeadPose = getControllerPoseInSensorFrame(controller::Action::HEAD); + if (sensorHeadPose.isValid()) { + _sumUserHeightSensorSpace = sensorHeadPose.getTranslation().y; + _tippingPoint = sensorHeadPose.getTranslation().y; + } _averageUserHeightCount = 1; setResetMode(true); _isInSittingState.set(isSitting); @@ -4077,21 +4081,14 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(MyAvatar& myAvatar, const gl glm::vec3 avatarHips = myAvatar.getAbsoluteJointTranslationInObjectFrame(myAvatar.getJointIndex("Hips")); glm::vec3 worldHips = transformPoint(myAvatar.getTransform().getMatrix(),avatarHips); glm::vec3 sensorHips = transformPoint(glm::inverse(myAvatar.getSensorToWorldMatrix()), worldHips); - + //qCDebug(interfaceapp) << " current mode " << myAvatar.getCurrentStandingHeight() << " " << sensorHeadPose.getTranslation().y << " state " << myAvatar.getIsInSittingState(); float averageSensorSpaceHeight = myAvatar._sumUserHeightSensorSpace / myAvatar._averageUserHeightCount; - glm::vec3 modeWorldSpace = transformPoint(myAvatar.getTransform().getMatrix(), glm::vec3(0.0f,myAvatar.getCurrentStandingHeight(),0.0f)); - glm::vec3 modeSensorSpace = transformPoint(glm::inverse(myAvatar.getSensorToWorldMatrix()), modeWorldSpace); - - // qCDebug(interfaceapp) << "mode reading avatar " << myAvatar.getCurrentStandingHeight() << "mode w " << modeWorldSpace << "mode s " << modeSensorSpace << "sensor pose " < (STANDING_HEIGHT_MULTIPLE * myAvatar._tippingPoint)) { - // } else if (sensorHeadPose.getTranslation().y > (STANDING_HEIGHT_MULTIPLE * modeSensorSpace.y)) { // if we recenter upwards then no longer in sitting state myAvatar._sitStandStateCount++; if (myAvatar._sitStandStateCount > SITTING_COUNT_THRESHOLD) { @@ -4105,7 +4102,7 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(MyAvatar& myAvatar, const gl } } else { // in the standing state - // if ((sensorHeadPose.getTranslation().y < (SITTING_HEIGHT_MULTIPLE * myAvatar._tippingPoint)) && (acosHead > COSINE_TEN_DEGREES)) { //&& !(sensorHips.y > (0.4f * averageSensorSpaceHeight) + // && (acosHead > COSINE_TEN_DEGREES)) { //&& !(sensorHips.y > (0.4f * averageSensorSpaceHeight) if ((sensorHeadPose.getTranslation().y < (SITTING_HEIGHT_MULTIPLE * myAvatar._tippingPoint))) { myAvatar._sitStandStateCount++; if (myAvatar._sitStandStateCount > SITTING_COUNT_THRESHOLD) { @@ -4114,14 +4111,14 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(MyAvatar& myAvatar, const gl returnValue = true; } } else { - myAvatar._tippingPoint = averageSensorSpaceHeight; + myAvatar._tippingPoint = myAvatar.getCurrentStandingHeight(); myAvatar._sitStandStateCount = 0; if (myAvatar._squatCount > SQUATTY_COUNT_THRESHOLD) { // return true; myAvatar._squatCount = 0; } } - // returnValue = (offset.y > CYLINDER_TOP) || (offset.y < CYLINDER_BOTTOM); + returnValue = (offset.y > CYLINDER_TOP) || (offset.y < CYLINDER_BOTTOM); } return returnValue; } @@ -4156,7 +4153,6 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat } if (!isActive(Vertical) && (shouldActivateVertical(myAvatar, desiredBodyMatrix, currentBodyMatrix) || hasDriveInput)) { activate(Vertical); - _timeRemaining[(int)Vertical] = 0.1f; qCDebug(interfaceapp) << "recenter vertically!!!!!! " << hasDriveInput; } } else { @@ -4214,9 +4210,6 @@ glm::mat4 MyAvatar::FollowHelper::postPhysicsUpdate(const MyAvatar& myAvatar, co // apply follow displacement to the body matrix. glm::vec3 worldLinearDisplacement = myAvatar.getCharacterController()->getFollowLinearDisplacement(); - if (worldLinearDisplacement.y > 0.0001f) { - qCDebug(interfaceapp) << "linear displacement " << worldLinearDisplacement << " time remaining " << getMaxTimeRemaining(); - } glm::quat worldAngularDisplacement = myAvatar.getCharacterController()->getFollowAngularDisplacement(); glm::mat4 sensorToWorldMatrix = myAvatar.getSensorToWorldMatrix(); @@ -4228,10 +4221,9 @@ glm::mat4 MyAvatar::FollowHelper::postPhysicsUpdate(const MyAvatar& myAvatar, co glm::mat4 newBodyMat = createMatFromQuatAndPos(sensorAngularDisplacement * glmExtractRotation(currentBodyMatrix), sensorLinearDisplacement + extractTranslation(currentBodyMatrix)); if (isActive(Vertical)) { + // myAvatar._sitStandStateChange = false; deactivate(Vertical); - return myAvatar.deriveBodyFromHMDSensor(); - } else { - return newBodyMat; + newBodyMat = myAvatar.deriveBodyFromHMDSensor(); } return newBodyMat; } else { diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 7854f5cb41..0c6b1b01a5 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -1805,7 +1805,7 @@ private: // height of user in sensor space, when standing erect. ThreadSafeValueCache _userHeight { DEFAULT_AVATAR_HEIGHT }; - float _sumUserHeightSensorSpace { DEFAULT_AVATAR_HEIGHT }; + float _sumUserHeightSensorSpace { 0.0f }; int _averageUserHeightCount { 1 }; bool _sitStandStateChange { false }; @@ -1820,7 +1820,7 @@ private: ThreadSafeValueCache _isInSittingState { false }; int _sitStandStateCount { 0 }; int _squatCount { 0 }; - float _tippingPoint { DEFAULT_AVATAR_HEIGHT }; + float _tippingPoint { 0.0f }; // load avatar scripts once when rig is ready bool _shouldLoadScripts { false }; From cbe638bfdb18d1420dacc470d46671ee4bb8c79e Mon Sep 17 00:00:00 2001 From: amantley Date: Thu, 4 Oct 2018 18:16:39 -0700 Subject: [PATCH 21/54] added flag for vertical recentering that is state change, snap, versus the usual .5 second recentering --- interface/src/avatar/MyAvatar.cpp | 6 +++--- interface/src/avatar/MyAvatar.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 09896e66c3..8756f1bbd8 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -4203,7 +4203,7 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat myAvatar.getCharacterController()->setFollowParameters(followWorldPose, getMaxTimeRemaining()); } -glm::mat4 MyAvatar::FollowHelper::postPhysicsUpdate(const MyAvatar& myAvatar, const glm::mat4& currentBodyMatrix) { +glm::mat4 MyAvatar::FollowHelper::postPhysicsUpdate(MyAvatar& myAvatar, const glm::mat4& currentBodyMatrix) { if (isActive()) { float dt = myAvatar.getCharacterController()->getFollowTime(); decrementTimeRemaining(dt); @@ -4220,8 +4220,8 @@ glm::mat4 MyAvatar::FollowHelper::postPhysicsUpdate(const MyAvatar& myAvatar, co glm::mat4 newBodyMat = createMatFromQuatAndPos(sensorAngularDisplacement * glmExtractRotation(currentBodyMatrix), sensorLinearDisplacement + extractTranslation(currentBodyMatrix)); - if (isActive(Vertical)) { - // myAvatar._sitStandStateChange = false; + if (myAvatar._sitStandStateChange) { + myAvatar._sitStandStateChange = false; deactivate(Vertical); newBodyMat = myAvatar.deriveBodyFromHMDSensor(); } diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 0c6b1b01a5..072ea04ee7 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -1725,7 +1725,7 @@ private: bool shouldActivateHorizontal(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const; bool shouldActivateHorizontalCG(MyAvatar& myAvatar) const; void prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat4& bodySensorMatrix, const glm::mat4& currentBodyMatrix, bool hasDriveInput); - glm::mat4 postPhysicsUpdate(const MyAvatar& myAvatar, const glm::mat4& currentBodyMatrix); + glm::mat4 postPhysicsUpdate(MyAvatar& myAvatar, const glm::mat4& currentBodyMatrix); bool getForceActivateRotation() const; void setForceActivateRotation(bool val); bool getForceActivateVertical() const; From ad46b7196634e301f9fdd5d5f8d0e11342959446 Mon Sep 17 00:00:00 2001 From: amantley Date: Fri, 5 Oct 2018 13:04:14 -0700 Subject: [PATCH 22/54] before moving the step state counting to myavatar::update() --- interface/src/avatar/MyAvatar.cpp | 28 ++++++++++++++++++++++------ interface/src/avatar/MyAvatar.h | 1 + 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 8756f1bbd8..c5defe3d72 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -4103,6 +4103,7 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(MyAvatar& myAvatar, const gl } else { // in the standing state // && (acosHead > COSINE_TEN_DEGREES)) { //&& !(sensorHips.y > (0.4f * averageSensorSpaceHeight) + if ((sensorHeadPose.getTranslation().y < (SITTING_HEIGHT_MULTIPLE * myAvatar._tippingPoint))) { myAvatar._sitStandStateCount++; if (myAvatar._sitStandStateCount > SITTING_COUNT_THRESHOLD) { @@ -4111,14 +4112,15 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(MyAvatar& myAvatar, const gl returnValue = true; } } else { + returnValue = (offset.y > CYLINDER_TOP) || (offset.y < CYLINDER_BOTTOM); myAvatar._tippingPoint = myAvatar.getCurrentStandingHeight(); myAvatar._sitStandStateCount = 0; if (myAvatar._squatCount > SQUATTY_COUNT_THRESHOLD) { - // return true; + // returnValue = true; myAvatar._squatCount = 0; } } - returnValue = (offset.y > CYLINDER_TOP) || (offset.y < CYLINDER_BOTTOM); + } return returnValue; } @@ -4151,10 +4153,20 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat } } } - if (!isActive(Vertical) && (shouldActivateVertical(myAvatar, desiredBodyMatrix, currentBodyMatrix) || hasDriveInput)) { - activate(Vertical); - qCDebug(interfaceapp) << "recenter vertically!!!!!! " << hasDriveInput; + + qCDebug(interfaceapp) << "velocity of headset " << glm::length(myAvatar.getControllerPoseInSensorFrame(controller::Action::HEAD).getVelocity()); + + if (_velocityCount > 60) { + if (!isActive(Vertical) && (shouldActivateVertical(myAvatar, desiredBodyMatrix, currentBodyMatrix) || hasDriveInput)) { + activate(Vertical); + qCDebug(interfaceapp) << "recenter vertically!!!!!! " << hasDriveInput; + } + } else { + if ((glm::length(myAvatar.getControllerPoseInSensorFrame(controller::Action::HEAD).getVelocity()) > 0.1f)) { + _velocityCount++; + } } + } else { if (!isActive(Rotation) && getForceActivateRotation()) { activate(Rotation); @@ -4223,7 +4235,11 @@ glm::mat4 MyAvatar::FollowHelper::postPhysicsUpdate(MyAvatar& myAvatar, const gl if (myAvatar._sitStandStateChange) { myAvatar._sitStandStateChange = false; deactivate(Vertical); - newBodyMat = myAvatar.deriveBodyFromHMDSensor(); + + qCDebug(interfaceapp) << "before snap " << extractTranslation(newBodyMat); + //newBodyMat = myAvatar.deriveBodyFromHMDSensor(); + setTranslation(newBodyMat, extractTranslation(myAvatar.deriveBodyFromHMDSensor())); + qCDebug(interfaceapp) << "after snap " << extractTranslation(newBodyMat); } return newBodyMat; } else { diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 072ea04ee7..24a58745a3 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -1738,6 +1738,7 @@ private: std::atomic _forceActivateVertical { false }; std::atomic _forceActivateHorizontal { false }; std::atomic _toggleHipsFollowing { true }; + int _velocityCount { 0 }; }; FollowHelper _follow; From 96872f841202f4a60fc8b3b2a77f9632d0197ce8 Mon Sep 17 00:00:00 2001 From: amantley Date: Fri, 5 Oct 2018 14:55:32 -0700 Subject: [PATCH 23/54] moved all the state update for sit and stand to myavatar::update() also made it so that sit horizontal reset is handled in non-cg recentering. to do: revisit what should be sent for desired body in prephysics update call --- interface/src/avatar/MyAvatar.cpp | 143 ++++++++++++++++++------------ 1 file changed, 87 insertions(+), 56 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index c5defe3d72..58a0ef4046 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -467,6 +467,11 @@ void MyAvatar::update(float deltaTime) { // update moving average of HMD facing in xz plane. const float HMD_FACING_TIMESCALE = getRotationRecenterFilterLength(); const float PERCENTAGE_WEIGHT_HEAD_VS_SHOULDERS_AZIMUTH = 0.0f; // 100 percent shoulders + const float STANDING_HEIGHT_MULTIPLE = 1.2f; + const float SITTING_HEIGHT_MULTIPLE = 0.833f; + const float COSINE_TEN_DEGREES = 0.98f; + const int SITTING_COUNT_THRESHOLD = 300; + const int SQUATTY_COUNT_THRESHOLD = 600; float tau = deltaTime / HMD_FACING_TIMESCALE; setHipToHandController(computeHandAzimuth()); @@ -505,7 +510,6 @@ void MyAvatar::update(float deltaTime) { // if the spine is straight and the head is below the default position by 5 cm then increment squatty count. const float SQUAT_THRESHOLD = 0.05f; - const float COSINE_TEN_DEGREES = 0.98f; glm::vec3 headDefaultPositionAvatarSpace = getAbsoluteDefaultJointTranslationInObjectFrame(getJointIndex("Head")); glm::quat spine2OrientationAvatarSpace = getAbsoluteJointRotationInObjectFrame(getJointIndex("Spine2")); glm::vec3 upSpine2 = spine2OrientationAvatarSpace * glm::vec3(0.0f, 1.0f, 0.0f); @@ -519,6 +523,65 @@ void MyAvatar::update(float deltaTime) { _squatCount = 0; } + float averageSensorSpaceHeight = _sumUserHeightSensorSpace / _averageUserHeightCount; + //auto sensorHeadPose = myAvatar.getControllerPoseInSensorFrame(controller::Action::HEAD); + //glm::vec3 upHead = transformVectorFast(sensorHeadPose.getMatrix(), glm::vec3(0.0f, 1.0f, 0.0f)); + //float acosHead = glm::dot(upHead, glm::vec3(0.0f, 1.0f, 0.0f)); + + glm::vec3 avatarHips = getAbsoluteJointTranslationInObjectFrame(getJointIndex("Hips")); + glm::vec3 worldHips = transformPoint(getTransform().getMatrix(), avatarHips); + glm::vec3 sensorHips = transformPoint(glm::inverse(getSensorToWorldMatrix()), worldHips); + + // put update sit stand state counts here + if (getIsInSittingState()) { + if (newHeightReading.getTranslation().y > (STANDING_HEIGHT_MULTIPLE * _tippingPoint)) { + // if we recenter upwards then no longer in sitting state + _sitStandStateCount++; + if (_sitStandStateCount > SITTING_COUNT_THRESHOLD) { + _sitStandStateCount = 0; + _squatCount = 0; + if (newHeightReading.isValid()) { + _sumUserHeightSensorSpace = newHeightReading.getTranslation().y; + _tippingPoint = newHeightReading.getTranslation().y; + } + _averageUserHeightCount = 1; + setResetMode(true); + setIsInSittingState(false); + setCenterOfGravityModelEnabled(true); + _sitStandStateChange = true; + } + } else { + _sitStandStateCount = 0; + // tipping point is average height when sitting. + _tippingPoint = averageSensorSpaceHeight; + } + } else { + // in the standing state + if ((newHeightReading.getTranslation().y < (SITTING_HEIGHT_MULTIPLE * _tippingPoint))) {// && (angleSpine2 > COSINE_TEN_DEGREES) && !(sensorHips.y > (0.4f * averageSensorSpaceHeight))) { + _sitStandStateCount++; + if (_sitStandStateCount > SITTING_COUNT_THRESHOLD) { + _sitStandStateCount = 0; + _squatCount = 0; + if (newHeightReading.isValid()) { + _sumUserHeightSensorSpace = newHeightReading.getTranslation().y; + _tippingPoint = newHeightReading.getTranslation().y; + } + _averageUserHeightCount = 1; + setResetMode(true); + setIsInSittingState(true); + setCenterOfGravityModelEnabled(false); + _sitStandStateChange = true; + } + } else { + // returnValue = (offset.y > CYLINDER_TOP) || (offset.y < CYLINDER_BOTTOM); + // use the mode height for the tipping point when we are standing. + _tippingPoint = getCurrentStandingHeight(); + _sitStandStateCount = 0; + } + + } + + if (_drawAverageFacingEnabled) { auto sensorHeadPose = getControllerPoseInSensorFrame(controller::Action::HEAD); glm::vec3 worldHeadPos = transformPoint(getSensorToWorldMatrix(), sensorHeadPose.getTranslation()); @@ -2028,10 +2091,10 @@ void MyAvatar::prepareForPhysicsSimulation() { _characterController.setPositionAndOrientation(getWorldPosition(), getWorldOrientation()); auto headPose = getControllerPoseInAvatarFrame(controller::Action::HEAD); if (headPose.isValid()) { - if (getCenterOfGravityModelEnabled() && !getIsInSittingState()) { - _follow.prePhysicsUpdate(*this, deriveBodyUsingCgModel(), _bodySensorMatrix, hasDriveInput()); + if (getCenterOfGravityModelEnabled()) { + //_follow.prePhysicsUpdate(*this, deriveBodyUsingCgModel(), _bodySensorMatrix, hasDriveInput()); } else { - _follow.prePhysicsUpdate(*this, deriveBodyFromHMDSensor(), _bodySensorMatrix, hasDriveInput()); + //_follow.prePhysicsUpdate(*this, deriveBodyFromHMDSensor(), _bodySensorMatrix, hasDriveInput()); } _follow.prePhysicsUpdate(*this, deriveBodyFromHMDSensor(), _bodySensorMatrix, hasDriveInput()); } else { @@ -3995,6 +4058,7 @@ bool MyAvatar::FollowHelper::shouldActivateHorizontal(const MyAvatar& myAvatar, // x axis of currentBodyMatrix in world space. glm::vec3 right = glm::normalize(glm::vec3(currentBodyMatrix[0][0], currentBodyMatrix[1][0], currentBodyMatrix[2][0])); glm::vec3 offset = extractTranslation(desiredBodyMatrix) - extractTranslation(currentBodyMatrix); + controller::Pose currentHeadPose = myAvatar.getControllerPoseInAvatarFrame(controller::Action::HEAD); float forwardLeanAmount = glm::dot(forward, offset); float lateralLeanAmount = glm::dot(right, offset); @@ -4003,14 +4067,19 @@ bool MyAvatar::FollowHelper::shouldActivateHorizontal(const MyAvatar& myAvatar, const float MAX_FORWARD_LEAN = 0.15f; const float MAX_BACKWARD_LEAN = 0.1f; - - if (forwardLeanAmount > 0 && forwardLeanAmount > MAX_FORWARD_LEAN) { - return true; + bool stepDetected = false; + if (myAvatar.getIsInSittingState()) { + if (!withinBaseOfSupport(currentHeadPose)) { + stepDetected = true; + } + } else if (forwardLeanAmount > 0 && forwardLeanAmount > MAX_FORWARD_LEAN) { + stepDetected = true; } else if (forwardLeanAmount < 0 && forwardLeanAmount < -MAX_BACKWARD_LEAN) { - return true; + stepDetected = true; + } else { + stepDetected = fabs(lateralLeanAmount) > MAX_LATERAL_LEAN; } - - return fabs(lateralLeanAmount) > MAX_LATERAL_LEAN; + return stepDetected; } bool MyAvatar::FollowHelper::shouldActivateHorizontalCG(MyAvatar& myAvatar) const { @@ -4026,10 +4095,6 @@ bool MyAvatar::FollowHelper::shouldActivateHorizontalCG(MyAvatar& myAvatar) cons if (myAvatar.getIsInWalkingState()) { stepDetected = true; - } else if (myAvatar.getIsInSittingState()) { - if (!withinBaseOfSupport(currentHeadPose)) { - stepDetected = true; - } } else { if (!withinBaseOfSupport(currentHeadPose) && headAngularVelocityBelowThreshold(currentHeadPose) && @@ -4066,61 +4131,27 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(MyAvatar& myAvatar, const gl const float CYLINDER_TOP = 0.1f; const float CYLINDER_BOTTOM = -1.5f; const float SITTING_BOTTOM = -0.02f; - const float STANDING_HEIGHT_MULTIPLE = 1.2f; - const float SITTING_HEIGHT_MULTIPLE = 0.833f; - const float COSINE_TEN_DEGREES = 0.98f; - const int SITTING_COUNT_THRESHOLD = 300; const int SQUATTY_COUNT_THRESHOLD = 600; glm::vec3 offset = extractTranslation(desiredBodyMatrix) - extractTranslation(currentBodyMatrix); - - auto sensorHeadPose = myAvatar.getControllerPoseInSensorFrame(controller::Action::HEAD); - glm::vec3 upHead = transformVectorFast(sensorHeadPose.getMatrix(), glm::vec3(0.0f, 1.0f, 0.0f)); - float acosHead = glm::dot(upHead, glm::vec3(0.0f, 1.0f, 0.0f)); - - glm::vec3 avatarHips = myAvatar.getAbsoluteJointTranslationInObjectFrame(myAvatar.getJointIndex("Hips")); - glm::vec3 worldHips = transformPoint(myAvatar.getTransform().getMatrix(),avatarHips); - glm::vec3 sensorHips = transformPoint(glm::inverse(myAvatar.getSensorToWorldMatrix()), worldHips); //qCDebug(interfaceapp) << " current mode " << myAvatar.getCurrentStandingHeight() << " " << sensorHeadPose.getTranslation().y << " state " << myAvatar.getIsInSittingState(); - float averageSensorSpaceHeight = myAvatar._sumUserHeightSensorSpace / myAvatar._averageUserHeightCount; + bool returnValue = false; + if (myAvatar._sitStandStateChange) { + returnValue = true; + } if (myAvatar.getIsInSittingState()) { if (offset.y < SITTING_BOTTOM) { // we recenter when sitting. returnValue = true; - } else if (sensorHeadPose.getTranslation().y > (STANDING_HEIGHT_MULTIPLE * myAvatar._tippingPoint)) { - // if we recenter upwards then no longer in sitting state - myAvatar._sitStandStateCount++; - if (myAvatar._sitStandStateCount > SITTING_COUNT_THRESHOLD) { - myAvatar.setIsInSittingState(false); - myAvatar._sitStandStateChange = true; - returnValue = true; - } - } else { - myAvatar._sitStandStateCount = 0; - myAvatar._tippingPoint = averageSensorSpaceHeight; } } else { // in the standing state - // && (acosHead > COSINE_TEN_DEGREES)) { //&& !(sensorHips.y > (0.4f * averageSensorSpaceHeight) - - if ((sensorHeadPose.getTranslation().y < (SITTING_HEIGHT_MULTIPLE * myAvatar._tippingPoint))) { - myAvatar._sitStandStateCount++; - if (myAvatar._sitStandStateCount > SITTING_COUNT_THRESHOLD) { - myAvatar.setIsInSittingState(true); - myAvatar._sitStandStateChange = true; - returnValue = true; - } - } else { - returnValue = (offset.y > CYLINDER_TOP) || (offset.y < CYLINDER_BOTTOM); - myAvatar._tippingPoint = myAvatar.getCurrentStandingHeight(); - myAvatar._sitStandStateCount = 0; - if (myAvatar._squatCount > SQUATTY_COUNT_THRESHOLD) { - // returnValue = true; - myAvatar._squatCount = 0; - } + returnValue = (offset.y > CYLINDER_TOP) || (offset.y < CYLINDER_BOTTOM); + if (myAvatar._squatCount > SQUATTY_COUNT_THRESHOLD) { + myAvatar._squatCount = 0; + returnValue = true; } - } return returnValue; } From 3517905435d5b0fa2c276f9c313de8de5460712e Mon Sep 17 00:00:00 2001 From: amantley Date: Fri, 5 Oct 2018 16:22:30 -0700 Subject: [PATCH 24/54] added getter and setter for sitstandstatechange bool --- interface/src/avatar/MyAvatar.cpp | 50 ++++++++++--------------------- interface/src/avatar/MyAvatar.h | 18 ++++++----- 2 files changed, 27 insertions(+), 41 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 58a0ef4046..995126f3ca 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -524,14 +524,11 @@ void MyAvatar::update(float deltaTime) { } float averageSensorSpaceHeight = _sumUserHeightSensorSpace / _averageUserHeightCount; - //auto sensorHeadPose = myAvatar.getControllerPoseInSensorFrame(controller::Action::HEAD); - //glm::vec3 upHead = transformVectorFast(sensorHeadPose.getMatrix(), glm::vec3(0.0f, 1.0f, 0.0f)); - //float acosHead = glm::dot(upHead, glm::vec3(0.0f, 1.0f, 0.0f)); glm::vec3 avatarHips = getAbsoluteJointTranslationInObjectFrame(getJointIndex("Hips")); glm::vec3 worldHips = transformPoint(getTransform().getMatrix(), avatarHips); glm::vec3 sensorHips = transformPoint(glm::inverse(getSensorToWorldMatrix()), worldHips); - + // put update sit stand state counts here if (getIsInSittingState()) { if (newHeightReading.getTranslation().y > (STANDING_HEIGHT_MULTIPLE * _tippingPoint)) { @@ -548,11 +545,11 @@ void MyAvatar::update(float deltaTime) { setResetMode(true); setIsInSittingState(false); setCenterOfGravityModelEnabled(true); - _sitStandStateChange = true; + setSitStandStateChange(true); } } else { _sitStandStateCount = 0; - // tipping point is average height when sitting. + // tipping point is average height when sitting. _tippingPoint = averageSensorSpaceHeight; } } else { @@ -570,7 +567,7 @@ void MyAvatar::update(float deltaTime) { setResetMode(true); setIsInSittingState(true); setCenterOfGravityModelEnabled(false); - _sitStandStateChange = true; + setSitStandStateChange(true); } } else { // returnValue = (offset.y > CYLINDER_TOP) || (offset.y < CYLINDER_BOTTOM); @@ -2091,11 +2088,6 @@ void MyAvatar::prepareForPhysicsSimulation() { _characterController.setPositionAndOrientation(getWorldPosition(), getWorldOrientation()); auto headPose = getControllerPoseInAvatarFrame(controller::Action::HEAD); if (headPose.isValid()) { - if (getCenterOfGravityModelEnabled()) { - //_follow.prePhysicsUpdate(*this, deriveBodyUsingCgModel(), _bodySensorMatrix, hasDriveInput()); - } else { - //_follow.prePhysicsUpdate(*this, deriveBodyFromHMDSensor(), _bodySensorMatrix, hasDriveInput()); - } _follow.prePhysicsUpdate(*this, deriveBodyFromHMDSensor(), _bodySensorMatrix, hasDriveInput()); } else { _follow.deactivate(); @@ -3886,15 +3878,6 @@ void MyAvatar::setIsInWalkingState(bool isWalking) { } void MyAvatar::setIsInSittingState(bool isSitting) { - _sitStandStateCount = 0; - _squatCount = 0; - controller::Pose sensorHeadPose = getControllerPoseInSensorFrame(controller::Action::HEAD); - if (sensorHeadPose.isValid()) { - _sumUserHeightSensorSpace = sensorHeadPose.getTranslation().y; - _tippingPoint = sensorHeadPose.getTranslation().y; - } - _averageUserHeightCount = 1; - setResetMode(true); _isInSittingState.set(isSitting); emit sittingEnabledChanged(isSitting); } @@ -3915,6 +3898,14 @@ float MyAvatar::getSprintSpeed() const { return _sprintSpeed.get(); } +void MyAvatar::setSitStandStateChange(bool stateChanged) { + _sitStandStateChange = stateChanged; +} + +float MyAvatar::getSitStandStateChange() const { + return _sitStandStateChange; +} + QVector MyAvatar::getScriptUrls() { QVector scripts = _skeletonModel->isLoaded() ? _skeletonModel->getFBXGeometry().scripts : QVector(); return scripts; @@ -4134,10 +4125,8 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(MyAvatar& myAvatar, const gl const int SQUATTY_COUNT_THRESHOLD = 600; glm::vec3 offset = extractTranslation(desiredBodyMatrix) - extractTranslation(currentBodyMatrix); - //qCDebug(interfaceapp) << " current mode " << myAvatar.getCurrentStandingHeight() << " " << sensorHeadPose.getTranslation().y << " state " << myAvatar.getIsInSittingState(); - bool returnValue = false; - if (myAvatar._sitStandStateChange) { + if (myAvatar.getSitStandStateChange()) { returnValue = true; } if (myAvatar.getIsInSittingState()) { @@ -4184,13 +4173,10 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat } } } - - qCDebug(interfaceapp) << "velocity of headset " << glm::length(myAvatar.getControllerPoseInSensorFrame(controller::Action::HEAD).getVelocity()); - + if (_velocityCount > 60) { if (!isActive(Vertical) && (shouldActivateVertical(myAvatar, desiredBodyMatrix, currentBodyMatrix) || hasDriveInput)) { activate(Vertical); - qCDebug(interfaceapp) << "recenter vertically!!!!!! " << hasDriveInput; } } else { if ((glm::length(myAvatar.getControllerPoseInSensorFrame(controller::Action::HEAD).getVelocity()) > 0.1f)) { @@ -4263,14 +4249,10 @@ glm::mat4 MyAvatar::FollowHelper::postPhysicsUpdate(MyAvatar& myAvatar, const gl glm::mat4 newBodyMat = createMatFromQuatAndPos(sensorAngularDisplacement * glmExtractRotation(currentBodyMatrix), sensorLinearDisplacement + extractTranslation(currentBodyMatrix)); - if (myAvatar._sitStandStateChange) { - myAvatar._sitStandStateChange = false; + if (myAvatar.getSitStandStateChange()) { + myAvatar.setSitStandStateChange(false); deactivate(Vertical); - - qCDebug(interfaceapp) << "before snap " << extractTranslation(newBodyMat); - //newBodyMat = myAvatar.deriveBodyFromHMDSensor(); setTranslation(newBodyMat, extractTranslation(myAvatar.deriveBodyFromHMDSensor())); - qCDebug(interfaceapp) << "after snap " << extractTranslation(newBodyMat); } return newBodyMat; } else { diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 24a58745a3..54aa015aff 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -1105,6 +1105,8 @@ public: float getWalkBackwardSpeed() const; void setSprintSpeed(float value); float getSprintSpeed() const; + void setSitStandStateChange(bool stateChanged); + float getSitStandStateChange() const; QVector getScriptUrls(); @@ -1804,14 +1806,16 @@ private: std::mutex _pinnedJointsMutex; std::vector _pinnedJoints; - // height of user in sensor space, when standing erect. - ThreadSafeValueCache _userHeight { DEFAULT_AVATAR_HEIGHT }; - float _sumUserHeightSensorSpace { 0.0f }; - int _averageUserHeightCount { 1 }; - bool _sitStandStateChange { false }; - void updateChildCauterization(SpatiallyNestablePointer object, bool cauterize); + const float DEFAULT_FLOOR_HEIGHT = 0.0f; + + // height of user in sensor space, when standing erect. + ThreadSafeValueCache _userHeight{ DEFAULT_AVATAR_HEIGHT }; + float _sumUserHeightSensorSpace{ DEFAULT_AVATAR_HEIGHT }; + int _averageUserHeightCount{ 1 }; + bool _sitStandStateChange{ false }; + // max unscaled forward movement speed ThreadSafeValueCache _walkSpeed { DEFAULT_AVATAR_MAX_WALKING_SPEED }; ThreadSafeValueCache _walkBackwardSpeed { DEFAULT_AVATAR_MAX_WALKING_BACKWARD_SPEED }; @@ -1821,7 +1825,7 @@ private: ThreadSafeValueCache _isInSittingState { false }; int _sitStandStateCount { 0 }; int _squatCount { 0 }; - float _tippingPoint { 0.0f }; + float _tippingPoint { DEFAULT_FLOOR_HEIGHT }; // load avatar scripts once when rig is ready bool _shouldLoadScripts { false }; From 5faf26abd104b0db6d4539b5e074aee4f201bf82 Mon Sep 17 00:00:00 2001 From: amantley Date: Thu, 11 Oct 2018 10:38:59 -0700 Subject: [PATCH 25/54] turned off shoulder rotation when we don't have hmd lean recentering on. this temporarily fixes the behavior of the shoulders in this mode. todo: use the spine2 position to determine azimuth of hands, then they will work in all conditions --- interface/src/avatar/MyAvatar.cpp | 7 +++++++ interface/src/avatar/MySkeletonModel.cpp | 3 ++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 1f38971ab4..77c66d062f 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -591,8 +591,15 @@ void MyAvatar::update(float deltaTime) { // draw hand azimuth vector glm::vec3 handAzimuthMidpoint = transformPoint(getTransform().getMatrix(), glm::vec3(_hipToHandController.x, 0.0f, _hipToHandController.y)); DebugDraw::getInstance().drawRay(getWorldPosition(), handAzimuthMidpoint, glm::vec4(0.0f, 1.0f, 1.0f, 1.0f)); + + } + // temp: draw spine 2 position for hand azimuth purposes. + int spine2Index = getJointIndex("Spine2"); + glm::vec3 spine2WorldPosition = transformPoint(getTransform().getMatrix(), getAbsoluteJointTranslationInObjectFrame(spine2Index)); + DebugDraw::getInstance().addMarker("spine2 location", Quaternions::IDENTITY, spine2WorldPosition, glm::vec4(1)); + if (_goToPending) { setWorldPosition(_goToPosition); setWorldOrientation(_goToOrientation); diff --git a/interface/src/avatar/MySkeletonModel.cpp b/interface/src/avatar/MySkeletonModel.cpp index 42ec582c47..1f97ce03f8 100644 --- a/interface/src/avatar/MySkeletonModel.cpp +++ b/interface/src/avatar/MySkeletonModel.cpp @@ -239,7 +239,7 @@ void MySkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) { params.primaryControllerFlags[Rig::PrimaryControllerType_Hips] = (uint8_t)Rig::ControllerFlags::Enabled | (uint8_t)Rig::ControllerFlags::Estimated; // set spine2 if we have hand controllers - if (myAvatar->getControllerPoseInAvatarFrame(controller::Action::RIGHT_HAND).isValid() && + if (myAvatar->getHMDLeanRecenterEnabled() && myAvatar->getControllerPoseInAvatarFrame(controller::Action::RIGHT_HAND).isValid() && myAvatar->getControllerPoseInAvatarFrame(controller::Action::LEFT_HAND).isValid() && !(params.primaryControllerFlags[Rig::PrimaryControllerType_Spine2] & (uint8_t)Rig::ControllerFlags::Enabled)) { @@ -250,6 +250,7 @@ void MySkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) { bool headExists = _rig.getAbsoluteJointPoseInRigFrame(_rig.indexOfJoint("Head"), currentHeadPose); bool hipsExists = _rig.getAbsoluteJointPoseInRigFrame(_rig.indexOfJoint("Hips"), currentHipsPose); if (spine2Exists && headExists && hipsExists) { + // qCDebug(interfaceapp) << "hips forward direction "<< (currentHipsPose.rot() * glm::vec3(0.0f, 0.0f, 1.0f)); AnimPose rigSpaceYaw(myAvatar->getSpine2RotationRigSpace()); glm::vec3 u, v, w; glm::vec3 fwd = rigSpaceYaw.rot() * glm::vec3(0.0f, 0.0f, 1.0f); From f73d974ad77b62a41b4d540e60b1cc1c584db98f Mon Sep 17 00:00:00 2001 From: amantley Date: Thu, 11 Oct 2018 15:14:04 -0700 Subject: [PATCH 26/54] added a lock state so you can lock sit or stand state, also made the hand azimuth relative to the spine2 location in avatar space. This stops the arms from behaving badly when the hands are in front of the chest but behind the root position of the avatar --- interface/src/avatar/MyAvatar.cpp | 119 ++++++++++++++--------- interface/src/avatar/MyAvatar.h | 1 + interface/src/avatar/MySkeletonModel.cpp | 3 +- 3 files changed, 75 insertions(+), 48 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 77c66d062f..6b4459e97c 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -531,52 +531,57 @@ void MyAvatar::update(float deltaTime) { glm::vec3 sensorHips = transformPoint(glm::inverse(getSensorToWorldMatrix()), worldHips); // put update sit stand state counts here - if (getIsInSittingState()) { - if (newHeightReading.getTranslation().y > (STANDING_HEIGHT_MULTIPLE * _tippingPoint)) { - // if we recenter upwards then no longer in sitting state - _sitStandStateCount++; - if (_sitStandStateCount > SITTING_COUNT_THRESHOLD) { - _sitStandStateCount = 0; - _squatCount = 0; - if (newHeightReading.isValid()) { - _sumUserHeightSensorSpace = newHeightReading.getTranslation().y; - _tippingPoint = newHeightReading.getTranslation().y; + if (!_lockSitStandState) { + if (getIsInSittingState()) { + if (newHeightReading.getTranslation().y > (STANDING_HEIGHT_MULTIPLE * _tippingPoint)) { + // if we recenter upwards then no longer in sitting state + _sitStandStateCount++; + if (_sitStandStateCount > SITTING_COUNT_THRESHOLD) { + _sitStandStateCount = 0; + _squatCount = 0; + if (newHeightReading.isValid()) { + _sumUserHeightSensorSpace = newHeightReading.getTranslation().y; + _tippingPoint = newHeightReading.getTranslation().y; + } + _averageUserHeightCount = 1; + setResetMode(true); + setIsInSittingState(false); + setCenterOfGravityModelEnabled(true); + setSitStandStateChange(true); } - _averageUserHeightCount = 1; - setResetMode(true); - setIsInSittingState(false); - setCenterOfGravityModelEnabled(true); - setSitStandStateChange(true); + qCDebug(interfaceapp) << "going to stand state"; + } else { + _sitStandStateCount = 0; + // tipping point is average height when sitting. + _tippingPoint = averageSensorSpaceHeight; } } else { - _sitStandStateCount = 0; - // tipping point is average height when sitting. - _tippingPoint = averageSensorSpaceHeight; - } - } else { - // in the standing state - if ((newHeightReading.getTranslation().y < (SITTING_HEIGHT_MULTIPLE * _tippingPoint))) {// && (angleSpine2 > COSINE_TEN_DEGREES) && !(sensorHips.y > (0.4f * averageSensorSpaceHeight))) { - _sitStandStateCount++; - if (_sitStandStateCount > SITTING_COUNT_THRESHOLD) { - _sitStandStateCount = 0; - _squatCount = 0; - if (newHeightReading.isValid()) { - _sumUserHeightSensorSpace = newHeightReading.getTranslation().y; - _tippingPoint = newHeightReading.getTranslation().y; - } - _averageUserHeightCount = 1; - setResetMode(true); - setIsInSittingState(true); - setCenterOfGravityModelEnabled(false); - setSitStandStateChange(true); - } - } else { - // returnValue = (offset.y > CYLINDER_TOP) || (offset.y < CYLINDER_BOTTOM); - // use the mode height for the tipping point when we are standing. - _tippingPoint = getCurrentStandingHeight(); - _sitStandStateCount = 0; - } + // in the standing state + if ((newHeightReading.getTranslation().y < (SITTING_HEIGHT_MULTIPLE * _tippingPoint))) {// && (angleSpine2 > COSINE_TEN_DEGREES) && !(sensorHips.y > (0.4f * averageSensorSpaceHeight))) { + _sitStandStateCount++; + if (_sitStandStateCount > SITTING_COUNT_THRESHOLD) { + _sitStandStateCount = 0; + _squatCount = 0; + if (newHeightReading.isValid()) { + _sumUserHeightSensorSpace = newHeightReading.getTranslation().y; + _tippingPoint = newHeightReading.getTranslation().y; + } + _averageUserHeightCount = 1; + setResetMode(true); + setIsInSittingState(true); + setCenterOfGravityModelEnabled(false); + setSitStandStateChange(true); + } + qCDebug(interfaceapp) << "going to sit state"; + } else { + // returnValue = (offset.y > CYLINDER_TOP) || (offset.y < CYLINDER_BOTTOM); + // use the mode height for the tipping point when we are standing. + _tippingPoint = getCurrentStandingHeight(); + _sitStandStateCount = 0; + } + + } } @@ -939,6 +944,15 @@ void MyAvatar::updateFromHMDSensorMatrix(const glm::mat4& hmdSensorMatrix) { // Find the vector halfway between the hip to hand azimuth vectors // This midpoint hand azimuth is in Avatar space glm::vec2 MyAvatar::computeHandAzimuth() const { + int spine2Index = _skeletonModel->getRig().indexOfJoint("Spine2"); + glm::vec3 azimuthOrigin(0.0f,0.0f,0.0f); + if (!(spine2Index < 0)) { + // use the spine for the azimuth origin. + azimuthOrigin = getAbsoluteJointTranslationInObjectFrame(spine2Index); + } else { + // use the avatar root as the azimuth origin. + } + controller::Pose leftHandPoseAvatarSpace = getLeftHandPose(); controller::Pose rightHandPoseAvatarSpace = getRightHandPose(); controller::Pose headPoseAvatarSpace = getControllerPoseInAvatarFrame(controller::Action::HEAD); @@ -946,11 +960,13 @@ glm::vec2 MyAvatar::computeHandAzimuth() const { glm::vec2 latestHipToHandController = _hipToHandController; if (leftHandPoseAvatarSpace.isValid() && rightHandPoseAvatarSpace.isValid() && headPoseAvatarSpace.isValid()) { + glm::vec3 rightHandOffset = rightHandPoseAvatarSpace.translation - azimuthOrigin; + glm::vec3 leftHandOffset = leftHandPoseAvatarSpace.translation - azimuthOrigin; // we need the old azimuth reading to prevent flipping the facing direction 180 // in the case where the hands go from being slightly less than 180 apart to slightly more than 180 apart. glm::vec2 oldAzimuthReading = _hipToHandController; - if ((glm::length(glm::vec2(rightHandPoseAvatarSpace.translation.x, rightHandPoseAvatarSpace.translation.z)) > 0.0f) && (glm::length(glm::vec2(leftHandPoseAvatarSpace.translation.x, leftHandPoseAvatarSpace.translation.z)) > 0.0f)) { - latestHipToHandController = lerp(glm::normalize(glm::vec2(rightHandPoseAvatarSpace.translation.x, rightHandPoseAvatarSpace.translation.z)), glm::normalize(glm::vec2(leftHandPoseAvatarSpace.translation.x, leftHandPoseAvatarSpace.translation.z)), HALFWAY); + if ((glm::length(glm::vec2(rightHandOffset.x, rightHandOffset.z)) > 0.0f) && (glm::length(glm::vec2(leftHandOffset.x, leftHandOffset.z)) > 0.0f)) { + latestHipToHandController = lerp(glm::normalize(glm::vec2(rightHandOffset.x, rightHandOffset.z)), glm::normalize(glm::vec2(leftHandOffset.x, leftHandOffset.z)), HALFWAY); } else { latestHipToHandController = glm::vec2(0.0f, -1.0f); } @@ -4134,21 +4150,29 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(MyAvatar& myAvatar, const gl const int SQUATTY_COUNT_THRESHOLD = 600; glm::vec3 offset = extractTranslation(desiredBodyMatrix) - extractTranslation(currentBodyMatrix); + bool returnValue = false; + returnValue = (offset.y > CYLINDER_TOP);// || (offset.y < CYLINDER_BOTTOM); + if (myAvatar.getSitStandStateChange()) { + qCDebug(interfaceapp) << "sit state change"; returnValue = true; } if (myAvatar.getIsInSittingState()) { if (offset.y < SITTING_BOTTOM) { // we recenter when sitting. + qCDebug(interfaceapp) << "lean back sitting "; returnValue = true; } } else { // in the standing state - returnValue = (offset.y > CYLINDER_TOP) || (offset.y < CYLINDER_BOTTOM); if (myAvatar._squatCount > SQUATTY_COUNT_THRESHOLD) { myAvatar._squatCount = 0; - returnValue = true; + qCDebug(interfaceapp) << "squatting "; + // returnValue = true; + } + if (returnValue == true) { + qCDebug(interfaceapp) << "above or below capsule in standing"; } } return returnValue; @@ -4182,7 +4206,7 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat } } } - + if (_velocityCount > 60) { if (!isActive(Vertical) && (shouldActivateVertical(myAvatar, desiredBodyMatrix, currentBodyMatrix) || hasDriveInput)) { activate(Vertical); @@ -4192,6 +4216,7 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat _velocityCount++; } } + } else { if (!isActive(Rotation) && getForceActivateRotation()) { diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index f268a05a15..f026f39493 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -1824,6 +1824,7 @@ private: float _sumUserHeightSensorSpace{ DEFAULT_AVATAR_HEIGHT }; int _averageUserHeightCount{ 1 }; bool _sitStandStateChange{ false }; + bool _lockSitStandState { true }; // max unscaled forward movement speed ThreadSafeValueCache _walkSpeed { DEFAULT_AVATAR_MAX_WALKING_SPEED }; diff --git a/interface/src/avatar/MySkeletonModel.cpp b/interface/src/avatar/MySkeletonModel.cpp index 1f97ce03f8..ce8fefa0c5 100644 --- a/interface/src/avatar/MySkeletonModel.cpp +++ b/interface/src/avatar/MySkeletonModel.cpp @@ -239,7 +239,8 @@ void MySkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) { params.primaryControllerFlags[Rig::PrimaryControllerType_Hips] = (uint8_t)Rig::ControllerFlags::Enabled | (uint8_t)Rig::ControllerFlags::Estimated; // set spine2 if we have hand controllers - if (myAvatar->getHMDLeanRecenterEnabled() && myAvatar->getControllerPoseInAvatarFrame(controller::Action::RIGHT_HAND).isValid() && + // myAvatar->getHMDLeanRecenterEnabled() && + if (myAvatar->getControllerPoseInAvatarFrame(controller::Action::RIGHT_HAND).isValid() && myAvatar->getControllerPoseInAvatarFrame(controller::Action::LEFT_HAND).isValid() && !(params.primaryControllerFlags[Rig::PrimaryControllerType_Spine2] & (uint8_t)Rig::ControllerFlags::Enabled)) { From 67afc862224dcb753acdf62b4a8d77f276806b8c Mon Sep 17 00:00:00 2001 From: amantley Date: Thu, 11 Oct 2018 18:39:44 -0700 Subject: [PATCH 27/54] cleanup --- interface/resources/qml/hifi/AvatarApp.qml | 1 + .../resources/qml/hifi/avatarapp/Settings.qml | 19 ++++++++++++ interface/src/avatar/MyAvatar.cpp | 29 +++++++++---------- interface/src/avatar/MyAvatar.h | 13 ++++++++- interface/src/avatar/MySkeletonModel.cpp | 3 +- scripts/system/avatarapp.js | 14 ++++++++- 6 files changed, 60 insertions(+), 19 deletions(-) diff --git a/interface/resources/qml/hifi/AvatarApp.qml b/interface/resources/qml/hifi/AvatarApp.qml index b06a2ca67c..bf647b65bb 100644 --- a/interface/resources/qml/hifi/AvatarApp.qml +++ b/interface/resources/qml/hifi/AvatarApp.qml @@ -253,6 +253,7 @@ Rectangle { dominantHand : settings.dominantHandIsLeft ? 'left' : 'right', collisionsEnabled : settings.avatarCollisionsOn, sittingEnabled : settings.avatarSittingOn, + lockStateEnabled : settings.avatarLockSitStandStateOn, animGraphOverrideUrl : settings.avatarAnimationOverrideJSON, collisionSoundUrl : settings.avatarCollisionSoundUrl }; diff --git a/interface/resources/qml/hifi/avatarapp/Settings.qml b/interface/resources/qml/hifi/avatarapp/Settings.qml index c4289ca650..8749079940 100644 --- a/interface/resources/qml/hifi/avatarapp/Settings.qml +++ b/interface/resources/qml/hifi/avatarapp/Settings.qml @@ -21,6 +21,7 @@ Rectangle { property alias dominantHandIsLeft: leftHandRadioButton.checked property alias avatarCollisionsOn: collisionsEnabledRadiobutton.checked property alias avatarSittingOn: sitRadiobutton.checked + property alias avatarLockSitStandStateOn: lockSitStandStateCheckbox.checked property alias avatarAnimationOverrideJSON: avatarAnimationUrlInputText.text property alias avatarAnimationJSON: avatarAnimationUrlInputText.placeholderText property alias avatarCollisionSoundUrl: avatarCollisionSoundUrlInputText.text @@ -52,6 +53,12 @@ Rectangle { standRadioButton.checked = true; } + if (settings.lockStateEnabled) { + lockSitStandStateCheckbox.checked = true; + } else { + lockSitStandStateCheckbox.checked = false; + } + avatarAnimationJSON = settings.animGraphUrl; avatarAnimationOverrideJSON = settings.animGraphOverrideUrl; avatarCollisionSoundUrl = settings.collisionSoundUrl; @@ -343,6 +350,18 @@ Rectangle { text: "Stand" boxSize: 20 } + + // "Lock State" Checkbox + + HifiControlsUit.CheckBox { + id: lockSitStandStateCheckbox; + visible: activeTab == "nearbyTab"; + anchors.right: reloadNearbyContainer.left; + anchors.rightMargin: 20; + checked: settings.lockStateEnabled; + text: "lock"; + boxSize: 24; + } } ColumnLayout { diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 6b4459e97c..745705f7b8 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -531,7 +531,7 @@ void MyAvatar::update(float deltaTime) { glm::vec3 sensorHips = transformPoint(glm::inverse(getSensorToWorldMatrix()), worldHips); // put update sit stand state counts here - if (!_lockSitStandState) { + if (getIsSitStandStateLocked()) { if (getIsInSittingState()) { if (newHeightReading.getTranslation().y > (STANDING_HEIGHT_MULTIPLE * _tippingPoint)) { // if we recenter upwards then no longer in sitting state @@ -584,7 +584,6 @@ void MyAvatar::update(float deltaTime) { } } - if (_drawAverageFacingEnabled) { auto sensorHeadPose = getControllerPoseInSensorFrame(controller::Action::HEAD); glm::vec3 worldHeadPos = transformPoint(getSensorToWorldMatrix(), sensorHeadPose.getTranslation()); @@ -595,16 +594,9 @@ void MyAvatar::update(float deltaTime) { // draw hand azimuth vector glm::vec3 handAzimuthMidpoint = transformPoint(getTransform().getMatrix(), glm::vec3(_hipToHandController.x, 0.0f, _hipToHandController.y)); - DebugDraw::getInstance().drawRay(getWorldPosition(), handAzimuthMidpoint, glm::vec4(0.0f, 1.0f, 1.0f, 1.0f)); - - + DebugDraw::getInstance().drawRay(getWorldPosition(), handAzimuthMidpoint, glm::vec4(0.0f, 1.0f, 1.0f, 1.0f)); } - // temp: draw spine 2 position for hand azimuth purposes. - int spine2Index = getJointIndex("Spine2"); - glm::vec3 spine2WorldPosition = transformPoint(getTransform().getMatrix(), getAbsoluteJointTranslationInObjectFrame(spine2Index)); - DebugDraw::getInstance().addMarker("spine2 location", Quaternions::IDENTITY, spine2WorldPosition, glm::vec4(1)); - if (_goToPending) { setWorldPosition(_goToPosition); setWorldOrientation(_goToOrientation); @@ -949,8 +941,6 @@ glm::vec2 MyAvatar::computeHandAzimuth() const { if (!(spine2Index < 0)) { // use the spine for the azimuth origin. azimuthOrigin = getAbsoluteJointTranslationInObjectFrame(spine2Index); - } else { - // use the avatar root as the azimuth origin. } controller::Pose leftHandPoseAvatarSpace = getLeftHandPose(); @@ -3882,6 +3872,10 @@ bool MyAvatar::getIsInSittingState() const { return _isInSittingState.get(); } +bool MyAvatar::getIsSitStandStateLocked() const { + return _lockSitStandState.get(); +} + float MyAvatar::getWalkSpeed() const { return _walkSpeed.get() * _walkSpeedScalar; } @@ -3907,6 +3901,11 @@ void MyAvatar::setIsInSittingState(bool isSitting) { emit sittingEnabledChanged(isSitting); } +void MyAvatar::setIsSitStandStateLocked(bool isLocked) { + _lockSitStandState.set(isLocked); + emit sitStandStateLockEnabledChanged(isLocked); +} + void MyAvatar::setWalkSpeed(float value) { _walkSpeed.set(value); } @@ -4152,7 +4151,7 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(MyAvatar& myAvatar, const gl glm::vec3 offset = extractTranslation(desiredBodyMatrix) - extractTranslation(currentBodyMatrix); bool returnValue = false; - returnValue = (offset.y > CYLINDER_TOP);// || (offset.y < CYLINDER_BOTTOM); + returnValue = (offset.y > CYLINDER_TOP) || (offset.y < CYLINDER_BOTTOM); if (myAvatar.getSitStandStateChange()) { qCDebug(interfaceapp) << "sit state change"; @@ -4206,7 +4205,7 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat } } } - + if (_velocityCount > 60) { if (!isActive(Vertical) && (shouldActivateVertical(myAvatar, desiredBodyMatrix, currentBodyMatrix) || hasDriveInput)) { activate(Vertical); @@ -4216,7 +4215,7 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat _velocityCount++; } } - + } else { if (!isActive(Rotation) && getForceActivateRotation()) { diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index f026f39493..674d4b8b70 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -244,6 +244,7 @@ class MyAvatar : public Avatar { Q_PROPERTY(float walkBackwardSpeed READ getWalkBackwardSpeed WRITE setWalkBackwardSpeed); Q_PROPERTY(float sprintSpeed READ getSprintSpeed WRITE setSprintSpeed); Q_PROPERTY(bool isInSittingState READ getIsInSittingState WRITE setIsInSittingState); + Q_PROPERTY(bool isSitStandStateLocked READ getIsSitStandStateLocked WRITE setIsSitStandStateLocked); const QString DOMINANT_LEFT_HAND = "left"; const QString DOMINANT_RIGHT_HAND = "right"; @@ -1105,6 +1106,8 @@ public: bool getIsInWalkingState() const; void setIsInSittingState(bool isSitting); bool getIsInSittingState() const; + void setIsSitStandStateLocked(bool isLocked); + bool getIsSitStandStateLocked() const; void setWalkSpeed(float value); float getWalkSpeed() const; void setWalkBackwardSpeed(float value); @@ -1526,6 +1529,14 @@ signals: */ void sittingEnabledChanged(bool enabled); + /**jsdoc + * Triggered when the sit state is enabled or disabled + * @function MyAvatar.sitStandStateLockEnabledChanged + * @param {boolean} enabled + * @returns {Signal} + */ + void sitStandStateLockEnabledChanged(bool enabled); + private slots: void leaveDomain(); void updateCollisionCapsuleCache(); @@ -1824,7 +1835,7 @@ private: float _sumUserHeightSensorSpace{ DEFAULT_AVATAR_HEIGHT }; int _averageUserHeightCount{ 1 }; bool _sitStandStateChange{ false }; - bool _lockSitStandState { true }; + ThreadSafeValueCache _lockSitStandState { true }; // max unscaled forward movement speed ThreadSafeValueCache _walkSpeed { DEFAULT_AVATAR_MAX_WALKING_SPEED }; diff --git a/interface/src/avatar/MySkeletonModel.cpp b/interface/src/avatar/MySkeletonModel.cpp index ce8fefa0c5..78c5c03cc9 100644 --- a/interface/src/avatar/MySkeletonModel.cpp +++ b/interface/src/avatar/MySkeletonModel.cpp @@ -239,7 +239,6 @@ void MySkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) { params.primaryControllerFlags[Rig::PrimaryControllerType_Hips] = (uint8_t)Rig::ControllerFlags::Enabled | (uint8_t)Rig::ControllerFlags::Estimated; // set spine2 if we have hand controllers - // myAvatar->getHMDLeanRecenterEnabled() && if (myAvatar->getControllerPoseInAvatarFrame(controller::Action::RIGHT_HAND).isValid() && myAvatar->getControllerPoseInAvatarFrame(controller::Action::LEFT_HAND).isValid() && !(params.primaryControllerFlags[Rig::PrimaryControllerType_Spine2] & (uint8_t)Rig::ControllerFlags::Enabled)) { @@ -251,7 +250,7 @@ void MySkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) { bool headExists = _rig.getAbsoluteJointPoseInRigFrame(_rig.indexOfJoint("Head"), currentHeadPose); bool hipsExists = _rig.getAbsoluteJointPoseInRigFrame(_rig.indexOfJoint("Hips"), currentHipsPose); if (spine2Exists && headExists && hipsExists) { - // qCDebug(interfaceapp) << "hips forward direction "<< (currentHipsPose.rot() * glm::vec3(0.0f, 0.0f, 1.0f)); + AnimPose rigSpaceYaw(myAvatar->getSpine2RotationRigSpace()); glm::vec3 u, v, w; glm::vec3 fwd = rigSpaceYaw.rot() * glm::vec3(0.0f, 0.0f, 1.0f); diff --git a/scripts/system/avatarapp.js b/scripts/system/avatarapp.js index faf624392a..4a25ab9551 100644 --- a/scripts/system/avatarapp.js +++ b/scripts/system/avatarapp.js @@ -64,7 +64,8 @@ function getMyAvatarSettings() { return { dominantHand: MyAvatar.getDominantHand(), collisionsEnabled : MyAvatar.getCollisionsEnabled(), - sittingEnabled : MyAvatar.isInSittingState, + sittingEnabled: MyAvatar.isInSittingState, + lockStateEnabled: MyAvatar.isSitStandStateLocked, collisionSoundUrl : MyAvatar.collisionSoundURL, animGraphUrl: MyAvatar.getAnimGraphUrl(), animGraphOverrideUrl : MyAvatar.getAnimGraphOverrideUrl(), @@ -145,6 +146,14 @@ function onSittingEnabledChanged(isSitting) { } } +function onSitStandStateLockedEnabledChanged(isLocked) { + if (currentAvatarSettings.lockStateEnabled !== isLocked) { + currentAvatarSettings.lockStateEnabled = isLocked; + print("emit lock sit stand state changed"); + sendToQml({ 'method': 'settingChanged', 'name': 'lockStateEnabled', 'value': isLocked }) + } +} + function onNewCollisionSoundUrl(url) { if(currentAvatarSettings.collisionSoundUrl !== url) { currentAvatarSettings.collisionSoundUrl = url; @@ -324,6 +333,7 @@ function fromQml(message) { // messages are {method, params}, like json-rpc. See MyAvatar.setDominantHand(message.settings.dominantHand); MyAvatar.setCollisionsEnabled(message.settings.collisionsEnabled); MyAvatar.isInSittingState = message.settings.sittingEnabled; + MyAvatar.isSitStandStateLocked = message.settings.lockStateEnabled; MyAvatar.collisionSoundURL = message.settings.collisionSoundUrl; MyAvatar.setAnimGraphOverrideUrl(message.settings.animGraphOverrideUrl); @@ -518,6 +528,7 @@ function off() { MyAvatar.dominantHandChanged.disconnect(onDominantHandChanged); MyAvatar.collisionsEnabledChanged.disconnect(onCollisionsEnabledChanged); MyAvatar.sittingEnabledChanged.disconnect(onSittingEnabledChanged); + MyAvatar.sitStandStateLockEnabledChanged.disconnect(onSitStandStateLockedEnabledChanged); MyAvatar.newCollisionSoundURL.disconnect(onNewCollisionSoundUrl); MyAvatar.animGraphUrlChanged.disconnect(onAnimGraphUrlChanged); MyAvatar.targetScaleChanged.disconnect(onTargetScaleChanged); @@ -533,6 +544,7 @@ function on() { MyAvatar.dominantHandChanged.connect(onDominantHandChanged); MyAvatar.collisionsEnabledChanged.connect(onCollisionsEnabledChanged); MyAvatar.sittingEnabledChanged.connect(onSittingEnabledChanged); + MyAvatar.sitStandStateLockEnabledChanged.connect(onSitStandStateLockedEnabledChanged); MyAvatar.newCollisionSoundURL.connect(onNewCollisionSoundUrl); MyAvatar.animGraphUrlChanged.connect(onAnimGraphUrlChanged); MyAvatar.targetScaleChanged.connect(onTargetScaleChanged); From 7dd156ccdd790bbc750d05465ad4ad3de6698067 Mon Sep 17 00:00:00 2001 From: amantley Date: Fri, 12 Oct 2018 15:00:15 -0700 Subject: [PATCH 28/54] made the threshold for the spine angle larger to make auto transitions more robust --- interface/src/avatar/MyAvatar.cpp | 57 +++++++++++++++--------- interface/src/avatar/MyAvatar.h | 2 +- interface/src/avatar/MySkeletonModel.cpp | 2 +- 3 files changed, 38 insertions(+), 23 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 745705f7b8..e130f78dc4 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -471,6 +471,7 @@ void MyAvatar::update(float deltaTime) { const float STANDING_HEIGHT_MULTIPLE = 1.2f; const float SITTING_HEIGHT_MULTIPLE = 0.833f; const float COSINE_TEN_DEGREES = 0.98f; + const float COSINE_THIRTY_DEGREES = 0.866f; const int SITTING_COUNT_THRESHOLD = 300; const int SQUATTY_COUNT_THRESHOLD = 600; @@ -518,7 +519,7 @@ void MyAvatar::update(float deltaTime) { upSpine2 = glm::normalize(upSpine2); } float angleSpine2 = glm::dot(upSpine2, glm::vec3(0.0f, 1.0f, 0.0f)); - if (getControllerPoseInAvatarFrame(controller::Action::HEAD).getTranslation().y < (headDefaultPositionAvatarSpace.y - SQUAT_THRESHOLD) && (angleSpine2 > COSINE_TEN_DEGREES)) { + if (getControllerPoseInAvatarFrame(controller::Action::HEAD).getTranslation().y < (headDefaultPositionAvatarSpace.y - SQUAT_THRESHOLD) && (angleSpine2 > COSINE_THIRTY_DEGREES)) { _squatCount++; } else { _squatCount = 0; @@ -531,7 +532,7 @@ void MyAvatar::update(float deltaTime) { glm::vec3 sensorHips = transformPoint(glm::inverse(getSensorToWorldMatrix()), worldHips); // put update sit stand state counts here - if (getIsSitStandStateLocked()) { + if (!getIsSitStandStateLocked() && (_follow._velocityCount > 60)) { if (getIsInSittingState()) { if (newHeightReading.getTranslation().y > (STANDING_HEIGHT_MULTIPLE * _tippingPoint)) { // if we recenter upwards then no longer in sitting state @@ -544,10 +545,10 @@ void MyAvatar::update(float deltaTime) { _tippingPoint = newHeightReading.getTranslation().y; } _averageUserHeightCount = 1; - setResetMode(true); + // setResetMode(true); setIsInSittingState(false); - setCenterOfGravityModelEnabled(true); - setSitStandStateChange(true); + // setCenterOfGravityModelEnabled(true); + // setSitStandStateChange(true); } qCDebug(interfaceapp) << "going to stand state"; } else { @@ -557,7 +558,7 @@ void MyAvatar::update(float deltaTime) { } } else { // in the standing state - if ((newHeightReading.getTranslation().y < (SITTING_HEIGHT_MULTIPLE * _tippingPoint))) {// && (angleSpine2 > COSINE_TEN_DEGREES) && !(sensorHips.y > (0.4f * averageSensorSpaceHeight))) { + if ((newHeightReading.getTranslation().y < (SITTING_HEIGHT_MULTIPLE * _tippingPoint)) && (angleSpine2 > COSINE_THIRTY_DEGREES)) { _sitStandStateCount++; if (_sitStandStateCount > SITTING_COUNT_THRESHOLD) { _sitStandStateCount = 0; @@ -567,11 +568,10 @@ void MyAvatar::update(float deltaTime) { _tippingPoint = newHeightReading.getTranslation().y; } _averageUserHeightCount = 1; - setResetMode(true); + // setResetMode(true); setIsInSittingState(true); - setCenterOfGravityModelEnabled(false); - - setSitStandStateChange(true); + // setCenterOfGravityModelEnabled(false); + // setSitStandStateChange(true); } qCDebug(interfaceapp) << "going to sit state"; } else { @@ -3898,6 +3898,13 @@ void MyAvatar::setIsInWalkingState(bool isWalking) { void MyAvatar::setIsInSittingState(bool isSitting) { _isInSittingState.set(isSitting); + setResetMode(true); + if (isSitting) { + setCenterOfGravityModelEnabled(false); + } else { + setCenterOfGravityModelEnabled(true); + } + setSitStandStateChange(true); emit sittingEnabledChanged(isSitting); } @@ -4146,32 +4153,34 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(MyAvatar& myAvatar, const gl const float CYLINDER_TOP = 0.1f; const float CYLINDER_BOTTOM = -1.5f; const float SITTING_BOTTOM = -0.02f; - const int SQUATTY_COUNT_THRESHOLD = 600; + const int SQUATTY_COUNT_THRESHOLD = 1800; glm::vec3 offset = extractTranslation(desiredBodyMatrix) - extractTranslation(currentBodyMatrix); bool returnValue = false; - returnValue = (offset.y > CYLINDER_TOP) || (offset.y < CYLINDER_BOTTOM); if (myAvatar.getSitStandStateChange()) { - qCDebug(interfaceapp) << "sit state change"; + // qCDebug(interfaceapp) << "sit state change"; returnValue = true; + } if (myAvatar.getIsInSittingState()) { + if (myAvatar.getIsSitStandStateLocked()) { + returnValue = (offset.y > CYLINDER_TOP); + } if (offset.y < SITTING_BOTTOM) { // we recenter when sitting. - qCDebug(interfaceapp) << "lean back sitting "; + // qCDebug(interfaceapp) << "lean back sitting "; returnValue = true; } } else { // in the standing state - if (myAvatar._squatCount > SQUATTY_COUNT_THRESHOLD) { + returnValue = (offset.y > CYLINDER_TOP) || (offset.y < CYLINDER_BOTTOM); + // finally check for squats in standing + if ((myAvatar._squatCount > SQUATTY_COUNT_THRESHOLD) && !myAvatar.getIsSitStandStateLocked()) { myAvatar._squatCount = 0; - qCDebug(interfaceapp) << "squatting "; - // returnValue = true; - } - if (returnValue == true) { - qCDebug(interfaceapp) << "above or below capsule in standing"; + // qCDebug(interfaceapp) << "squatting "; + returnValue = true; } } return returnValue; @@ -4185,6 +4194,7 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat if (!isActive(Rotation) && (shouldActivateRotation(myAvatar, desiredBodyMatrix, currentBodyMatrix) || hasDriveInput)) { activate(Rotation); + qCDebug(interfaceapp) << "should activate rotation true "; myAvatar.setHeadControllerFacingMovingAverage(myAvatar.getHeadControllerFacing()); } if (myAvatar.getCenterOfGravityModelEnabled()) { @@ -4199,7 +4209,8 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat // center of gravity model is not enabled if (!isActive(Horizontal) && (shouldActivateHorizontal(myAvatar, desiredBodyMatrix, currentBodyMatrix) || hasDriveInput)) { activate(Horizontal); - if (myAvatar.getEnableStepResetRotation()) { + if (myAvatar.getEnableStepResetRotation() && !myAvatar.getIsInSittingState()) { + qCDebug(interfaceapp) << "step recenter rotation true "; activate(Rotation); myAvatar.setHeadControllerFacingMovingAverage(myAvatar.getHeadControllerFacing()); } @@ -4214,6 +4225,10 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat if ((glm::length(myAvatar.getControllerPoseInSensorFrame(controller::Action::HEAD).getVelocity()) > 0.1f)) { _velocityCount++; } + if (_velocityCount > 60) { + qCDebug(interfaceapp) << "reached velocity count "; + } + } diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 674d4b8b70..10b5510e4d 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -1835,7 +1835,7 @@ private: float _sumUserHeightSensorSpace{ DEFAULT_AVATAR_HEIGHT }; int _averageUserHeightCount{ 1 }; bool _sitStandStateChange{ false }; - ThreadSafeValueCache _lockSitStandState { true }; + ThreadSafeValueCache _lockSitStandState { false }; // max unscaled forward movement speed ThreadSafeValueCache _walkSpeed { DEFAULT_AVATAR_MAX_WALKING_SPEED }; diff --git a/interface/src/avatar/MySkeletonModel.cpp b/interface/src/avatar/MySkeletonModel.cpp index 78c5c03cc9..e5b9df7dd1 100644 --- a/interface/src/avatar/MySkeletonModel.cpp +++ b/interface/src/avatar/MySkeletonModel.cpp @@ -46,7 +46,7 @@ static AnimPose computeHipsInSensorFrame(MyAvatar* myAvatar, bool isFlying) { } glm::mat4 hipsMat; - if (myAvatar->getCenterOfGravityModelEnabled() && !isFlying && !(myAvatar->getIsInWalkingState()) && !(myAvatar->getIsInSittingState())) { + if (myAvatar->getCenterOfGravityModelEnabled() && !isFlying && !(myAvatar->getIsInWalkingState()) && !(myAvatar->getIsInSittingState()) && myAvatar->getHMDLeanRecenterEnabled()) { // then we use center of gravity model hipsMat = myAvatar->deriveBodyUsingCgModel(); } else { From ee830cdcb0ef19f7f731d6032eccefe957a7fec3 Mon Sep 17 00:00:00 2001 From: amantley Date: Fri, 12 Oct 2018 16:05:31 -0700 Subject: [PATCH 29/54] cleaned white space --- interface/src/avatar/MyAvatar.cpp | 40 +++++++++---------------------- 1 file changed, 11 insertions(+), 29 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index e130f78dc4..5e4db283a3 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -470,7 +470,6 @@ void MyAvatar::update(float deltaTime) { const float PERCENTAGE_WEIGHT_HEAD_VS_SHOULDERS_AZIMUTH = 0.0f; // 100 percent shoulders const float STANDING_HEIGHT_MULTIPLE = 1.2f; const float SITTING_HEIGHT_MULTIPLE = 0.833f; - const float COSINE_TEN_DEGREES = 0.98f; const float COSINE_THIRTY_DEGREES = 0.866f; const int SITTING_COUNT_THRESHOLD = 300; const int SQUATTY_COUNT_THRESHOLD = 600; @@ -545,12 +544,8 @@ void MyAvatar::update(float deltaTime) { _tippingPoint = newHeightReading.getTranslation().y; } _averageUserHeightCount = 1; - // setResetMode(true); setIsInSittingState(false); - // setCenterOfGravityModelEnabled(true); - // setSitStandStateChange(true); } - qCDebug(interfaceapp) << "going to stand state"; } else { _sitStandStateCount = 0; // tipping point is average height when sitting. @@ -568,19 +563,13 @@ void MyAvatar::update(float deltaTime) { _tippingPoint = newHeightReading.getTranslation().y; } _averageUserHeightCount = 1; - // setResetMode(true); setIsInSittingState(true); - // setCenterOfGravityModelEnabled(false); - // setSitStandStateChange(true); } - qCDebug(interfaceapp) << "going to sit state"; } else { - // returnValue = (offset.y > CYLINDER_TOP) || (offset.y < CYLINDER_BOTTOM); // use the mode height for the tipping point when we are standing. _tippingPoint = getCurrentStandingHeight(); _sitStandStateCount = 0; } - } } @@ -594,7 +583,7 @@ void MyAvatar::update(float deltaTime) { // draw hand azimuth vector glm::vec3 handAzimuthMidpoint = transformPoint(getTransform().getMatrix(), glm::vec3(_hipToHandController.x, 0.0f, _hipToHandController.y)); - DebugDraw::getInstance().drawRay(getWorldPosition(), handAzimuthMidpoint, glm::vec4(0.0f, 1.0f, 1.0f, 1.0f)); + DebugDraw::getInstance().drawRay(getWorldPosition(), handAzimuthMidpoint, glm::vec4(0.0f, 1.0f, 1.0f, 1.0f)); } if (_goToPending) { @@ -3909,7 +3898,12 @@ void MyAvatar::setIsInSittingState(bool isSitting) { } void MyAvatar::setIsSitStandStateLocked(bool isLocked) { + const float DEFAULT_FLOOR_HEIGHT = 0.0f; _lockSitStandState.set(isLocked); + _sitStandStateCount = 0; + _sumUserHeightSensorSpace = DEFAULT_AVATAR_HEIGHT; + _tippingPoint = DEFAULT_FLOOR_HEIGHT; + _averageUserHeightCount = 1; emit sitStandStateLockEnabledChanged(isLocked); } @@ -4156,21 +4150,17 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(MyAvatar& myAvatar, const gl const int SQUATTY_COUNT_THRESHOLD = 1800; glm::vec3 offset = extractTranslation(desiredBodyMatrix) - extractTranslation(currentBodyMatrix); - bool returnValue = false; if (myAvatar.getSitStandStateChange()) { - // qCDebug(interfaceapp) << "sit state change"; returnValue = true; - } if (myAvatar.getIsInSittingState()) { if (myAvatar.getIsSitStandStateLocked()) { returnValue = (offset.y > CYLINDER_TOP); } if (offset.y < SITTING_BOTTOM) { - // we recenter when sitting. - // qCDebug(interfaceapp) << "lean back sitting "; + // we recenter more easily when in sitting state. returnValue = true; } } else { @@ -4179,7 +4169,6 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(MyAvatar& myAvatar, const gl // finally check for squats in standing if ((myAvatar._squatCount > SQUATTY_COUNT_THRESHOLD) && !myAvatar.getIsSitStandStateLocked()) { myAvatar._squatCount = 0; - // qCDebug(interfaceapp) << "squatting "; returnValue = true; } } @@ -4194,7 +4183,6 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat if (!isActive(Rotation) && (shouldActivateRotation(myAvatar, desiredBodyMatrix, currentBodyMatrix) || hasDriveInput)) { activate(Rotation); - qCDebug(interfaceapp) << "should activate rotation true "; myAvatar.setHeadControllerFacingMovingAverage(myAvatar.getHeadControllerFacing()); } if (myAvatar.getCenterOfGravityModelEnabled()) { @@ -4210,28 +4198,22 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat if (!isActive(Horizontal) && (shouldActivateHorizontal(myAvatar, desiredBodyMatrix, currentBodyMatrix) || hasDriveInput)) { activate(Horizontal); if (myAvatar.getEnableStepResetRotation() && !myAvatar.getIsInSittingState()) { - qCDebug(interfaceapp) << "step recenter rotation true "; activate(Rotation); myAvatar.setHeadControllerFacingMovingAverage(myAvatar.getHeadControllerFacing()); } } } - - if (_velocityCount > 60) { + const int VELOCITY_COUNT_THRESHOLD = 60; + const float MINIMUM_HMD_VELOCITY = 0.1f; + if (_velocityCount > VELOCITY_COUNT_THRESHOLD) { if (!isActive(Vertical) && (shouldActivateVertical(myAvatar, desiredBodyMatrix, currentBodyMatrix) || hasDriveInput)) { activate(Vertical); } } else { - if ((glm::length(myAvatar.getControllerPoseInSensorFrame(controller::Action::HEAD).getVelocity()) > 0.1f)) { + if ((glm::length(myAvatar.getControllerPoseInSensorFrame(controller::Action::HEAD).getVelocity()) > MINIMUM_HMD_VELOCITY)) { _velocityCount++; } - if (_velocityCount > 60) { - qCDebug(interfaceapp) << "reached velocity count "; - } - } - - } else { if (!isActive(Rotation) && getForceActivateRotation()) { activate(Rotation); From 90c9e578c845df4661adeda1f8d3809d2fb9fe53 Mon Sep 17 00:00:00 2001 From: amantley Date: Fri, 12 Oct 2018 16:47:53 -0700 Subject: [PATCH 30/54] when you unlock the transitions you now start in stand state --- interface/src/avatar/MyAvatar.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 5e4db283a3..172fdac96c 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -3904,6 +3904,10 @@ void MyAvatar::setIsSitStandStateLocked(bool isLocked) { _sumUserHeightSensorSpace = DEFAULT_AVATAR_HEIGHT; _tippingPoint = DEFAULT_FLOOR_HEIGHT; _averageUserHeightCount = 1; + if (!isLocked) { + // always start the auto transition mode in standing state. + setIsInSittingState(false); + } emit sitStandStateLockEnabledChanged(isLocked); } From 8e272d6dd27c95a9a2a73dc14c6e7755a97d9887 Mon Sep 17 00:00:00 2001 From: amantley Date: Mon, 15 Oct 2018 08:43:25 -0700 Subject: [PATCH 31/54] added the correction code for when you are misslabeled as sitting while you are standing. It will now handle a sit down correctly. Also made the first approximation of state based on the average user height. This should use the user input of their height associated with their account --- interface/src/avatar/MyAvatar.cpp | 12 ++++++++++++ interface/src/avatar/MyAvatar.h | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 172fdac96c..458c3ee422 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -546,6 +546,18 @@ void MyAvatar::update(float deltaTime) { _averageUserHeightCount = 1; setIsInSittingState(false); } + } else if ((newHeightReading.getTranslation().y < (SITTING_HEIGHT_MULTIPLE * _tippingPoint)) && (angleSpine2 > COSINE_THIRTY_DEGREES)) { + _sitStandStateCount++; + if (_sitStandStateCount > SITTING_COUNT_THRESHOLD) { + _sitStandStateCount = 0; + _squatCount = 0; + if (newHeightReading.isValid()) { + _sumUserHeightSensorSpace = newHeightReading.getTranslation().y; + _tippingPoint = newHeightReading.getTranslation().y; + } + _averageUserHeightCount = 1; + setIsInSittingState(true); + } } else { _sitStandStateCount = 0; // tipping point is average height when sitting. diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 10b5510e4d..61eed672ef 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -1846,7 +1846,7 @@ private: ThreadSafeValueCache _isInSittingState { false }; int _sitStandStateCount { 0 }; int _squatCount { 0 }; - float _tippingPoint { DEFAULT_FLOOR_HEIGHT }; + float _tippingPoint { DEFAULT_AVATAR_HEIGHT }; // load avatar scripts once when rig is ready bool _shouldLoadScripts { false }; From ae3ae9ce9a081e7b41d544f038655adda975b367 Mon Sep 17 00:00:00 2001 From: amantley Date: Mon, 15 Oct 2018 09:52:34 -0700 Subject: [PATCH 32/54] put in condition for away mode so that when you take the hmd off and put it back on the initial guess to your state is made again. --- interface/src/avatar/MyAvatar.cpp | 102 +++++++++++++++++------------- 1 file changed, 57 insertions(+), 45 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 458c3ee422..4e347eebbb 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -530,58 +530,70 @@ void MyAvatar::update(float deltaTime) { glm::vec3 worldHips = transformPoint(getTransform().getMatrix(), avatarHips); glm::vec3 sensorHips = transformPoint(glm::inverse(getSensorToWorldMatrix()), worldHips); + const int VELOCITY_COUNT_THRESHOLD = 60; // put update sit stand state counts here - if (!getIsSitStandStateLocked() && (_follow._velocityCount > 60)) { - if (getIsInSittingState()) { - if (newHeightReading.getTranslation().y > (STANDING_HEIGHT_MULTIPLE * _tippingPoint)) { - // if we recenter upwards then no longer in sitting state - _sitStandStateCount++; - if (_sitStandStateCount > SITTING_COUNT_THRESHOLD) { - _sitStandStateCount = 0; - _squatCount = 0; - if (newHeightReading.isValid()) { - _sumUserHeightSensorSpace = newHeightReading.getTranslation().y; - _tippingPoint = newHeightReading.getTranslation().y; + if (!getIsSitStandStateLocked() && (_follow._velocityCount > VELOCITY_COUNT_THRESHOLD)) { + if (!getIsAway()) { + if (getIsInSittingState()) { + if (newHeightReading.getTranslation().y > (STANDING_HEIGHT_MULTIPLE * _tippingPoint)) { + // if we recenter upwards then no longer in sitting state + _sitStandStateCount++; + if (_sitStandStateCount > SITTING_COUNT_THRESHOLD) { + _sitStandStateCount = 0; + _squatCount = 0; + if (newHeightReading.isValid()) { + _sumUserHeightSensorSpace = newHeightReading.getTranslation().y; + _tippingPoint = newHeightReading.getTranslation().y; + } + _averageUserHeightCount = 1; + setIsInSittingState(false); } - _averageUserHeightCount = 1; - setIsInSittingState(false); - } - } else if ((newHeightReading.getTranslation().y < (SITTING_HEIGHT_MULTIPLE * _tippingPoint)) && (angleSpine2 > COSINE_THIRTY_DEGREES)) { - _sitStandStateCount++; - if (_sitStandStateCount > SITTING_COUNT_THRESHOLD) { - _sitStandStateCount = 0; - _squatCount = 0; - if (newHeightReading.isValid()) { - _sumUserHeightSensorSpace = newHeightReading.getTranslation().y; - _tippingPoint = newHeightReading.getTranslation().y; + } else if ((newHeightReading.getTranslation().y < (SITTING_HEIGHT_MULTIPLE * _tippingPoint)) && (angleSpine2 > COSINE_THIRTY_DEGREES)) { + _sitStandStateCount++; + if (_sitStandStateCount > SITTING_COUNT_THRESHOLD) { + _sitStandStateCount = 0; + _squatCount = 0; + if (newHeightReading.isValid()) { + _sumUserHeightSensorSpace = newHeightReading.getTranslation().y; + _tippingPoint = newHeightReading.getTranslation().y; + } + _averageUserHeightCount = 1; + setIsInSittingState(true); } - _averageUserHeightCount = 1; - setIsInSittingState(true); + } else { + _sitStandStateCount = 0; + // tipping point is average height when sitting. + _tippingPoint = averageSensorSpaceHeight; } } else { - _sitStandStateCount = 0; - // tipping point is average height when sitting. - _tippingPoint = averageSensorSpaceHeight; + // in the standing state + if ((newHeightReading.getTranslation().y < (SITTING_HEIGHT_MULTIPLE * _tippingPoint)) && (angleSpine2 > COSINE_THIRTY_DEGREES)) { + _sitStandStateCount++; + if (_sitStandStateCount > SITTING_COUNT_THRESHOLD) { + _sitStandStateCount = 0; + _squatCount = 0; + if (newHeightReading.isValid()) { + _sumUserHeightSensorSpace = newHeightReading.getTranslation().y; + _tippingPoint = newHeightReading.getTranslation().y; + } + _averageUserHeightCount = 1; + setIsInSittingState(true); + } + } else { + // use the mode height for the tipping point when we are standing. + _tippingPoint = getCurrentStandingHeight(); + _sitStandStateCount = 0; + } } } else { - // in the standing state - if ((newHeightReading.getTranslation().y < (SITTING_HEIGHT_MULTIPLE * _tippingPoint)) && (angleSpine2 > COSINE_THIRTY_DEGREES)) { - _sitStandStateCount++; - if (_sitStandStateCount > SITTING_COUNT_THRESHOLD) { - _sitStandStateCount = 0; - _squatCount = 0; - if (newHeightReading.isValid()) { - _sumUserHeightSensorSpace = newHeightReading.getTranslation().y; - _tippingPoint = newHeightReading.getTranslation().y; - } - _averageUserHeightCount = 1; - setIsInSittingState(true); - } - } else { - // use the mode height for the tipping point when we are standing. - _tippingPoint = getCurrentStandingHeight(); - _sitStandStateCount = 0; - } + // if you are away then reset the average and set state to standing. + _squatCount = 0; + _sitStandStateCount = 0; + _follow._velocityCount = 0; + _averageUserHeightCount = 1; + _sumUserHeightSensorSpace = DEFAULT_AVATAR_HEIGHT; + _tippingPoint = DEFAULT_AVATAR_HEIGHT; + setIsInSittingState(false); } } From 9ec999e15e84b7eda15462efbe5ffb109955f9c4 Mon Sep 17 00:00:00 2001 From: amantley Date: Mon, 15 Oct 2018 16:43:03 -0700 Subject: [PATCH 33/54] added condition for start up in oculus that gets the correct starting height --- interface/src/avatar/MyAvatar.cpp | 104 +++++++++++++++++------------- 1 file changed, 59 insertions(+), 45 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 4e347eebbb..c809a2d614 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -471,7 +471,9 @@ void MyAvatar::update(float deltaTime) { const float STANDING_HEIGHT_MULTIPLE = 1.2f; const float SITTING_HEIGHT_MULTIPLE = 0.833f; const float COSINE_THIRTY_DEGREES = 0.866f; - const int SITTING_COUNT_THRESHOLD = 300; + const float COSINE_TEN_DEGREES = 0.9848f; + const int SITTING_COUNT_THRESHOLD = 100; + const int STANDING_COUNT_THRESHOLD = 10; const int SQUATTY_COUNT_THRESHOLD = 600; float tau = deltaTime / HMD_FACING_TIMESCALE; @@ -530,59 +532,70 @@ void MyAvatar::update(float deltaTime) { glm::vec3 worldHips = transformPoint(getTransform().getMatrix(), avatarHips); glm::vec3 sensorHips = transformPoint(glm::inverse(getSensorToWorldMatrix()), worldHips); + glm::vec3 headUp = newHeightReading.getRotation() * glm::vec3(0.0f, 1.0f, 0.0f); + if (glm::length(headUp) > 0.0f) { + headUp = glm::normalize(headUp); + } + float angleHeadUp = glm::dot(headUp, glm::vec3(0.0f, 1.0f, 0.0f)); + const int VELOCITY_COUNT_THRESHOLD = 60; // put update sit stand state counts here - if (!getIsSitStandStateLocked() && (_follow._velocityCount > VELOCITY_COUNT_THRESHOLD)) { + if (!getIsSitStandStateLocked()) { if (!getIsAway()) { - if (getIsInSittingState()) { - if (newHeightReading.getTranslation().y > (STANDING_HEIGHT_MULTIPLE * _tippingPoint)) { - // if we recenter upwards then no longer in sitting state - _sitStandStateCount++; - if (_sitStandStateCount > SITTING_COUNT_THRESHOLD) { - _sitStandStateCount = 0; - _squatCount = 0; - if (newHeightReading.isValid()) { - _sumUserHeightSensorSpace = newHeightReading.getTranslation().y; - _tippingPoint = newHeightReading.getTranslation().y; + if ((_follow._velocityCount > VELOCITY_COUNT_THRESHOLD) || (qApp->isHMDMode() && (qApp->getActiveDisplayPlugin()->getName() == "Oculus Rift"))) { + if (getIsInSittingState()) { + if (newHeightReading.getTranslation().y > (STANDING_HEIGHT_MULTIPLE * _tippingPoint)) { + // if we recenter upwards then no longer in sitting state + _sitStandStateCount++; + if (_sitStandStateCount > STANDING_COUNT_THRESHOLD) { + _sitStandStateCount = 0; + _squatCount = 0; + if (newHeightReading.isValid()) { + _sumUserHeightSensorSpace = newHeightReading.getTranslation().y; + _tippingPoint = newHeightReading.getTranslation().y; + } + _averageUserHeightCount = 1; + setIsInSittingState(false); } - _averageUserHeightCount = 1; - setIsInSittingState(false); - } - } else if ((newHeightReading.getTranslation().y < (SITTING_HEIGHT_MULTIPLE * _tippingPoint)) && (angleSpine2 > COSINE_THIRTY_DEGREES)) { - _sitStandStateCount++; - if (_sitStandStateCount > SITTING_COUNT_THRESHOLD) { - _sitStandStateCount = 0; - _squatCount = 0; - if (newHeightReading.isValid()) { - _sumUserHeightSensorSpace = newHeightReading.getTranslation().y; - _tippingPoint = newHeightReading.getTranslation().y; + } else if ((newHeightReading.getTranslation().y < (SITTING_HEIGHT_MULTIPLE * _tippingPoint)) && (angleHeadUp > COSINE_THIRTY_DEGREES)) { + // if we are mis labelled as sitting but we are standing in the real world this will + // make sure that a real sit is still recognized so we won't be stuck in sitting unable to change state + _sitStandStateCount++; + if (_sitStandStateCount > SITTING_COUNT_THRESHOLD) { + _sitStandStateCount = 0; + _squatCount = 0; + if (newHeightReading.isValid()) { + _sumUserHeightSensorSpace = newHeightReading.getTranslation().y; + _tippingPoint = newHeightReading.getTranslation().y; + } + _averageUserHeightCount = 1; + // here we stay in sit state but reset the average height + setIsInSittingState(true); } - _averageUserHeightCount = 1; - setIsInSittingState(true); + } else { + _sitStandStateCount = 0; + // tipping point is average height when sitting. + _tippingPoint = averageSensorSpaceHeight; } } else { - _sitStandStateCount = 0; - // tipping point is average height when sitting. - _tippingPoint = averageSensorSpaceHeight; - } - } else { - // in the standing state - if ((newHeightReading.getTranslation().y < (SITTING_HEIGHT_MULTIPLE * _tippingPoint)) && (angleSpine2 > COSINE_THIRTY_DEGREES)) { - _sitStandStateCount++; - if (_sitStandStateCount > SITTING_COUNT_THRESHOLD) { - _sitStandStateCount = 0; - _squatCount = 0; - if (newHeightReading.isValid()) { - _sumUserHeightSensorSpace = newHeightReading.getTranslation().y; - _tippingPoint = newHeightReading.getTranslation().y; + // in the standing state + if ((newHeightReading.getTranslation().y < (SITTING_HEIGHT_MULTIPLE * _tippingPoint)) && (angleHeadUp > COSINE_THIRTY_DEGREES)) { + _sitStandStateCount++; + if (_sitStandStateCount > SITTING_COUNT_THRESHOLD) { + _sitStandStateCount = 0; + _squatCount = 0; + if (newHeightReading.isValid()) { + _sumUserHeightSensorSpace = newHeightReading.getTranslation().y; + _tippingPoint = newHeightReading.getTranslation().y; + } + _averageUserHeightCount = 1; + setIsInSittingState(true); } - _averageUserHeightCount = 1; - setIsInSittingState(true); + } else { + // use the mode height for the tipping point when we are standing. + _tippingPoint = getCurrentStandingHeight(); + _sitStandStateCount = 0; } - } else { - // use the mode height for the tipping point when we are standing. - _tippingPoint = getCurrentStandingHeight(); - _sitStandStateCount = 0; } } } else { @@ -4240,6 +4253,7 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat } else { if ((glm::length(myAvatar.getControllerPoseInSensorFrame(controller::Action::HEAD).getVelocity()) > MINIMUM_HMD_VELOCITY)) { _velocityCount++; + qCDebug(interfaceapp) << "velocity count is " << _velocityCount << " is away " << myAvatar.getIsAway() << " hmd mode "<< qApp->isHMDMode() << " " << qApp->getActiveDisplayPlugin()->getName(); } } } else { From 49b869c5e31c7d0b45ff51eaa54af28850cd26bf Mon Sep 17 00:00:00 2001 From: amantley Date: Mon, 15 Oct 2018 18:02:50 -0700 Subject: [PATCH 34/54] got rid of velocity count, now use 'away' to trigger when to start computing the sit stand state --- interface/src/avatar/MyAvatar.cpp | 15 +-------------- interface/src/avatar/MyAvatar.h | 1 - 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index c809a2d614..66e8570743 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -542,7 +542,7 @@ void MyAvatar::update(float deltaTime) { // put update sit stand state counts here if (!getIsSitStandStateLocked()) { if (!getIsAway()) { - if ((_follow._velocityCount > VELOCITY_COUNT_THRESHOLD) || (qApp->isHMDMode() && (qApp->getActiveDisplayPlugin()->getName() == "Oculus Rift"))) { + if (qApp->isHMDMode()) { if (getIsInSittingState()) { if (newHeightReading.getTranslation().y > (STANDING_HEIGHT_MULTIPLE * _tippingPoint)) { // if we recenter upwards then no longer in sitting state @@ -602,7 +602,6 @@ void MyAvatar::update(float deltaTime) { // if you are away then reset the average and set state to standing. _squatCount = 0; _sitStandStateCount = 0; - _follow._velocityCount = 0; _averageUserHeightCount = 1; _sumUserHeightSensorSpace = DEFAULT_AVATAR_HEIGHT; _tippingPoint = DEFAULT_AVATAR_HEIGHT; @@ -4244,18 +4243,6 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat } } } - const int VELOCITY_COUNT_THRESHOLD = 60; - const float MINIMUM_HMD_VELOCITY = 0.1f; - if (_velocityCount > VELOCITY_COUNT_THRESHOLD) { - if (!isActive(Vertical) && (shouldActivateVertical(myAvatar, desiredBodyMatrix, currentBodyMatrix) || hasDriveInput)) { - activate(Vertical); - } - } else { - if ((glm::length(myAvatar.getControllerPoseInSensorFrame(controller::Action::HEAD).getVelocity()) > MINIMUM_HMD_VELOCITY)) { - _velocityCount++; - qCDebug(interfaceapp) << "velocity count is " << _velocityCount << " is away " << myAvatar.getIsAway() << " hmd mode "<< qApp->isHMDMode() << " " << qApp->getActiveDisplayPlugin()->getName(); - } - } } else { if (!isActive(Rotation) && getForceActivateRotation()) { activate(Rotation); diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 61eed672ef..e8d9090e03 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -1760,7 +1760,6 @@ private: std::atomic _forceActivateVertical { false }; std::atomic _forceActivateHorizontal { false }; std::atomic _toggleHipsFollowing { true }; - int _velocityCount { 0 }; }; FollowHelper _follow; From 7d7fe8c08913de6fc852881df268984934c2c80a Mon Sep 17 00:00:00 2001 From: amantley Date: Mon, 15 Oct 2018 18:12:27 -0700 Subject: [PATCH 35/54] removed some cruft --- interface/src/avatar/MyAvatar.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 66e8570743..00a8e0f30e 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -510,6 +510,7 @@ void MyAvatar::update(float deltaTime) { setCurrentStandingHeight(computeStandingHeightMode(newHeightReading)); setAverageHeadRotation(computeAverageHeadRotation(getControllerPoseInAvatarFrame(controller::Action::HEAD))); } + float averageSensorSpaceHeight = _sumUserHeightSensorSpace / _averageUserHeightCount; // if the spine is straight and the head is below the default position by 5 cm then increment squatty count. const float SQUAT_THRESHOLD = 0.05f; @@ -526,12 +527,6 @@ void MyAvatar::update(float deltaTime) { _squatCount = 0; } - float averageSensorSpaceHeight = _sumUserHeightSensorSpace / _averageUserHeightCount; - - glm::vec3 avatarHips = getAbsoluteJointTranslationInObjectFrame(getJointIndex("Hips")); - glm::vec3 worldHips = transformPoint(getTransform().getMatrix(), avatarHips); - glm::vec3 sensorHips = transformPoint(glm::inverse(getSensorToWorldMatrix()), worldHips); - glm::vec3 headUp = newHeightReading.getRotation() * glm::vec3(0.0f, 1.0f, 0.0f); if (glm::length(headUp) > 0.0f) { headUp = glm::normalize(headUp); From 952b1122713192f70bb5b1df4fb8ae987da16522 Mon Sep 17 00:00:00 2001 From: amantley Date: Tue, 16 Oct 2018 15:10:26 -0700 Subject: [PATCH 36/54] changed the transition times to make them shorter sit == 3sec stand == 1sec, also added failsafe for when the average height is above 5ft. this can recover from a missed transition to standing. --- interface/src/avatar/MyAvatar.cpp | 153 ++++++++++++++---------------- interface/src/avatar/MyAvatar.h | 10 +- 2 files changed, 76 insertions(+), 87 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 00a8e0f30e..b59ff675e1 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -464,17 +464,72 @@ void MyAvatar::reset(bool andRecenter, bool andReload, bool andHead) { } } +void MyAvatar::updateSitStandState(float newHeightReading, float angleHeadUp) { + const float STANDING_HEIGHT_MULTIPLE = 1.2f; + const float SITTING_HEIGHT_MULTIPLE = 0.833f; + const int SITTING_COUNT_THRESHOLD = 180; + const int STANDING_COUNT_THRESHOLD = 60; + const int SQUATTY_COUNT_THRESHOLD = 600; + + // qCDebug(interfaceapp) << "locked " << getIsSitStandStateLocked() << " away " << getIsAway() << " hmd " << qApp->isHMDMode() << " user height " << _userHeight.get(); + if (!getIsSitStandStateLocked() && !getIsAway() && qApp->isHMDMode()) { + if (getIsInSittingState()) { + if (newHeightReading > (STANDING_HEIGHT_MULTIPLE * _tippingPoint)) { + // if we recenter upwards then no longer in sitting state + _sitStandStateCount++; + if (_sitStandStateCount > STANDING_COUNT_THRESHOLD) { + _sumUserHeightSensorSpace = newHeightReading; + _tippingPoint = newHeightReading; + setIsInSittingState(false); + } + } else if (newHeightReading < (SITTING_HEIGHT_MULTIPLE * _tippingPoint)) { + // if we are mis labelled as sitting but we are standing in the real world this will + // make sure that a real sit is still recognized so we won't be stuck in sitting unable to change state + _sitStandStateCount++; + if (_sitStandStateCount > SITTING_COUNT_THRESHOLD) { + _sumUserHeightSensorSpace = newHeightReading; + _tippingPoint = newHeightReading; + // here we stay in sit state but reset the average height + setIsInSittingState(true); + } + } else { + // sanity check if average height greater than 5ft they are not sitting(or get off your dangerous barstool please) + if (_sumUserHeightSensorSpace > 1.52f) { + setIsInSittingState(true); + } else { + // tipping point is average height when sitting. + _tippingPoint = _sumUserHeightSensorSpace; + _sitStandStateCount = 0; + } + } + } else { + // in the standing state + if (newHeightReading < (SITTING_HEIGHT_MULTIPLE * _tippingPoint)) { + _sitStandStateCount++; + if (_sitStandStateCount > SITTING_COUNT_THRESHOLD) { + _sumUserHeightSensorSpace = newHeightReading; + _tippingPoint = newHeightReading; + setIsInSittingState(true); + } + } else { + // use the mode height for the tipping point when we are standing. + _tippingPoint = getCurrentStandingHeight(); + _sitStandStateCount = 0; + } + } + } else { + // if you are away then reset the average and set state to standing. + _sumUserHeightSensorSpace = _userHeight.get(); + _tippingPoint = _userHeight.get(); + setIsInSittingState(false); + } +} + void MyAvatar::update(float deltaTime) { // update moving average of HMD facing in xz plane. const float HMD_FACING_TIMESCALE = getRotationRecenterFilterLength(); const float PERCENTAGE_WEIGHT_HEAD_VS_SHOULDERS_AZIMUTH = 0.0f; // 100 percent shoulders - const float STANDING_HEIGHT_MULTIPLE = 1.2f; - const float SITTING_HEIGHT_MULTIPLE = 0.833f; const float COSINE_THIRTY_DEGREES = 0.866f; - const float COSINE_TEN_DEGREES = 0.9848f; - const int SITTING_COUNT_THRESHOLD = 100; - const int STANDING_COUNT_THRESHOLD = 10; - const int SQUATTY_COUNT_THRESHOLD = 600; float tau = deltaTime / HMD_FACING_TIMESCALE; setHipToHandController(computeHandAzimuth()); @@ -504,13 +559,11 @@ void MyAvatar::update(float deltaTime) { controller::Pose newHeightReading = getControllerPoseInSensorFrame(controller::Action::HEAD); if (newHeightReading.isValid()) { int newHeightReadingInCentimeters = glm::floor(newHeightReading.getTranslation().y * CENTIMETERS_PER_METER); - _sumUserHeightSensorSpace += newHeightReading.getTranslation().y; - _averageUserHeightCount++; + _sumUserHeightSensorSpace = lerp(_sumUserHeightSensorSpace, newHeightReading.getTranslation().y, 0.01f); _recentModeReadings.insert(newHeightReadingInCentimeters); setCurrentStandingHeight(computeStandingHeightMode(newHeightReading)); setAverageHeadRotation(computeAverageHeadRotation(getControllerPoseInAvatarFrame(controller::Action::HEAD))); } - float averageSensorSpaceHeight = _sumUserHeightSensorSpace / _averageUserHeightCount; // if the spine is straight and the head is below the default position by 5 cm then increment squatty count. const float SQUAT_THRESHOLD = 0.05f; @@ -533,76 +586,8 @@ void MyAvatar::update(float deltaTime) { } float angleHeadUp = glm::dot(headUp, glm::vec3(0.0f, 1.0f, 0.0f)); - const int VELOCITY_COUNT_THRESHOLD = 60; // put update sit stand state counts here - if (!getIsSitStandStateLocked()) { - if (!getIsAway()) { - if (qApp->isHMDMode()) { - if (getIsInSittingState()) { - if (newHeightReading.getTranslation().y > (STANDING_HEIGHT_MULTIPLE * _tippingPoint)) { - // if we recenter upwards then no longer in sitting state - _sitStandStateCount++; - if (_sitStandStateCount > STANDING_COUNT_THRESHOLD) { - _sitStandStateCount = 0; - _squatCount = 0; - if (newHeightReading.isValid()) { - _sumUserHeightSensorSpace = newHeightReading.getTranslation().y; - _tippingPoint = newHeightReading.getTranslation().y; - } - _averageUserHeightCount = 1; - setIsInSittingState(false); - } - } else if ((newHeightReading.getTranslation().y < (SITTING_HEIGHT_MULTIPLE * _tippingPoint)) && (angleHeadUp > COSINE_THIRTY_DEGREES)) { - // if we are mis labelled as sitting but we are standing in the real world this will - // make sure that a real sit is still recognized so we won't be stuck in sitting unable to change state - _sitStandStateCount++; - if (_sitStandStateCount > SITTING_COUNT_THRESHOLD) { - _sitStandStateCount = 0; - _squatCount = 0; - if (newHeightReading.isValid()) { - _sumUserHeightSensorSpace = newHeightReading.getTranslation().y; - _tippingPoint = newHeightReading.getTranslation().y; - } - _averageUserHeightCount = 1; - // here we stay in sit state but reset the average height - setIsInSittingState(true); - } - } else { - _sitStandStateCount = 0; - // tipping point is average height when sitting. - _tippingPoint = averageSensorSpaceHeight; - } - } else { - // in the standing state - if ((newHeightReading.getTranslation().y < (SITTING_HEIGHT_MULTIPLE * _tippingPoint)) && (angleHeadUp > COSINE_THIRTY_DEGREES)) { - _sitStandStateCount++; - if (_sitStandStateCount > SITTING_COUNT_THRESHOLD) { - _sitStandStateCount = 0; - _squatCount = 0; - if (newHeightReading.isValid()) { - _sumUserHeightSensorSpace = newHeightReading.getTranslation().y; - _tippingPoint = newHeightReading.getTranslation().y; - } - _averageUserHeightCount = 1; - setIsInSittingState(true); - } - } else { - // use the mode height for the tipping point when we are standing. - _tippingPoint = getCurrentStandingHeight(); - _sitStandStateCount = 0; - } - } - } - } else { - // if you are away then reset the average and set state to standing. - _squatCount = 0; - _sitStandStateCount = 0; - _averageUserHeightCount = 1; - _sumUserHeightSensorSpace = DEFAULT_AVATAR_HEIGHT; - _tippingPoint = DEFAULT_AVATAR_HEIGHT; - setIsInSittingState(false); - } - } + updateSitStandState(newHeightReading.getTranslation().y, angleHeadUp); if (_drawAverageFacingEnabled) { auto sensorHeadPose = getControllerPoseInSensorFrame(controller::Action::HEAD); @@ -3917,6 +3902,9 @@ void MyAvatar::setIsInWalkingState(bool isWalking) { } void MyAvatar::setIsInSittingState(bool isSitting) { + _sitStandStateCount = 0; + _squatCount = 0; + // 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); if (isSitting) { @@ -3929,12 +3917,10 @@ void MyAvatar::setIsInSittingState(bool isSitting) { } void MyAvatar::setIsSitStandStateLocked(bool isLocked) { - const float DEFAULT_FLOOR_HEIGHT = 0.0f; _lockSitStandState.set(isLocked); _sitStandStateCount = 0; - _sumUserHeightSensorSpace = DEFAULT_AVATAR_HEIGHT; - _tippingPoint = DEFAULT_FLOOR_HEIGHT; - _averageUserHeightCount = 1; + _sumUserHeightSensorSpace = _userHeight.get(); + _tippingPoint = _userHeight.get(); if (!isLocked) { // always start the auto transition mode in standing state. setIsInSittingState(false); @@ -4238,6 +4224,9 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat } } } + if (!isActive(Vertical) && (shouldActivateVertical(myAvatar, desiredBodyMatrix, currentBodyMatrix) || hasDriveInput)) { + activate(Vertical); + } } else { if (!isActive(Rotation) && getForceActivateRotation()) { activate(Rotation); diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index e8d9090e03..59f9145404 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -1116,6 +1116,7 @@ public: float getSprintSpeed() const; void setSitStandStateChange(bool stateChanged); float getSitStandStateChange() const; + void updateSitStandState(float newHeightReading, float angleHeadUp); QVector getScriptUrls(); @@ -1830,10 +1831,9 @@ private: const float DEFAULT_FLOOR_HEIGHT = 0.0f; // height of user in sensor space, when standing erect. - ThreadSafeValueCache _userHeight{ DEFAULT_AVATAR_HEIGHT }; - float _sumUserHeightSensorSpace{ DEFAULT_AVATAR_HEIGHT }; - int _averageUserHeightCount{ 1 }; - bool _sitStandStateChange{ false }; + ThreadSafeValueCache _userHeight { DEFAULT_AVATAR_HEIGHT }; + float _sumUserHeightSensorSpace { _userHeight.get() }; + bool _sitStandStateChange { false }; ThreadSafeValueCache _lockSitStandState { false }; // max unscaled forward movement speed @@ -1845,7 +1845,7 @@ private: ThreadSafeValueCache _isInSittingState { false }; int _sitStandStateCount { 0 }; int _squatCount { 0 }; - float _tippingPoint { DEFAULT_AVATAR_HEIGHT }; + float _tippingPoint { _userHeight.get() }; // load avatar scripts once when rig is ready bool _shouldLoadScripts { false }; From cf7dc49499814f286b0e19c7ad75482b9557e367 Mon Sep 17 00:00:00 2001 From: amantley Date: Tue, 16 Oct 2018 16:04:31 -0700 Subject: [PATCH 37/54] removed a commment and changed the sanity check to be a const instead of a magic number --- interface/src/avatar/MyAvatar.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index b59ff675e1..742dda72b2 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -470,8 +470,8 @@ void MyAvatar::updateSitStandState(float newHeightReading, float angleHeadUp) { const int SITTING_COUNT_THRESHOLD = 180; const int STANDING_COUNT_THRESHOLD = 60; const int SQUATTY_COUNT_THRESHOLD = 600; + const float SITTING_UPPER_BOUND = 1.52f; - // qCDebug(interfaceapp) << "locked " << getIsSitStandStateLocked() << " away " << getIsAway() << " hmd " << qApp->isHMDMode() << " user height " << _userHeight.get(); if (!getIsSitStandStateLocked() && !getIsAway() && qApp->isHMDMode()) { if (getIsInSittingState()) { if (newHeightReading > (STANDING_HEIGHT_MULTIPLE * _tippingPoint)) { @@ -494,7 +494,7 @@ void MyAvatar::updateSitStandState(float newHeightReading, float angleHeadUp) { } } else { // sanity check if average height greater than 5ft they are not sitting(or get off your dangerous barstool please) - if (_sumUserHeightSensorSpace > 1.52f) { + if (_sumUserHeightSensorSpace > SITTING_UPPER_BOUND) { setIsInSittingState(true); } else { // tipping point is average height when sitting. From 1764531822f86b160a2e509c6e46820d9a088f1c Mon Sep 17 00:00:00 2001 From: amantley Date: Tue, 16 Oct 2018 16:31:55 -0700 Subject: [PATCH 38/54] removed hand azimuth changes, that fixed azimuth when hands go behind origin of MyAvatar, these changes will be in a separate pr --- interface/src/avatar/MyAvatar.cpp | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 742dda72b2..7a35b0ee56 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -941,13 +941,6 @@ void MyAvatar::updateFromHMDSensorMatrix(const glm::mat4& hmdSensorMatrix) { // Find the vector halfway between the hip to hand azimuth vectors // This midpoint hand azimuth is in Avatar space glm::vec2 MyAvatar::computeHandAzimuth() const { - int spine2Index = _skeletonModel->getRig().indexOfJoint("Spine2"); - glm::vec3 azimuthOrigin(0.0f,0.0f,0.0f); - if (!(spine2Index < 0)) { - // use the spine for the azimuth origin. - azimuthOrigin = getAbsoluteJointTranslationInObjectFrame(spine2Index); - } - controller::Pose leftHandPoseAvatarSpace = getLeftHandPose(); controller::Pose rightHandPoseAvatarSpace = getRightHandPose(); controller::Pose headPoseAvatarSpace = getControllerPoseInAvatarFrame(controller::Action::HEAD); @@ -955,13 +948,11 @@ glm::vec2 MyAvatar::computeHandAzimuth() const { glm::vec2 latestHipToHandController = _hipToHandController; if (leftHandPoseAvatarSpace.isValid() && rightHandPoseAvatarSpace.isValid() && headPoseAvatarSpace.isValid()) { - glm::vec3 rightHandOffset = rightHandPoseAvatarSpace.translation - azimuthOrigin; - glm::vec3 leftHandOffset = leftHandPoseAvatarSpace.translation - azimuthOrigin; // we need the old azimuth reading to prevent flipping the facing direction 180 // in the case where the hands go from being slightly less than 180 apart to slightly more than 180 apart. glm::vec2 oldAzimuthReading = _hipToHandController; - if ((glm::length(glm::vec2(rightHandOffset.x, rightHandOffset.z)) > 0.0f) && (glm::length(glm::vec2(leftHandOffset.x, leftHandOffset.z)) > 0.0f)) { - latestHipToHandController = lerp(glm::normalize(glm::vec2(rightHandOffset.x, rightHandOffset.z)), glm::normalize(glm::vec2(leftHandOffset.x, leftHandOffset.z)), HALFWAY); + if ((glm::length(glm::vec2(rightHandPoseAvatarSpace.translation.x, rightHandPoseAvatarSpace.translation.z)) > 0.0f) && (glm::length(glm::vec2(leftHandPoseAvatarSpace.translation.x, leftHandPoseAvatarSpace.translation.z)) > 0.0f)) { + latestHipToHandController = lerp(glm::normalize(glm::vec2(rightHandPoseAvatarSpace.translation.x, rightHandPoseAvatarSpace.translation.z)), glm::normalize(glm::vec2(leftHandPoseAvatarSpace.translation.x, leftHandPoseAvatarSpace.translation.z)), HALFWAY); } else { latestHipToHandController = glm::vec2(0.0f, -1.0f); } From baeccebfb9e3349f238adc7d4175dbcf7e1c0adb Mon Sep 17 00:00:00 2001 From: amantley Date: Tue, 16 Oct 2018 17:45:55 -0700 Subject: [PATCH 39/54] changed the transition times to make the sit longer and the stand shorter --- interface/src/avatar/MyAvatar.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 7a35b0ee56..b85f19a06d 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -467,8 +467,8 @@ void MyAvatar::reset(bool andRecenter, bool andReload, bool andHead) { void MyAvatar::updateSitStandState(float newHeightReading, float angleHeadUp) { const float STANDING_HEIGHT_MULTIPLE = 1.2f; const float SITTING_HEIGHT_MULTIPLE = 0.833f; - const int SITTING_COUNT_THRESHOLD = 180; - const int STANDING_COUNT_THRESHOLD = 60; + const int SITTING_COUNT_THRESHOLD = 240; + const int STANDING_COUNT_THRESHOLD = 20; const int SQUATTY_COUNT_THRESHOLD = 600; const float SITTING_UPPER_BOUND = 1.52f; @@ -495,7 +495,7 @@ void MyAvatar::updateSitStandState(float newHeightReading, float angleHeadUp) { } else { // sanity check if average height greater than 5ft they are not sitting(or get off your dangerous barstool please) if (_sumUserHeightSensorSpace > SITTING_UPPER_BOUND) { - setIsInSittingState(true); + setIsInSittingState(false); } else { // tipping point is average height when sitting. _tippingPoint = _sumUserHeightSensorSpace; @@ -4192,7 +4192,6 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat if (myAvatar.getHMDLeanRecenterEnabled() && qApp->getCamera().getMode() != CAMERA_MODE_MIRROR) { - if (!isActive(Rotation) && (shouldActivateRotation(myAvatar, desiredBodyMatrix, currentBodyMatrix) || hasDriveInput)) { activate(Rotation); myAvatar.setHeadControllerFacingMovingAverage(myAvatar.getHeadControllerFacing()); From cd7af8b6052c887276e552b99be6a341530a459b Mon Sep 17 00:00:00 2001 From: amantley Date: Wed, 17 Oct 2018 08:51:40 -0700 Subject: [PATCH 40/54] changed the name of sumuserheightsensorspace to averageuserheightSensorSpace --- interface/src/avatar/MyAvatar.cpp | 16 ++++++++-------- interface/src/avatar/MyAvatar.h | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index b85f19a06d..9fe91e44b9 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -478,7 +478,7 @@ void MyAvatar::updateSitStandState(float newHeightReading, float angleHeadUp) { // if we recenter upwards then no longer in sitting state _sitStandStateCount++; if (_sitStandStateCount > STANDING_COUNT_THRESHOLD) { - _sumUserHeightSensorSpace = newHeightReading; + _averageUserHeightSensorSpace = newHeightReading; _tippingPoint = newHeightReading; setIsInSittingState(false); } @@ -487,18 +487,18 @@ void MyAvatar::updateSitStandState(float newHeightReading, float angleHeadUp) { // make sure that a real sit is still recognized so we won't be stuck in sitting unable to change state _sitStandStateCount++; if (_sitStandStateCount > SITTING_COUNT_THRESHOLD) { - _sumUserHeightSensorSpace = newHeightReading; + _averageUserHeightSensorSpace = newHeightReading; _tippingPoint = newHeightReading; // here we stay in sit state but reset the average height setIsInSittingState(true); } } else { // sanity check if average height greater than 5ft they are not sitting(or get off your dangerous barstool please) - if (_sumUserHeightSensorSpace > SITTING_UPPER_BOUND) { + if (_averageUserHeightSensorSpace > SITTING_UPPER_BOUND) { setIsInSittingState(false); } else { // tipping point is average height when sitting. - _tippingPoint = _sumUserHeightSensorSpace; + _tippingPoint = _averageUserHeightSensorSpace; _sitStandStateCount = 0; } } @@ -507,7 +507,7 @@ void MyAvatar::updateSitStandState(float newHeightReading, float angleHeadUp) { if (newHeightReading < (SITTING_HEIGHT_MULTIPLE * _tippingPoint)) { _sitStandStateCount++; if (_sitStandStateCount > SITTING_COUNT_THRESHOLD) { - _sumUserHeightSensorSpace = newHeightReading; + _averageUserHeightSensorSpace = newHeightReading; _tippingPoint = newHeightReading; setIsInSittingState(true); } @@ -519,7 +519,7 @@ void MyAvatar::updateSitStandState(float newHeightReading, float angleHeadUp) { } } else { // if you are away then reset the average and set state to standing. - _sumUserHeightSensorSpace = _userHeight.get(); + _averageUserHeightSensorSpace = _userHeight.get(); _tippingPoint = _userHeight.get(); setIsInSittingState(false); } @@ -559,7 +559,7 @@ void MyAvatar::update(float deltaTime) { controller::Pose newHeightReading = getControllerPoseInSensorFrame(controller::Action::HEAD); if (newHeightReading.isValid()) { int newHeightReadingInCentimeters = glm::floor(newHeightReading.getTranslation().y * CENTIMETERS_PER_METER); - _sumUserHeightSensorSpace = lerp(_sumUserHeightSensorSpace, newHeightReading.getTranslation().y, 0.01f); + _averageUserHeightSensorSpace = lerp(_averageUserHeightSensorSpace, newHeightReading.getTranslation().y, 0.01f); _recentModeReadings.insert(newHeightReadingInCentimeters); setCurrentStandingHeight(computeStandingHeightMode(newHeightReading)); setAverageHeadRotation(computeAverageHeadRotation(getControllerPoseInAvatarFrame(controller::Action::HEAD))); @@ -3910,7 +3910,7 @@ void MyAvatar::setIsInSittingState(bool isSitting) { void MyAvatar::setIsSitStandStateLocked(bool isLocked) { _lockSitStandState.set(isLocked); _sitStandStateCount = 0; - _sumUserHeightSensorSpace = _userHeight.get(); + _averageUserHeightSensorSpace = _userHeight.get(); _tippingPoint = _userHeight.get(); if (!isLocked) { // always start the auto transition mode in standing state. diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 59f9145404..d1ba0fd9cf 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -1832,7 +1832,7 @@ private: // height of user in sensor space, when standing erect. ThreadSafeValueCache _userHeight { DEFAULT_AVATAR_HEIGHT }; - float _sumUserHeightSensorSpace { _userHeight.get() }; + float _averageUserHeightSensorSpace { _userHeight.get() }; bool _sitStandStateChange { false }; ThreadSafeValueCache _lockSitStandState { false }; From b9a2f19d302f87b74a13d75f45a0285883914d3d Mon Sep 17 00:00:00 2001 From: amantley Date: Thu, 18 Oct 2018 16:39:50 -0700 Subject: [PATCH 41/54] made all the suggested corrections except the dropdown qml. --- .../resources/qml/hifi/avatarapp/Settings.qml | 36 +++++++++--- interface/src/avatar/MyAvatar.cpp | 55 ++++++++++--------- interface/src/avatar/MyAvatar.h | 9 +-- 3 files changed, 62 insertions(+), 38 deletions(-) diff --git a/interface/resources/qml/hifi/avatarapp/Settings.qml b/interface/resources/qml/hifi/avatarapp/Settings.qml index 8749079940..fd72d70106 100644 --- a/interface/resources/qml/hifi/avatarapp/Settings.qml +++ b/interface/resources/qml/hifi/avatarapp/Settings.qml @@ -354,14 +354,36 @@ Rectangle { // "Lock State" Checkbox HifiControlsUit.CheckBox { - id: lockSitStandStateCheckbox; - visible: activeTab == "nearbyTab"; - anchors.right: reloadNearbyContainer.left; - anchors.rightMargin: 20; - checked: settings.lockStateEnabled; - text: "lock"; - boxSize: 24; + id: lockSitStandStateCheckbox + visible: activeTab == "nearbyTab" + anchors.right: reloadNearbyContainer.left + anchors.rightMargin: 20 + checked: settings.lockStateEnabled + text: "lock" + boxSize: 24 } + + // sit stand combo box + HifiControlsUit.ComboBox { + id: boxy + //textRole: "text" + currentIndex: 2 + model: ListModel { + id: cbItems + ListElement { text: "Force Sitting"; color: "Yellow" } + ListElement { text: "Force Standing"; color: "Green" } + ListElement { text: "Auto Mode"; color: "Brown" } + ListElement { text: "Disable Recentering"; color: "Red" } + } + //displayText: "fred" + //label: cbItems.get(currentIndex).text + width: 200 + onCurrentIndexChanged: { + console.debug(cbItems.get(currentIndex).text + ", " + cbItems.get(currentIndex).color) + console.debug("line 2") + } + } + } ColumnLayout { diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 9fe91e44b9..2c9b83b636 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -464,20 +464,19 @@ void MyAvatar::reset(bool andRecenter, bool andReload, bool andHead) { } } -void MyAvatar::updateSitStandState(float newHeightReading, float angleHeadUp) { +void MyAvatar::updateSitStandState(float newHeightReading, float dt) { const float STANDING_HEIGHT_MULTIPLE = 1.2f; const float SITTING_HEIGHT_MULTIPLE = 0.833f; - const int SITTING_COUNT_THRESHOLD = 240; - const int STANDING_COUNT_THRESHOLD = 20; - const int SQUATTY_COUNT_THRESHOLD = 600; + const float SITTING_TIMEOUT = 4.0f; // 4 seconds + const float STANDING_TIMEOUT = 0.3333f; // 1/3 second const float SITTING_UPPER_BOUND = 1.52f; if (!getIsSitStandStateLocked() && !getIsAway() && qApp->isHMDMode()) { if (getIsInSittingState()) { if (newHeightReading > (STANDING_HEIGHT_MULTIPLE * _tippingPoint)) { // if we recenter upwards then no longer in sitting state - _sitStandStateCount++; - if (_sitStandStateCount > STANDING_COUNT_THRESHOLD) { + _sitStandStateTimer += dt; + if (_sitStandStateTimer > STANDING_TIMEOUT) { _averageUserHeightSensorSpace = newHeightReading; _tippingPoint = newHeightReading; setIsInSittingState(false); @@ -485,8 +484,8 @@ void MyAvatar::updateSitStandState(float newHeightReading, float angleHeadUp) { } else if (newHeightReading < (SITTING_HEIGHT_MULTIPLE * _tippingPoint)) { // if we are mis labelled as sitting but we are standing in the real world this will // make sure that a real sit is still recognized so we won't be stuck in sitting unable to change state - _sitStandStateCount++; - if (_sitStandStateCount > SITTING_COUNT_THRESHOLD) { + _sitStandStateTimer += dt; + if (_sitStandStateTimer > SITTING_TIMEOUT) { _averageUserHeightSensorSpace = newHeightReading; _tippingPoint = newHeightReading; // here we stay in sit state but reset the average height @@ -499,14 +498,14 @@ void MyAvatar::updateSitStandState(float newHeightReading, float angleHeadUp) { } else { // tipping point is average height when sitting. _tippingPoint = _averageUserHeightSensorSpace; - _sitStandStateCount = 0; + _sitStandStateTimer = 0.0f; } } } else { // in the standing state if (newHeightReading < (SITTING_HEIGHT_MULTIPLE * _tippingPoint)) { - _sitStandStateCount++; - if (_sitStandStateCount > SITTING_COUNT_THRESHOLD) { + _sitStandStateTimer += dt; + if (_sitStandStateTimer > SITTING_TIMEOUT) { _averageUserHeightSensorSpace = newHeightReading; _tippingPoint = newHeightReading; setIsInSittingState(true); @@ -514,7 +513,7 @@ void MyAvatar::updateSitStandState(float newHeightReading, float angleHeadUp) { } else { // use the mode height for the tipping point when we are standing. _tippingPoint = getCurrentStandingHeight(); - _sitStandStateCount = 0; + _sitStandStateTimer = 0.0f; } } } else { @@ -530,6 +529,7 @@ void MyAvatar::update(float deltaTime) { const float HMD_FACING_TIMESCALE = getRotationRecenterFilterLength(); const float PERCENTAGE_WEIGHT_HEAD_VS_SHOULDERS_AZIMUTH = 0.0f; // 100 percent shoulders const float COSINE_THIRTY_DEGREES = 0.866f; + const float SQUATTY_TIMEOUT = 30.0f; // 30 seconds float tau = deltaTime / HMD_FACING_TIMESCALE; setHipToHandController(computeHandAzimuth()); @@ -575,19 +575,17 @@ void MyAvatar::update(float deltaTime) { } float angleSpine2 = glm::dot(upSpine2, glm::vec3(0.0f, 1.0f, 0.0f)); if (getControllerPoseInAvatarFrame(controller::Action::HEAD).getTranslation().y < (headDefaultPositionAvatarSpace.y - SQUAT_THRESHOLD) && (angleSpine2 > COSINE_THIRTY_DEGREES)) { - _squatCount++; + _squatTimer += deltaTime; + if (_squatTimer > SQUATTY_TIMEOUT) { + _squatTimer = 0.0f; + _follow._squatDetected = true; + } } else { - _squatCount = 0; + _squatTimer = 0.0f; } - glm::vec3 headUp = newHeightReading.getRotation() * glm::vec3(0.0f, 1.0f, 0.0f); - if (glm::length(headUp) > 0.0f) { - headUp = glm::normalize(headUp); - } - float angleHeadUp = glm::dot(headUp, glm::vec3(0.0f, 1.0f, 0.0f)); - // put update sit stand state counts here - updateSitStandState(newHeightReading.getTranslation().y, angleHeadUp); + updateSitStandState(newHeightReading.getTranslation().y, deltaTime); if (_drawAverageFacingEnabled) { auto sensorHeadPose = getControllerPoseInSensorFrame(controller::Action::HEAD); @@ -3893,8 +3891,8 @@ void MyAvatar::setIsInWalkingState(bool isWalking) { } void MyAvatar::setIsInSittingState(bool isSitting) { - _sitStandStateCount = 0; - _squatCount = 0; + _sitStandStateTimer = 0.0f; + _squatTimer = 0.0f; // 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); @@ -3909,7 +3907,8 @@ void MyAvatar::setIsInSittingState(bool isSitting) { void MyAvatar::setIsSitStandStateLocked(bool isLocked) { _lockSitStandState.set(isLocked); - _sitStandStateCount = 0; + _sitStandStateTimer = 0.0f; + _squatTimer = 0.0f; _averageUserHeightSensorSpace = _userHeight.get(); _tippingPoint = _userHeight.get(); if (!isLocked) { @@ -4155,7 +4154,7 @@ bool MyAvatar::FollowHelper::shouldActivateHorizontalCG(MyAvatar& myAvatar) cons return stepDetected; } -bool MyAvatar::FollowHelper::shouldActivateVertical(MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const { +bool MyAvatar::FollowHelper::shouldActivateVertical(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const { const float CYLINDER_TOP = 0.1f; const float CYLINDER_BOTTOM = -1.5f; const float SITTING_BOTTOM = -0.02f; @@ -4179,8 +4178,7 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(MyAvatar& myAvatar, const gl // in the standing state returnValue = (offset.y > CYLINDER_TOP) || (offset.y < CYLINDER_BOTTOM); // finally check for squats in standing - if ((myAvatar._squatCount > SQUATTY_COUNT_THRESHOLD) && !myAvatar.getIsSitStandStateLocked()) { - myAvatar._squatCount = 0; + if (_squatDetected) { returnValue = true; } } @@ -4216,6 +4214,9 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat } if (!isActive(Vertical) && (shouldActivateVertical(myAvatar, desiredBodyMatrix, currentBodyMatrix) || hasDriveInput)) { activate(Vertical); + if (_squatDetected) { + _squatDetected = false; + } } } else { if (!isActive(Rotation) && getForceActivateRotation()) { diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index d1ba0fd9cf..be8b5fa1b2 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -1116,7 +1116,7 @@ public: float getSprintSpeed() const; void setSitStandStateChange(bool stateChanged); float getSitStandStateChange() const; - void updateSitStandState(float newHeightReading, float angleHeadUp); + void updateSitStandState(float newHeightReading, float dt); QVector getScriptUrls(); @@ -1744,7 +1744,7 @@ private: float getMaxTimeRemaining() const; void decrementTimeRemaining(float dt); bool shouldActivateRotation(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const; - bool shouldActivateVertical(MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) 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; void prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat4& bodySensorMatrix, const glm::mat4& currentBodyMatrix, bool hasDriveInput); @@ -1757,6 +1757,7 @@ private: void setForceActivateHorizontal(bool val); bool getToggleHipsFollowing() const; void setToggleHipsFollowing(bool followHead); + bool _squatDetected { false }; std::atomic _forceActivateRotation { false }; std::atomic _forceActivateVertical { false }; std::atomic _forceActivateHorizontal { false }; @@ -1843,8 +1844,8 @@ private: float _walkSpeedScalar { AVATAR_WALK_SPEED_SCALAR }; bool _isInWalkingState { false }; ThreadSafeValueCache _isInSittingState { false }; - int _sitStandStateCount { 0 }; - int _squatCount { 0 }; + float _sitStandStateTimer { 0.0f }; + float _squatTimer { 0.0f }; float _tippingPoint { _userHeight.get() }; // load avatar scripts once when rig is ready From 0837f790ebd748add984b1ac2cd21a34909fa512 Mon Sep 17 00:00:00 2001 From: amantley Date: Fri, 19 Oct 2018 07:46:16 -0700 Subject: [PATCH 42/54] combo box changes --- .../resources/qml/hifi/avatarapp/Settings.qml | 23 +++++++++++++++++-- interface/src/avatar/MyAvatar.cpp | 1 + 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/interface/resources/qml/hifi/avatarapp/Settings.qml b/interface/resources/qml/hifi/avatarapp/Settings.qml index fd72d70106..64ae03237c 100644 --- a/interface/resources/qml/hifi/avatarapp/Settings.qml +++ b/interface/resources/qml/hifi/avatarapp/Settings.qml @@ -366,7 +366,7 @@ Rectangle { // sit stand combo box HifiControlsUit.ComboBox { id: boxy - //textRole: "text" + comboBox.textRole: "text" currentIndex: 2 model: ListModel { id: cbItems @@ -378,7 +378,26 @@ Rectangle { //displayText: "fred" //label: cbItems.get(currentIndex).text width: 200 - onCurrentIndexChanged: { + onCurrentIndexChanged: { + if (cbItems.get(currentIndex).text === "Force Sitting") { + sitRadiobutton.checked = true + lockSitStandStateCheckbox.checked = true + settings.lockStateEnabled = true + settings.sittingEnabled = true + } else if (cbItems.get(currentIndex).text === "Force Standing") { + sitRadiobutton.checked = false + lockSitStandStateCheckbox.checked = true + settings.lockStateEnabled = true + settings.sittingEnabled = false + } else if (cbItems.get(currentIndex).text === "auto") { + sitRadiobutton.checked = false + lockSitStandStateCheckbox.checked = false + settings.lockStateEnabled = false + settings.sittingEnabled = false + } else if (cbItems.get(currentIndex).text === "Disable Recentering") { + settings.lockStateEnabled = false + settings.sittingEnabled = false + } console.debug(cbItems.get(currentIndex).text + ", " + cbItems.get(currentIndex).color) console.debug("line 2") } diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 2c9b83b636..95141d614f 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -533,6 +533,7 @@ void MyAvatar::update(float deltaTime) { float tau = deltaTime / HMD_FACING_TIMESCALE; setHipToHandController(computeHandAzimuth()); + qCDebug(interfaceapp) << " the sit state is " << _isInSittingState.get() << " the lock is " << _lockSitStandState.get(); // put the average hand azimuth into sensor space. // then mix it with head facing direction to determine rotation recenter From a43985ef64088a88b02ab2bf11a1788fe611a6cd Mon Sep 17 00:00:00 2001 From: amantley Date: Fri, 19 Oct 2018 16:03:53 -0700 Subject: [PATCH 43/54] combo box for recenter model is added --- interface/resources/qml/hifi/AvatarApp.qml | 3 +- .../resources/qml/hifi/avatarapp/Settings.qml | 85 +------------------ interface/src/avatar/MyAvatar.cpp | 35 +++++++- interface/src/avatar/MyAvatar.h | 24 +++++- scripts/system/avatarapp.js | 32 ++----- 5 files changed, 71 insertions(+), 108 deletions(-) diff --git a/interface/resources/qml/hifi/AvatarApp.qml b/interface/resources/qml/hifi/AvatarApp.qml index bf647b65bb..2d714c0d33 100644 --- a/interface/resources/qml/hifi/AvatarApp.qml +++ b/interface/resources/qml/hifi/AvatarApp.qml @@ -252,8 +252,7 @@ Rectangle { var avatarSettings = { dominantHand : settings.dominantHandIsLeft ? 'left' : 'right', collisionsEnabled : settings.avatarCollisionsOn, - sittingEnabled : settings.avatarSittingOn, - lockStateEnabled : settings.avatarLockSitStandStateOn, + recenterModel : settings.avatarRecenterModelOn, animGraphOverrideUrl : settings.avatarAnimationOverrideJSON, collisionSoundUrl : settings.avatarCollisionSoundUrl }; diff --git a/interface/resources/qml/hifi/avatarapp/Settings.qml b/interface/resources/qml/hifi/avatarapp/Settings.qml index 64ae03237c..cd71442bca 100644 --- a/interface/resources/qml/hifi/avatarapp/Settings.qml +++ b/interface/resources/qml/hifi/avatarapp/Settings.qml @@ -20,8 +20,7 @@ Rectangle { property real scaleValue: scaleSlider.value / 10 property alias dominantHandIsLeft: leftHandRadioButton.checked property alias avatarCollisionsOn: collisionsEnabledRadiobutton.checked - property alias avatarSittingOn: sitRadiobutton.checked - property alias avatarLockSitStandStateOn: lockSitStandStateCheckbox.checked + property alias avatarRecenterModelOn: boxy.currentIndex property alias avatarAnimationOverrideJSON: avatarAnimationUrlInputText.text property alias avatarAnimationJSON: avatarAnimationUrlInputText.placeholderText property alias avatarCollisionSoundUrl: avatarCollisionSoundUrlInputText.text @@ -47,21 +46,11 @@ Rectangle { collisionsDisabledRadioButton.checked = true; } - if (settings.sittingEnabled) { - sitRadiobutton.checked = true; - } else { - standRadioButton.checked = true; - } - - if (settings.lockStateEnabled) { - lockSitStandStateCheckbox.checked = true; - } else { - lockSitStandStateCheckbox.checked = false; - } - avatarAnimationJSON = settings.animGraphUrl; avatarAnimationOverrideJSON = settings.animGraphOverrideUrl; avatarCollisionSoundUrl = settings.collisionSoundUrl; + print("values " + avatarRecenterModelOn + " " + settings.recenterModel); + avatarRecenterModelOn = settings.recenterModel; visible = true; } @@ -305,7 +294,7 @@ Rectangle { } // TextStyle9 - + RalewaySemiBold { size: 17; Layout.row: 2 @@ -318,51 +307,6 @@ Rectangle { id: sitStand } - HifiControlsUit.RadioButton { - id: sitRadiobutton - - Layout.row: 2 - Layout.column: 1 - Layout.leftMargin: -40 - - ButtonGroup.group: sitStand - checked: true - - colorScheme: hifi.colorSchemes.light - fontSize: 17 - letterSpacing: 1.4 - text: "Sit" - boxSize: 20 - } - - HifiControlsUit.RadioButton { - id: standRadioButton - - Layout.row: 2 - Layout.column: 2 - Layout.rightMargin: 20 - - ButtonGroup.group: sitStand - - colorScheme: hifi.colorSchemes.light - fontSize: 17 - letterSpacing: 1.4 - text: "Stand" - boxSize: 20 - } - - // "Lock State" Checkbox - - HifiControlsUit.CheckBox { - id: lockSitStandStateCheckbox - visible: activeTab == "nearbyTab" - anchors.right: reloadNearbyContainer.left - anchors.rightMargin: 20 - checked: settings.lockStateEnabled - text: "lock" - boxSize: 24 - } - // sit stand combo box HifiControlsUit.ComboBox { id: boxy @@ -375,29 +319,8 @@ Rectangle { ListElement { text: "Auto Mode"; color: "Brown" } ListElement { text: "Disable Recentering"; color: "Red" } } - //displayText: "fred" - //label: cbItems.get(currentIndex).text width: 200 onCurrentIndexChanged: { - if (cbItems.get(currentIndex).text === "Force Sitting") { - sitRadiobutton.checked = true - lockSitStandStateCheckbox.checked = true - settings.lockStateEnabled = true - settings.sittingEnabled = true - } else if (cbItems.get(currentIndex).text === "Force Standing") { - sitRadiobutton.checked = false - lockSitStandStateCheckbox.checked = true - settings.lockStateEnabled = true - settings.sittingEnabled = false - } else if (cbItems.get(currentIndex).text === "auto") { - sitRadiobutton.checked = false - lockSitStandStateCheckbox.checked = false - settings.lockStateEnabled = false - settings.sittingEnabled = false - } else if (cbItems.get(currentIndex).text === "Disable Recentering") { - settings.lockStateEnabled = false - settings.sittingEnabled = false - } console.debug(cbItems.get(currentIndex).text + ", " + cbItems.get(currentIndex).color) console.debug("line 2") } diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 95141d614f..14829a7b2e 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -533,7 +533,7 @@ void MyAvatar::update(float deltaTime) { float tau = deltaTime / HMD_FACING_TIMESCALE; setHipToHandController(computeHandAzimuth()); - qCDebug(interfaceapp) << " the sit state is " << _isInSittingState.get() << " the lock is " << _lockSitStandState.get(); + //qCDebug(interfaceapp) << " the sit state is " << _isInSittingState.get() << " the lock is " << _lockSitStandState.get(); // put the average hand azimuth into sensor space. // then mix it with head facing direction to determine rotation recenter @@ -3867,6 +3867,10 @@ bool MyAvatar::getIsInSittingState() const { return _isInSittingState.get(); } +MyAvatar::SitStandModelType MyAvatar::getRecenterModel() const { + return _recenterModel.get(); +} + bool MyAvatar::getIsSitStandStateLocked() const { return _lockSitStandState.get(); } @@ -3903,9 +3907,38 @@ void MyAvatar::setIsInSittingState(bool isSitting) { setCenterOfGravityModelEnabled(true); } setSitStandStateChange(true); + emit sittingEnabledChanged(isSitting); } +void MyAvatar::setRecenterModel(MyAvatar::SitStandModelType modelName) { + + _recenterModel.set(modelName); + //int temp = 0; + qCDebug(interfaceapp) << "recenter property changed " << modelName; + switch (modelName) { + case SitStandModelType::ForceSit: + setIsInSittingState(true); + setIsSitStandStateLocked(true); + break; + case SitStandModelType::ForceStand: + setIsInSittingState(false); + setIsSitStandStateLocked(true); + break; + case SitStandModelType::Auto: + setIsInSittingState(false); + setIsSitStandStateLocked(false); + break; + case SitStandModelType::DisableHMDLean: + setHMDLeanRecenterEnabled(false); + setIsInSittingState(false); + setIsSitStandStateLocked(false); + break; + } + qCDebug(interfaceapp) << "recenter property changed " << modelName << " sit " << _isInSittingState.get() << " lock " << _lockSitStandState.get(); + emit recenterModelChanged((int)modelName); +} + void MyAvatar::setIsSitStandStateLocked(bool isLocked) { _lockSitStandState.set(isLocked); _sitStandStateTimer = 0.0f; diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index be8b5fa1b2..c59bdcd66d 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -143,6 +143,7 @@ class MyAvatar : public Avatar { * @property {number} walkBackwardSpeed * @property {number} sprintSpeed * @property {number} isInSittingState + * @property {number} recenterModel * * @property {Vec3} skeletonOffset - Can be used to apply a translation offset between the avatar's position and the * registration point of the 3D model. @@ -244,6 +245,7 @@ class MyAvatar : public Avatar { Q_PROPERTY(float walkBackwardSpeed READ getWalkBackwardSpeed WRITE setWalkBackwardSpeed); Q_PROPERTY(float sprintSpeed READ getSprintSpeed WRITE setSprintSpeed); Q_PROPERTY(bool isInSittingState READ getIsInSittingState WRITE setIsInSittingState); + Q_PROPERTY(MyAvatar::SitStandModelType recenterModel READ getRecenterModel WRITE setRecenterModel); Q_PROPERTY(bool isSitStandStateLocked READ getIsSitStandStateLocked WRITE setIsSitStandStateLocked); const QString DOMINANT_LEFT_HAND = "left"; @@ -265,6 +267,15 @@ public: }; Q_ENUM(DriveKeys) + enum SitStandModelType { + ForceSit = 0, + ForceStand, + Auto, + DisableHMDLean, + NumSitStandTypes + }; + Q_ENUM(SitStandModelType) + explicit MyAvatar(QThread* thread); virtual ~MyAvatar(); @@ -1106,6 +1117,8 @@ public: bool getIsInWalkingState() const; void setIsInSittingState(bool isSitting); bool getIsInSittingState() const; + void setRecenterModel(MyAvatar::SitStandModelType modelName); + MyAvatar::SitStandModelType getRecenterModel() const; void setIsSitStandStateLocked(bool isLocked); bool getIsSitStandStateLocked() const; void setWalkSpeed(float value); @@ -1530,6 +1543,14 @@ signals: */ void sittingEnabledChanged(bool enabled); + /**jsdoc + * Triggered when the recenter model is changed + * @function MyAvatar.recenterModelChanged + * @param {int} modeltype + * @ + */ + void recenterModelChanged(int modelName); + /**jsdoc * Triggered when the sit state is enabled or disabled * @function MyAvatar.sitStandStateLockEnabledChanged @@ -1829,7 +1850,7 @@ private: void updateChildCauterization(SpatiallyNestablePointer object, bool cauterize); - const float DEFAULT_FLOOR_HEIGHT = 0.0f; + // height of user in sensor space, when standing erect. ThreadSafeValueCache _userHeight { DEFAULT_AVATAR_HEIGHT }; @@ -1844,6 +1865,7 @@ private: float _walkSpeedScalar { AVATAR_WALK_SPEED_SCALAR }; bool _isInWalkingState { false }; ThreadSafeValueCache _isInSittingState { false }; + ThreadSafeValueCache _recenterModel { MyAvatar::SitStandModelType::Auto }; float _sitStandStateTimer { 0.0f }; float _squatTimer { 0.0f }; float _tippingPoint { _userHeight.get() }; diff --git a/scripts/system/avatarapp.js b/scripts/system/avatarapp.js index 4a25ab9551..d64454c534 100644 --- a/scripts/system/avatarapp.js +++ b/scripts/system/avatarapp.js @@ -64,8 +64,7 @@ function getMyAvatarSettings() { return { dominantHand: MyAvatar.getDominantHand(), collisionsEnabled : MyAvatar.getCollisionsEnabled(), - sittingEnabled: MyAvatar.isInSittingState, - lockStateEnabled: MyAvatar.isSitStandStateLocked, + recenterModel: MyAvatar.recenterModel, collisionSoundUrl : MyAvatar.collisionSoundURL, animGraphUrl: MyAvatar.getAnimGraphUrl(), animGraphOverrideUrl : MyAvatar.getAnimGraphOverrideUrl(), @@ -138,19 +137,11 @@ function onCollisionsEnabledChanged(enabled) { } } -function onSittingEnabledChanged(isSitting) { - if (currentAvatarSettings.sittingEnabled !== isSitting) { - currentAvatarSettings.sittingEnabled = isSitting; - print("emit sitting changed"); - sendToQml({ 'method': 'settingChanged', 'name': 'sittingEnabled', 'value': isSitting }) - } -} - -function onSitStandStateLockedEnabledChanged(isLocked) { - if (currentAvatarSettings.lockStateEnabled !== isLocked) { - currentAvatarSettings.lockStateEnabled = isLocked; - print("emit lock sit stand state changed"); - sendToQml({ 'method': 'settingChanged', 'name': 'lockStateEnabled', 'value': isLocked }) +function onRecenterModelChanged(modelName) { + if (currentAvatarSettings.recenterModel !== modelName) { + currentAvatarSettings.recenterModel = modelName; + print("emit recenter model changed"); + sendToQml({ 'method': 'settingChanged', 'name': 'recenterModel', 'value': modelName }) } } @@ -329,14 +320,11 @@ function fromQml(message) { // messages are {method, params}, like json-rpc. See case 'saveSettings': MyAvatar.setAvatarScale(message.avatarScale); currentAvatar.avatarScale = message.avatarScale; - MyAvatar.setDominantHand(message.settings.dominantHand); MyAvatar.setCollisionsEnabled(message.settings.collisionsEnabled); - MyAvatar.isInSittingState = message.settings.sittingEnabled; - MyAvatar.isSitStandStateLocked = message.settings.lockStateEnabled; + MyAvatar.recenterModel = message.settings.recenterModel; MyAvatar.collisionSoundURL = message.settings.collisionSoundUrl; MyAvatar.setAnimGraphOverrideUrl(message.settings.animGraphOverrideUrl); - settings = getMyAvatarSettings(); break; default: @@ -527,8 +515,7 @@ function off() { MyAvatar.skeletonModelURLChanged.disconnect(onSkeletonModelURLChanged); MyAvatar.dominantHandChanged.disconnect(onDominantHandChanged); MyAvatar.collisionsEnabledChanged.disconnect(onCollisionsEnabledChanged); - MyAvatar.sittingEnabledChanged.disconnect(onSittingEnabledChanged); - MyAvatar.sitStandStateLockEnabledChanged.disconnect(onSitStandStateLockedEnabledChanged); + MyAvatar.recenterModelChanged.disconnect(onRecenterModelChanged); MyAvatar.newCollisionSoundURL.disconnect(onNewCollisionSoundUrl); MyAvatar.animGraphUrlChanged.disconnect(onAnimGraphUrlChanged); MyAvatar.targetScaleChanged.disconnect(onTargetScaleChanged); @@ -543,8 +530,7 @@ function on() { MyAvatar.skeletonModelURLChanged.connect(onSkeletonModelURLChanged); MyAvatar.dominantHandChanged.connect(onDominantHandChanged); MyAvatar.collisionsEnabledChanged.connect(onCollisionsEnabledChanged); - MyAvatar.sittingEnabledChanged.connect(onSittingEnabledChanged); - MyAvatar.sitStandStateLockEnabledChanged.connect(onSitStandStateLockedEnabledChanged); + MyAvatar.recenterModelChanged.connect(onRecenterModelChanged); MyAvatar.newCollisionSoundURL.connect(onNewCollisionSoundUrl); MyAvatar.animGraphUrlChanged.connect(onAnimGraphUrlChanged); MyAvatar.targetScaleChanged.connect(onTargetScaleChanged); From 070a517423af7e6304f3ddc50564b0e65dd01bd0 Mon Sep 17 00:00:00 2001 From: amantley Date: Fri, 19 Oct 2018 18:07:03 -0700 Subject: [PATCH 44/54] changed the recenterModel variables to userRecenterModel --- interface/resources/qml/hifi/AvatarApp.qml | 2 +- .../resources/qml/hifi/avatarapp/Settings.qml | 17 ++- interface/src/avatar/MyAvatar.cpp | 108 +++++++++--------- interface/src/avatar/MyAvatar.h | 20 ++-- scripts/system/avatarapp.js | 18 +-- 5 files changed, 80 insertions(+), 85 deletions(-) diff --git a/interface/resources/qml/hifi/AvatarApp.qml b/interface/resources/qml/hifi/AvatarApp.qml index 2d714c0d33..549db20ab1 100644 --- a/interface/resources/qml/hifi/AvatarApp.qml +++ b/interface/resources/qml/hifi/AvatarApp.qml @@ -252,7 +252,7 @@ Rectangle { var avatarSettings = { dominantHand : settings.dominantHandIsLeft ? 'left' : 'right', collisionsEnabled : settings.avatarCollisionsOn, - recenterModel : settings.avatarRecenterModelOn, + userRecenterModel : settings.avatarRecenterModelOn, animGraphOverrideUrl : settings.avatarAnimationOverrideJSON, collisionSoundUrl : settings.avatarCollisionSoundUrl }; diff --git a/interface/resources/qml/hifi/avatarapp/Settings.qml b/interface/resources/qml/hifi/avatarapp/Settings.qml index cd71442bca..eb994b86de 100644 --- a/interface/resources/qml/hifi/avatarapp/Settings.qml +++ b/interface/resources/qml/hifi/avatarapp/Settings.qml @@ -20,7 +20,7 @@ Rectangle { property real scaleValue: scaleSlider.value / 10 property alias dominantHandIsLeft: leftHandRadioButton.checked property alias avatarCollisionsOn: collisionsEnabledRadiobutton.checked - property alias avatarRecenterModelOn: boxy.currentIndex + property alias avatarRecenterModelOn: userModelComboBox.currentIndex property alias avatarAnimationOverrideJSON: avatarAnimationUrlInputText.text property alias avatarAnimationJSON: avatarAnimationUrlInputText.placeholderText property alias avatarCollisionSoundUrl: avatarCollisionSoundUrlInputText.text @@ -49,8 +49,7 @@ Rectangle { avatarAnimationJSON = settings.animGraphUrl; avatarAnimationOverrideJSON = settings.animGraphOverrideUrl; avatarCollisionSoundUrl = settings.collisionSoundUrl; - print("values " + avatarRecenterModelOn + " " + settings.recenterModel); - avatarRecenterModelOn = settings.recenterModel; + avatarRecenterModelOn = settings.userRecenterModel; visible = true; } @@ -294,22 +293,21 @@ Rectangle { } // TextStyle9 - + RalewaySemiBold { size: 17; Layout.row: 2 Layout.column: 0 - text: "Sitting State" + text: "User Model:" } - ButtonGroup { - id: sitStand - } // sit stand combo box HifiControlsUit.ComboBox { - id: boxy + Layout.row: 2 + Layout.column: 1 + id: userModelComboBox comboBox.textRole: "text" currentIndex: 2 model: ListModel { @@ -325,7 +323,6 @@ Rectangle { console.debug("line 2") } } - } ColumnLayout { diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 14829a7b2e..0b58c2c158 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -470,57 +470,58 @@ void MyAvatar::updateSitStandState(float newHeightReading, float dt) { const float SITTING_TIMEOUT = 4.0f; // 4 seconds const float STANDING_TIMEOUT = 0.3333f; // 1/3 second const float SITTING_UPPER_BOUND = 1.52f; - - if (!getIsSitStandStateLocked() && !getIsAway() && qApp->isHMDMode()) { - if (getIsInSittingState()) { - if (newHeightReading > (STANDING_HEIGHT_MULTIPLE * _tippingPoint)) { - // if we recenter upwards then no longer in sitting state - _sitStandStateTimer += dt; - if (_sitStandStateTimer > STANDING_TIMEOUT) { - _averageUserHeightSensorSpace = newHeightReading; - _tippingPoint = newHeightReading; - setIsInSittingState(false); - } - } else if (newHeightReading < (SITTING_HEIGHT_MULTIPLE * _tippingPoint)) { - // if we are mis labelled as sitting but we are standing in the real world this will - // make sure that a real sit is still recognized so we won't be stuck in sitting unable to change state - _sitStandStateTimer += dt; - if (_sitStandStateTimer > SITTING_TIMEOUT) { - _averageUserHeightSensorSpace = newHeightReading; - _tippingPoint = newHeightReading; - // here we stay in sit state but reset the average height - setIsInSittingState(true); + if (!getIsSitStandStateLocked()) { + if (!getIsAway() && qApp->isHMDMode()) { + if (getIsInSittingState()) { + if (newHeightReading > (STANDING_HEIGHT_MULTIPLE * _tippingPoint)) { + // if we recenter upwards then no longer in sitting state + _sitStandStateTimer += dt; + if (_sitStandStateTimer > STANDING_TIMEOUT) { + _averageUserHeightSensorSpace = newHeightReading; + _tippingPoint = newHeightReading; + setIsInSittingState(false); + } + } else if (newHeightReading < (SITTING_HEIGHT_MULTIPLE * _tippingPoint)) { + // if we are mis labelled as sitting but we are standing in the real world this will + // make sure that a real sit is still recognized so we won't be stuck in sitting unable to change state + _sitStandStateTimer += dt; + if (_sitStandStateTimer > SITTING_TIMEOUT) { + _averageUserHeightSensorSpace = newHeightReading; + _tippingPoint = newHeightReading; + // here we stay in sit state but reset the average height + setIsInSittingState(true); + } + } else { + // sanity check if average height greater than 5ft they are not sitting(or get off your dangerous barstool please) + if (_averageUserHeightSensorSpace > SITTING_UPPER_BOUND) { + setIsInSittingState(false); + } else { + // tipping point is average height when sitting. + _tippingPoint = _averageUserHeightSensorSpace; + _sitStandStateTimer = 0.0f; + } } } else { - // sanity check if average height greater than 5ft they are not sitting(or get off your dangerous barstool please) - if (_averageUserHeightSensorSpace > SITTING_UPPER_BOUND) { - setIsInSittingState(false); + // in the standing state + if (newHeightReading < (SITTING_HEIGHT_MULTIPLE * _tippingPoint)) { + _sitStandStateTimer += dt; + if (_sitStandStateTimer > SITTING_TIMEOUT) { + _averageUserHeightSensorSpace = newHeightReading; + _tippingPoint = newHeightReading; + setIsInSittingState(true); + } } else { - // tipping point is average height when sitting. - _tippingPoint = _averageUserHeightSensorSpace; + // use the mode height for the tipping point when we are standing. + _tippingPoint = getCurrentStandingHeight(); _sitStandStateTimer = 0.0f; } } } else { - // in the standing state - if (newHeightReading < (SITTING_HEIGHT_MULTIPLE * _tippingPoint)) { - _sitStandStateTimer += dt; - if (_sitStandStateTimer > SITTING_TIMEOUT) { - _averageUserHeightSensorSpace = newHeightReading; - _tippingPoint = newHeightReading; - setIsInSittingState(true); - } - } else { - // use the mode height for the tipping point when we are standing. - _tippingPoint = getCurrentStandingHeight(); - _sitStandStateTimer = 0.0f; - } + //if you are away then reset the average and set state to standing. + _averageUserHeightSensorSpace = _userHeight.get(); + _tippingPoint = _userHeight.get(); + setIsInSittingState(false); } - } else { - // if you are away then reset the average and set state to standing. - _averageUserHeightSensorSpace = _userHeight.get(); - _tippingPoint = _userHeight.get(); - setIsInSittingState(false); } } @@ -533,7 +534,7 @@ void MyAvatar::update(float deltaTime) { float tau = deltaTime / HMD_FACING_TIMESCALE; setHipToHandController(computeHandAzimuth()); - //qCDebug(interfaceapp) << " the sit state is " << _isInSittingState.get() << " the lock is " << _lockSitStandState.get(); + qCDebug(interfaceapp) << " the sit state is " << _isInSittingState.get() << " the lock is " << _lockSitStandState.get(); // put the average hand azimuth into sensor space. // then mix it with head facing direction to determine rotation recenter @@ -3867,8 +3868,8 @@ bool MyAvatar::getIsInSittingState() const { return _isInSittingState.get(); } -MyAvatar::SitStandModelType MyAvatar::getRecenterModel() const { - return _recenterModel.get(); +MyAvatar::SitStandModelType MyAvatar::getUserRecenterModel() const { + return _userRecenterModel.get(); } bool MyAvatar::getIsSitStandStateLocked() const { @@ -3907,25 +3908,25 @@ void MyAvatar::setIsInSittingState(bool isSitting) { setCenterOfGravityModelEnabled(true); } setSitStandStateChange(true); - - emit sittingEnabledChanged(isSitting); } -void MyAvatar::setRecenterModel(MyAvatar::SitStandModelType modelName) { +void MyAvatar::setUserRecenterModel(MyAvatar::SitStandModelType modelName) { + + _userRecenterModel.set(modelName); - _recenterModel.set(modelName); - //int temp = 0; - qCDebug(interfaceapp) << "recenter property changed " << modelName; switch (modelName) { case SitStandModelType::ForceSit: + setHMDLeanRecenterEnabled(true); setIsInSittingState(true); setIsSitStandStateLocked(true); break; case SitStandModelType::ForceStand: + setHMDLeanRecenterEnabled(true); setIsInSittingState(false); setIsSitStandStateLocked(true); break; case SitStandModelType::Auto: + setHMDLeanRecenterEnabled(true); setIsInSittingState(false); setIsSitStandStateLocked(false); break; @@ -3936,7 +3937,7 @@ void MyAvatar::setRecenterModel(MyAvatar::SitStandModelType modelName) { break; } qCDebug(interfaceapp) << "recenter property changed " << modelName << " sit " << _isInSittingState.get() << " lock " << _lockSitStandState.get(); - emit recenterModelChanged((int)modelName); + emit userRecenterModelChanged((int)modelName); } void MyAvatar::setIsSitStandStateLocked(bool isLocked) { @@ -3949,7 +3950,6 @@ void MyAvatar::setIsSitStandStateLocked(bool isLocked) { // always start the auto transition mode in standing state. setIsInSittingState(false); } - emit sitStandStateLockEnabledChanged(isLocked); } void MyAvatar::setWalkSpeed(float value) { diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index c59bdcd66d..691ab80530 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -143,7 +143,7 @@ class MyAvatar : public Avatar { * @property {number} walkBackwardSpeed * @property {number} sprintSpeed * @property {number} isInSittingState - * @property {number} recenterModel + * @property {number} userRecenterModel * * @property {Vec3} skeletonOffset - Can be used to apply a translation offset between the avatar's position and the * registration point of the 3D model. @@ -245,7 +245,7 @@ class MyAvatar : public Avatar { Q_PROPERTY(float walkBackwardSpeed READ getWalkBackwardSpeed WRITE setWalkBackwardSpeed); Q_PROPERTY(float sprintSpeed READ getSprintSpeed WRITE setSprintSpeed); Q_PROPERTY(bool isInSittingState READ getIsInSittingState WRITE setIsInSittingState); - Q_PROPERTY(MyAvatar::SitStandModelType recenterModel READ getRecenterModel WRITE setRecenterModel); + Q_PROPERTY(MyAvatar::SitStandModelType userRecenterModel READ getUserRecenterModel WRITE setUserRecenterModel); Q_PROPERTY(bool isSitStandStateLocked READ getIsSitStandStateLocked WRITE setIsSitStandStateLocked); const QString DOMINANT_LEFT_HAND = "left"; @@ -1117,8 +1117,8 @@ public: bool getIsInWalkingState() const; void setIsInSittingState(bool isSitting); bool getIsInSittingState() const; - void setRecenterModel(MyAvatar::SitStandModelType modelName); - MyAvatar::SitStandModelType getRecenterModel() const; + void setUserRecenterModel(MyAvatar::SitStandModelType modelName); + MyAvatar::SitStandModelType getUserRecenterModel() const; void setIsSitStandStateLocked(bool isLocked); bool getIsSitStandStateLocked() const; void setWalkSpeed(float value); @@ -1545,11 +1545,11 @@ signals: /**jsdoc * Triggered when the recenter model is changed - * @function MyAvatar.recenterModelChanged - * @param {int} modeltype - * @ + * @function MyAvatar.userRecenterModelChanged + * @param {int} userRecenteringModeltype + * @returns {Signal} */ - void recenterModelChanged(int modelName); + void userRecenterModelChanged(int modelName); /**jsdoc * Triggered when the sit state is enabled or disabled @@ -1850,8 +1850,6 @@ private: void updateChildCauterization(SpatiallyNestablePointer object, bool cauterize); - - // height of user in sensor space, when standing erect. ThreadSafeValueCache _userHeight { DEFAULT_AVATAR_HEIGHT }; float _averageUserHeightSensorSpace { _userHeight.get() }; @@ -1865,7 +1863,7 @@ private: float _walkSpeedScalar { AVATAR_WALK_SPEED_SCALAR }; bool _isInWalkingState { false }; ThreadSafeValueCache _isInSittingState { false }; - ThreadSafeValueCache _recenterModel { MyAvatar::SitStandModelType::Auto }; + ThreadSafeValueCache _userRecenterModel { MyAvatar::SitStandModelType::Auto }; float _sitStandStateTimer { 0.0f }; float _squatTimer { 0.0f }; float _tippingPoint { _userHeight.get() }; diff --git a/scripts/system/avatarapp.js b/scripts/system/avatarapp.js index d64454c534..b30f87c944 100644 --- a/scripts/system/avatarapp.js +++ b/scripts/system/avatarapp.js @@ -64,7 +64,7 @@ function getMyAvatarSettings() { return { dominantHand: MyAvatar.getDominantHand(), collisionsEnabled : MyAvatar.getCollisionsEnabled(), - recenterModel: MyAvatar.recenterModel, + userRecenterModel: MyAvatar.userRecenterModel, collisionSoundUrl : MyAvatar.collisionSoundURL, animGraphUrl: MyAvatar.getAnimGraphUrl(), animGraphOverrideUrl : MyAvatar.getAnimGraphOverrideUrl(), @@ -137,11 +137,11 @@ function onCollisionsEnabledChanged(enabled) { } } -function onRecenterModelChanged(modelName) { - if (currentAvatarSettings.recenterModel !== modelName) { - currentAvatarSettings.recenterModel = modelName; - print("emit recenter model changed"); - sendToQml({ 'method': 'settingChanged', 'name': 'recenterModel', 'value': modelName }) +function onUserRecenterModelChanged(modelName) { + if (currentAvatarSettings.userRecenterModel !== modelName) { + currentAvatarSettings.userRecenterModel = modelName; + print("emit user recenter model changed"); + sendToQml({ 'method': 'settingChanged', 'name': 'userRecenterModel', 'value': modelName }) } } @@ -322,7 +322,7 @@ function fromQml(message) { // messages are {method, params}, like json-rpc. See currentAvatar.avatarScale = message.avatarScale; MyAvatar.setDominantHand(message.settings.dominantHand); MyAvatar.setCollisionsEnabled(message.settings.collisionsEnabled); - MyAvatar.recenterModel = message.settings.recenterModel; + MyAvatar.userRecenterModel = message.settings.userRecenterModel; MyAvatar.collisionSoundURL = message.settings.collisionSoundUrl; MyAvatar.setAnimGraphOverrideUrl(message.settings.animGraphOverrideUrl); settings = getMyAvatarSettings(); @@ -515,7 +515,7 @@ function off() { MyAvatar.skeletonModelURLChanged.disconnect(onSkeletonModelURLChanged); MyAvatar.dominantHandChanged.disconnect(onDominantHandChanged); MyAvatar.collisionsEnabledChanged.disconnect(onCollisionsEnabledChanged); - MyAvatar.recenterModelChanged.disconnect(onRecenterModelChanged); + MyAvatar.userRecenterModelChanged.disconnect(onUserRecenterModelChanged); MyAvatar.newCollisionSoundURL.disconnect(onNewCollisionSoundUrl); MyAvatar.animGraphUrlChanged.disconnect(onAnimGraphUrlChanged); MyAvatar.targetScaleChanged.disconnect(onTargetScaleChanged); @@ -530,7 +530,7 @@ function on() { MyAvatar.skeletonModelURLChanged.connect(onSkeletonModelURLChanged); MyAvatar.dominantHandChanged.connect(onDominantHandChanged); MyAvatar.collisionsEnabledChanged.connect(onCollisionsEnabledChanged); - MyAvatar.recenterModelChanged.connect(onRecenterModelChanged); + MyAvatar.userRecenterModelChanged.connect(onUserRecenterModelChanged); MyAvatar.newCollisionSoundURL.connect(onNewCollisionSoundUrl); MyAvatar.animGraphUrlChanged.connect(onAnimGraphUrlChanged); MyAvatar.targetScaleChanged.connect(onTargetScaleChanged); From 55daeb11cdcdb007ec7cfcabbc8eac18d46a4270 Mon Sep 17 00:00:00 2001 From: amantley Date: Fri, 19 Oct 2018 18:43:02 -0700 Subject: [PATCH 45/54] moved the radio buttons on the avatar settings to even them out better. will be corrected I'm sure --- interface/resources/qml/hifi/avatarapp/Settings.qml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/interface/resources/qml/hifi/avatarapp/Settings.qml b/interface/resources/qml/hifi/avatarapp/Settings.qml index eb994b86de..dbf38eb5fc 100644 --- a/interface/resources/qml/hifi/avatarapp/Settings.qml +++ b/interface/resources/qml/hifi/avatarapp/Settings.qml @@ -32,7 +32,7 @@ Rectangle { scaleSlider.notify = false; scaleSlider.value = Math.round(avatarScale * 10); - scaleSlider.notify = true;; + scaleSlider.notify = true; if (settings.dominantHand === 'left') { leftHandRadioButton.checked = true; @@ -191,7 +191,7 @@ Rectangle { anchors.left: parent.left anchors.right: parent.right - rows: 2 + rows: 3 rowSpacing: 25 columns: 3 @@ -214,7 +214,7 @@ Rectangle { Layout.row: 0 Layout.column: 1 - Layout.leftMargin: -40 + Layout.leftMargin: 20 ButtonGroup.group: leftRight checked: true @@ -231,7 +231,7 @@ Rectangle { Layout.row: 0 Layout.column: 2 - Layout.rightMargin: 20 + Layout.rightMargin: -20 ButtonGroup.group: leftRight @@ -260,7 +260,7 @@ Rectangle { Layout.row: 1 Layout.column: 1 - Layout.leftMargin: -40 + Layout.leftMargin: 20 ButtonGroup.group: onOff colorScheme: hifi.colorSchemes.light @@ -281,7 +281,7 @@ Rectangle { Layout.row: 1 Layout.column: 2 - Layout.rightMargin: 20 + Layout.rightMargin: -20 ButtonGroup.group: onOff colorScheme: hifi.colorSchemes.light From a427ddb23543dac8e9cf1a111b24c9c6267ac797 Mon Sep 17 00:00:00 2001 From: amantley Date: Sat, 20 Oct 2018 09:16:05 -0700 Subject: [PATCH 46/54] removed extraneous print statements --- interface/resources/qml/hifi/avatarapp/Settings.qml | 4 ---- interface/src/avatar/MyAvatar.cpp | 2 -- 2 files changed, 6 deletions(-) diff --git a/interface/resources/qml/hifi/avatarapp/Settings.qml b/interface/resources/qml/hifi/avatarapp/Settings.qml index dbf38eb5fc..b7083bda13 100644 --- a/interface/resources/qml/hifi/avatarapp/Settings.qml +++ b/interface/resources/qml/hifi/avatarapp/Settings.qml @@ -318,10 +318,6 @@ Rectangle { ListElement { text: "Disable Recentering"; color: "Red" } } width: 200 - onCurrentIndexChanged: { - console.debug(cbItems.get(currentIndex).text + ", " + cbItems.get(currentIndex).color) - console.debug("line 2") - } } } diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 0b58c2c158..c8d33a770e 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -534,7 +534,6 @@ void MyAvatar::update(float deltaTime) { float tau = deltaTime / HMD_FACING_TIMESCALE; setHipToHandController(computeHandAzimuth()); - qCDebug(interfaceapp) << " the sit state is " << _isInSittingState.get() << " the lock is " << _lockSitStandState.get(); // put the average hand azimuth into sensor space. // then mix it with head facing direction to determine rotation recenter @@ -3936,7 +3935,6 @@ void MyAvatar::setUserRecenterModel(MyAvatar::SitStandModelType modelName) { setIsSitStandStateLocked(false); break; } - qCDebug(interfaceapp) << "recenter property changed " << modelName << " sit " << _isInSittingState.get() << " lock " << _lockSitStandState.get(); emit userRecenterModelChanged((int)modelName); } From 5efb889de53ea3fd5d4375a05db885ce4bf02787 Mon Sep 17 00:00:00 2001 From: amantley Date: Sat, 20 Oct 2018 13:42:17 -0700 Subject: [PATCH 47/54] removed unused variables --- interface/src/avatar/MyAvatar.cpp | 44 ++++++++++++++----------------- 1 file changed, 20 insertions(+), 24 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index c8d33a770e..94a6c6f514 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -3606,12 +3606,9 @@ glm::vec3 MyAvatar::computeCounterBalance() { glm::vec3 counterBalancedCg = (1.0f / DEFAULT_AVATAR_HIPS_MASS) * counterBalancedForHead; // find the height of the hips - const float UPPER_LEG_FRACTION = 0.3333f; glm::vec3 xzDiff((cgHeadMass.position.x - counterBalancedCg.x), 0.0f, (cgHeadMass.position.z - counterBalancedCg.z)); float headMinusHipXz = glm::length(xzDiff); float headHipDefault = glm::length(tposeHead - tposeHips); - float hipFootDefault = tposeHips.y - tposeRightFoot.y; - float sitSquatThreshold = tposeHips.y - (UPPER_LEG_FRACTION * hipFootDefault); float hipHeight = 0.0f; if (headHipDefault > headMinusHipXz) { hipHeight = sqrtf((headHipDefault * headHipDefault) - (headMinusHipXz * headMinusHipXz)); @@ -3914,26 +3911,26 @@ void MyAvatar::setUserRecenterModel(MyAvatar::SitStandModelType modelName) { _userRecenterModel.set(modelName); switch (modelName) { - case SitStandModelType::ForceSit: - setHMDLeanRecenterEnabled(true); - setIsInSittingState(true); - setIsSitStandStateLocked(true); - break; - case SitStandModelType::ForceStand: - setHMDLeanRecenterEnabled(true); - setIsInSittingState(false); - setIsSitStandStateLocked(true); - break; - case SitStandModelType::Auto: - setHMDLeanRecenterEnabled(true); - setIsInSittingState(false); - setIsSitStandStateLocked(false); - break; - case SitStandModelType::DisableHMDLean: - setHMDLeanRecenterEnabled(false); - setIsInSittingState(false); - setIsSitStandStateLocked(false); - break; + case MyAvatar::SitStandModelType::ForceSit: + setHMDLeanRecenterEnabled(true); + setIsInSittingState(true); + setIsSitStandStateLocked(true); + break; + case MyAvatar::SitStandModelType::ForceStand: + setHMDLeanRecenterEnabled(true); + setIsInSittingState(false); + setIsSitStandStateLocked(true); + break; + case MyAvatar::SitStandModelType::Auto: + setHMDLeanRecenterEnabled(true); + setIsInSittingState(false); + setIsSitStandStateLocked(false); + break; + case MyAvatar::SitStandModelType::DisableHMDLean: + setHMDLeanRecenterEnabled(false); + setIsInSittingState(false); + setIsSitStandStateLocked(false); + break; } emit userRecenterModelChanged((int)modelName); } @@ -4190,7 +4187,6 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(const MyAvatar& myAvatar, co const float CYLINDER_TOP = 0.1f; const float CYLINDER_BOTTOM = -1.5f; const float SITTING_BOTTOM = -0.02f; - const int SQUATTY_COUNT_THRESHOLD = 1800; glm::vec3 offset = extractTranslation(desiredBodyMatrix) - extractTranslation(currentBodyMatrix); bool returnValue = false; From eb3db9a5715ad53c0344bee64647e67aa0de8eac Mon Sep 17 00:00:00 2001 From: amantley Date: Sat, 20 Oct 2018 16:13:41 -0700 Subject: [PATCH 48/54] added default to case statement --- interface/src/avatar/MyAvatar.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index b2146fb14d..dd40a748af 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -3970,6 +3970,8 @@ void MyAvatar::setUserRecenterModel(MyAvatar::SitStandModelType modelName) { setIsInSittingState(false); setIsSitStandStateLocked(false); break; + default: + break; } emit userRecenterModelChanged((int)modelName); } From 8cb09c37eed722dd701afa6b4868581381d03762 Mon Sep 17 00:00:00 2001 From: amantley Date: Mon, 22 Oct 2018 21:26:30 -0700 Subject: [PATCH 49/54] changed the ui to the settings/controls --- interface/src/avatar/MyAvatar.cpp | 2 +- interface/src/ui/PreferencesDialog.cpp | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index dd40a748af..c55a257d6a 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -533,7 +533,7 @@ void MyAvatar::update(float deltaTime) { float tau = deltaTime / HMD_FACING_TIMESCALE; setHipToHandController(computeHandAzimuth()); - + qCDebug(interfaceapp) << "lock " << _lockSitStandState.get() << " sit " << _isInSittingState.get() << " hmd lean "<< _hmdLeanRecenterEnabled; // put the average hand azimuth into sensor space. // then mix it with head facing direction to determine rotation recenter if (getControllerPoseInAvatarFrame(controller::Action::LEFT_HAND).isValid() && getControllerPoseInAvatarFrame(controller::Action::RIGHT_HAND).isValid()) { diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index 5eccef5e9d..eeca96222b 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -243,6 +243,29 @@ void setupPreferences() { preference->setIndented(true); preferences->addPreference(preference); } + { + auto getter = [myAvatar]()->int { if (myAvatar->getUserRecenterModel() == MyAvatar::SitStandModelType::Auto) { + return 0; + } else if (myAvatar->getUserRecenterModel() == MyAvatar::SitStandModelType::ForceSit) { + return 1; + } else { + return 2; + }}; + auto setter = [myAvatar](int value) { if (value == 0) { + myAvatar->setUserRecenterModel(MyAvatar::SitStandModelType::Auto); + } else if (value == 1) { + myAvatar->setUserRecenterModel(MyAvatar::SitStandModelType::ForceSit); + } else { + myAvatar->setUserRecenterModel(MyAvatar::SitStandModelType::DisableHMDLean); + }}; + auto preference = new RadioButtonsPreference(VR_MOVEMENT, "Auto / Force Sit / Disable Recenter", getter, setter); + QStringList items; + items << "Auto" << "Force Sitting" << "Disable Recenter"; + preference->setHeading("User Activity mode"); + preference->setItems(items); + preferences->addPreference(preference); + } + { auto getter = [myAvatar]()->int { return myAvatar->getSnapTurn() ? 0 : 1; }; auto setter = [myAvatar](int value) { myAvatar->setSnapTurn(value == 0); }; From 3e8663f8e9dbcf53fe86a8a4baf33681b0c8c4d1 Mon Sep 17 00:00:00 2001 From: amantley Date: Mon, 22 Oct 2018 22:31:26 -0700 Subject: [PATCH 50/54] removed the dropdown from the avatar app, because it is in settings controls now --- interface/resources/qml/hifi/AvatarApp.qml | 1 - .../resources/qml/hifi/avatarapp/Settings.qml | 40 +++---------------- scripts/system/avatarapp.js | 14 +------ 3 files changed, 7 insertions(+), 48 deletions(-) diff --git a/interface/resources/qml/hifi/AvatarApp.qml b/interface/resources/qml/hifi/AvatarApp.qml index d68e5bfcd7..39590748cf 100644 --- a/interface/resources/qml/hifi/AvatarApp.qml +++ b/interface/resources/qml/hifi/AvatarApp.qml @@ -252,7 +252,6 @@ Rectangle { var avatarSettings = { dominantHand : settings.dominantHandIsLeft ? 'left' : 'right', collisionsEnabled : settings.avatarCollisionsOn, - userRecenterModel : settings.avatarRecenterModelOn, animGraphOverrideUrl : settings.avatarAnimationOverrideJSON, collisionSoundUrl : settings.avatarCollisionSoundUrl }; diff --git a/interface/resources/qml/hifi/avatarapp/Settings.qml b/interface/resources/qml/hifi/avatarapp/Settings.qml index ec2b176f54..bad1394133 100644 --- a/interface/resources/qml/hifi/avatarapp/Settings.qml +++ b/interface/resources/qml/hifi/avatarapp/Settings.qml @@ -20,7 +20,6 @@ Rectangle { property real scaleValue: scaleSlider.value / 10 property alias dominantHandIsLeft: leftHandRadioButton.checked property alias avatarCollisionsOn: collisionsEnabledRadiobutton.checked - property alias avatarRecenterModelOn: userModelComboBox.currentIndex property alias avatarAnimationOverrideJSON: avatarAnimationUrlInputText.text property alias avatarAnimationJSON: avatarAnimationUrlInputText.placeholderText property alias avatarCollisionSoundUrl: avatarCollisionSoundUrlInputText.text @@ -49,7 +48,6 @@ Rectangle { avatarAnimationJSON = settings.animGraphUrl; avatarAnimationOverrideJSON = settings.animGraphOverrideUrl; avatarCollisionSoundUrl = settings.collisionSoundUrl; - avatarRecenterModelOn = settings.userRecenterModel; visible = true; } @@ -191,7 +189,7 @@ Rectangle { anchors.left: parent.left anchors.right: parent.right - rows: 3 + rows: 2 rowSpacing: 25 columns: 3 @@ -214,7 +212,7 @@ Rectangle { Layout.row: 0 Layout.column: 1 - Layout.leftMargin: 20 + Layout.leftMargin: -40 ButtonGroup.group: leftRight checked: true @@ -231,7 +229,7 @@ Rectangle { Layout.row: 0 Layout.column: 2 - Layout.rightMargin: -20 + Layout.rightMargin: 20 ButtonGroup.group: leftRight @@ -260,7 +258,7 @@ Rectangle { Layout.row: 1 Layout.column: 1 - Layout.leftMargin: 20 + Layout.leftMargin: -40 ButtonGroup.group: onOff colorScheme: hifi.colorSchemes.light @@ -281,7 +279,7 @@ Rectangle { Layout.row: 1 Layout.column: 2 - Layout.rightMargin: -20 + Layout.rightMargin: 20 ButtonGroup.group: onOff colorScheme: hifi.colorSchemes.light @@ -291,34 +289,6 @@ Rectangle { text: "OFF" boxSize: 20 } - - // TextStyle9 - - RalewaySemiBold { - size: 17; - Layout.row: 2 - Layout.column: 0 - - text: "User Model:" - } - - - // sit stand combo box - HifiControlsUit.ComboBox { - Layout.row: 2 - Layout.column: 1 - id: userModelComboBox - comboBox.textRole: "text" - currentIndex: 2 - model: ListModel { - id: cbItems - ListElement { text: "Force Sitting"; color: "Yellow" } - ListElement { text: "Force Standing"; color: "Green" } - ListElement { text: "Auto Mode"; color: "Brown" } - ListElement { text: "Disable Recentering"; color: "Red" } - } - width: 200 - } } ColumnLayout { diff --git a/scripts/system/avatarapp.js b/scripts/system/avatarapp.js index 0c99460929..ece35acce7 100644 --- a/scripts/system/avatarapp.js +++ b/scripts/system/avatarapp.js @@ -64,7 +64,6 @@ function getMyAvatarSettings() { return { dominantHand: MyAvatar.getDominantHand(), collisionsEnabled : MyAvatar.getCollisionsEnabled(), - userRecenterModel: MyAvatar.userRecenterModel, collisionSoundUrl : MyAvatar.collisionSoundURL, animGraphUrl: MyAvatar.getAnimGraphUrl(), animGraphOverrideUrl : MyAvatar.getAnimGraphOverrideUrl(), @@ -137,14 +136,6 @@ function onCollisionsEnabledChanged(enabled) { } } -function onUserRecenterModelChanged(modelName) { - if (currentAvatarSettings.userRecenterModel !== modelName) { - currentAvatarSettings.userRecenterModel = modelName; - print("emit user recenter model changed"); - sendToQml({ 'method': 'settingChanged', 'name': 'userRecenterModel', 'value': modelName }) - } -} - function onNewCollisionSoundUrl(url) { if(currentAvatarSettings.collisionSoundUrl !== url) { currentAvatarSettings.collisionSoundUrl = url; @@ -320,11 +311,12 @@ function fromQml(message) { // messages are {method, params}, like json-rpc. See case 'saveSettings': MyAvatar.setAvatarScale(message.avatarScale); currentAvatar.avatarScale = message.avatarScale; + MyAvatar.setDominantHand(message.settings.dominantHand); MyAvatar.setCollisionsEnabled(message.settings.collisionsEnabled); - MyAvatar.userRecenterModel = message.settings.userRecenterModel; MyAvatar.collisionSoundURL = message.settings.collisionSoundUrl; MyAvatar.setAnimGraphOverrideUrl(message.settings.animGraphOverrideUrl); + settings = getMyAvatarSettings(); break; default: @@ -497,7 +489,6 @@ function off() { MyAvatar.skeletonModelURLChanged.disconnect(onSkeletonModelURLChanged); MyAvatar.dominantHandChanged.disconnect(onDominantHandChanged); MyAvatar.collisionsEnabledChanged.disconnect(onCollisionsEnabledChanged); - MyAvatar.userRecenterModelChanged.disconnect(onUserRecenterModelChanged); MyAvatar.newCollisionSoundURL.disconnect(onNewCollisionSoundUrl); MyAvatar.animGraphUrlChanged.disconnect(onAnimGraphUrlChanged); MyAvatar.targetScaleChanged.disconnect(onTargetScaleChanged); @@ -512,7 +503,6 @@ function on() { MyAvatar.skeletonModelURLChanged.connect(onSkeletonModelURLChanged); MyAvatar.dominantHandChanged.connect(onDominantHandChanged); MyAvatar.collisionsEnabledChanged.connect(onCollisionsEnabledChanged); - MyAvatar.userRecenterModelChanged.connect(onUserRecenterModelChanged); MyAvatar.newCollisionSoundURL.connect(onNewCollisionSoundUrl); MyAvatar.animGraphUrlChanged.connect(onAnimGraphUrlChanged); MyAvatar.targetScaleChanged.connect(onTargetScaleChanged); From 39a16703e4c6efafd1e8f2beb4ec0b88964fdbf9 Mon Sep 17 00:00:00 2001 From: amantley Date: Tue, 23 Oct 2018 10:52:14 -0700 Subject: [PATCH 51/54] updated wording for the radio buttons for avatar leaning model --- interface/src/avatar/MyAvatar.cpp | 2 +- interface/src/ui/PreferencesDialog.cpp | 45 +++++++++++++------------- 2 files changed, 23 insertions(+), 24 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index c55a257d6a..dd40a748af 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -533,7 +533,7 @@ void MyAvatar::update(float deltaTime) { float tau = deltaTime / HMD_FACING_TIMESCALE; setHipToHandController(computeHandAzimuth()); - qCDebug(interfaceapp) << "lock " << _lockSitStandState.get() << " sit " << _isInSittingState.get() << " hmd lean "<< _hmdLeanRecenterEnabled; + // put the average hand azimuth into sensor space. // then mix it with head facing direction to determine rotation recenter if (getControllerPoseInAvatarFrame(controller::Action::LEFT_HAND).isValid() && getControllerPoseInAvatarFrame(controller::Action::RIGHT_HAND).isValid()) { diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index eeca96222b..92628c23b7 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -243,29 +243,6 @@ void setupPreferences() { preference->setIndented(true); preferences->addPreference(preference); } - { - auto getter = [myAvatar]()->int { if (myAvatar->getUserRecenterModel() == MyAvatar::SitStandModelType::Auto) { - return 0; - } else if (myAvatar->getUserRecenterModel() == MyAvatar::SitStandModelType::ForceSit) { - return 1; - } else { - return 2; - }}; - auto setter = [myAvatar](int value) { if (value == 0) { - myAvatar->setUserRecenterModel(MyAvatar::SitStandModelType::Auto); - } else if (value == 1) { - myAvatar->setUserRecenterModel(MyAvatar::SitStandModelType::ForceSit); - } else { - myAvatar->setUserRecenterModel(MyAvatar::SitStandModelType::DisableHMDLean); - }}; - auto preference = new RadioButtonsPreference(VR_MOVEMENT, "Auto / Force Sit / Disable Recenter", getter, setter); - QStringList items; - items << "Auto" << "Force Sitting" << "Disable Recenter"; - preference->setHeading("User Activity mode"); - preference->setItems(items); - preferences->addPreference(preference); - } - { auto getter = [myAvatar]()->int { return myAvatar->getSnapTurn() ? 0 : 1; }; auto setter = [myAvatar](int value) { myAvatar->setSnapTurn(value == 0); }; @@ -282,6 +259,28 @@ void setupPreferences() { auto preference = new CheckPreference(VR_MOVEMENT, "Show room boundaries while teleporting", getter, setter); preferences->addPreference(preference); } + { + auto getter = [myAvatar]()->int { if (myAvatar->getUserRecenterModel() == MyAvatar::SitStandModelType::Auto) { + return 0; + } else if (myAvatar->getUserRecenterModel() == MyAvatar::SitStandModelType::ForceSit) { + return 1; + } else { + return 2; + }}; + auto setter = [myAvatar](int value) { if (value == 0) { + myAvatar->setUserRecenterModel(MyAvatar::SitStandModelType::Auto); + } else if (value == 1) { + myAvatar->setUserRecenterModel(MyAvatar::SitStandModelType::ForceSit); + } else { + myAvatar->setUserRecenterModel(MyAvatar::SitStandModelType::DisableHMDLean); + }}; + auto preference = new RadioButtonsPreference(VR_MOVEMENT, "Auto / Force Sit / Disable Recenter", getter, setter); + QStringList items; + items << "Auto - turns on avatar leaning when standing in real world" << "Seated - disables all avatar leaning while sitting in real world" << "Disabled - allows avatar sitting on the floor [Experimental]"; + preference->setHeading("Avatar leaning behavior"); + preference->setItems(items); + preferences->addPreference(preference); + } { auto getter = [=]()->float { return myAvatar->getUserHeight(); }; auto setter = [=](float value) { myAvatar->setUserHeight(value); }; From 0d39343be4fee9954ef870c091ea6b6270d0191e Mon Sep 17 00:00:00 2001 From: amantley Date: Tue, 23 Oct 2018 11:19:47 -0700 Subject: [PATCH 52/54] changed if statement to switch in preferencesDialog.cpp, also removed print statement --- interface/src/ui/PreferencesDialog.cpp | 35 +++++++++++++++----------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index 92628c23b7..2b8f991174 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -260,20 +260,27 @@ void setupPreferences() { preferences->addPreference(preference); } { - auto getter = [myAvatar]()->int { if (myAvatar->getUserRecenterModel() == MyAvatar::SitStandModelType::Auto) { - return 0; - } else if (myAvatar->getUserRecenterModel() == MyAvatar::SitStandModelType::ForceSit) { - return 1; - } else { - return 2; - }}; - auto setter = [myAvatar](int value) { if (value == 0) { - myAvatar->setUserRecenterModel(MyAvatar::SitStandModelType::Auto); - } else if (value == 1) { - myAvatar->setUserRecenterModel(MyAvatar::SitStandModelType::ForceSit); - } else { - myAvatar->setUserRecenterModel(MyAvatar::SitStandModelType::DisableHMDLean); - }}; + auto getter = [myAvatar]()->int { switch (myAvatar->getUserRecenterModel()) { + case MyAvatar::SitStandModelType::Auto: + default: + return 0; + case MyAvatar::SitStandModelType::ForceSit: + return 1; + case MyAvatar::SitStandModelType::DisableHMDLean: + return 2; + }}; + auto setter = [myAvatar](int value) { switch (value) { + case 0: + default: + myAvatar->setUserRecenterModel(MyAvatar::SitStandModelType::Auto); + break; + case 1: + myAvatar->setUserRecenterModel(MyAvatar::SitStandModelType::ForceSit); + break; + case 2: + myAvatar->setUserRecenterModel(MyAvatar::SitStandModelType::DisableHMDLean); + break; + }}; auto preference = new RadioButtonsPreference(VR_MOVEMENT, "Auto / Force Sit / Disable Recenter", getter, setter); QStringList items; items << "Auto - turns on avatar leaning when standing in real world" << "Seated - disables all avatar leaning while sitting in real world" << "Disabled - allows avatar sitting on the floor [Experimental]"; From 9bc92cb2a33cf982ff894057a0a65454d6cb7840 Mon Sep 17 00:00:00 2001 From: amantley Date: Tue, 23 Oct 2018 12:29:04 -0700 Subject: [PATCH 53/54] removed leftover triggers --- interface/src/avatar/MyAvatar.cpp | 4 +--- interface/src/avatar/MyAvatar.h | 23 ----------------------- 2 files changed, 1 insertion(+), 26 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index dd40a748af..78cfed9b30 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -3961,6 +3961,7 @@ void MyAvatar::setUserRecenterModel(MyAvatar::SitStandModelType modelName) { setIsSitStandStateLocked(true); break; case MyAvatar::SitStandModelType::Auto: + default: setHMDLeanRecenterEnabled(true); setIsInSittingState(false); setIsSitStandStateLocked(false); @@ -3970,10 +3971,7 @@ void MyAvatar::setUserRecenterModel(MyAvatar::SitStandModelType modelName) { setIsInSittingState(false); setIsSitStandStateLocked(false); break; - default: - break; } - emit userRecenterModelChanged((int)modelName); } void MyAvatar::setIsSitStandStateLocked(bool isLocked) { diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 0f6f9d9411..8bbf163bd8 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -1555,29 +1555,6 @@ signals: */ void disableHandTouchForIDChanged(const QUuid& entityID, bool disable); - /**jsdoc - * Triggered when the sit state is enabled or disabled - * @function MyAvatar.sittingEnabledChanged - * @param {boolean} enabled - * @returns {Signal} - */ - void sittingEnabledChanged(bool enabled); - - /**jsdoc - * Triggered when the recenter model is changed - * @function MyAvatar.userRecenterModelChanged - * @param {int} userRecenteringModeltype - * @returns {Signal} - */ - void userRecenterModelChanged(int modelName); - - /**jsdoc - * Triggered when the sit state is enabled or disabled - * @function MyAvatar.sitStandStateLockEnabledChanged - * @param {boolean} enabled - * @returns {Signal} - */ - void sitStandStateLockEnabledChanged(bool enabled); private slots: void leaveDomain(); From 2df9d6c5e9065fbe9b83eb975dccec98a6273f2c Mon Sep 17 00:00:00 2001 From: amantley Date: Tue, 23 Oct 2018 13:37:56 -0700 Subject: [PATCH 54/54] addressed missing changes for luis --- interface/src/avatar/MyAvatar.cpp | 32 +++++++++--------- interface/src/ui/PreferencesDialog.cpp | 46 ++++++++++++++------------ 2 files changed, 42 insertions(+), 36 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 78cfed9b30..71c3ba4fc6 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -530,6 +530,7 @@ void MyAvatar::update(float deltaTime) { const float PERCENTAGE_WEIGHT_HEAD_VS_SHOULDERS_AZIMUTH = 0.0f; // 100 percent shoulders const float COSINE_THIRTY_DEGREES = 0.866f; const float SQUATTY_TIMEOUT = 30.0f; // 30 seconds + const float HEIGHT_FILTER_COEFFICIENT = 0.01f; float tau = deltaTime / HMD_FACING_TIMESCALE; setHipToHandController(computeHandAzimuth()); @@ -559,7 +560,7 @@ void MyAvatar::update(float deltaTime) { controller::Pose newHeightReading = getControllerPoseInSensorFrame(controller::Action::HEAD); if (newHeightReading.isValid()) { int newHeightReadingInCentimeters = glm::floor(newHeightReading.getTranslation().y * CENTIMETERS_PER_METER); - _averageUserHeightSensorSpace = lerp(_averageUserHeightSensorSpace, newHeightReading.getTranslation().y, 0.01f); + _averageUserHeightSensorSpace = lerp(_averageUserHeightSensorSpace, newHeightReading.getTranslation().y, HEIGHT_FILTER_COEFFICIENT); _recentModeReadings.insert(newHeightReadingInCentimeters); setCurrentStandingHeight(computeStandingHeightMode(newHeightReading)); setAverageHeadRotation(computeAverageHeadRotation(getControllerPoseInAvatarFrame(controller::Action::HEAD))); @@ -4232,21 +4233,22 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(const MyAvatar& myAvatar, co if (myAvatar.getSitStandStateChange()) { returnValue = true; - } - if (myAvatar.getIsInSittingState()) { - if (myAvatar.getIsSitStandStateLocked()) { - returnValue = (offset.y > CYLINDER_TOP); - } - if (offset.y < SITTING_BOTTOM) { - // we recenter more easily when in sitting state. - returnValue = true; - } } else { - // in the standing state - returnValue = (offset.y > CYLINDER_TOP) || (offset.y < CYLINDER_BOTTOM); - // finally check for squats in standing - if (_squatDetected) { - returnValue = true; + if (myAvatar.getIsInSittingState()) { + if (myAvatar.getIsSitStandStateLocked()) { + returnValue = (offset.y > CYLINDER_TOP); + } + if (offset.y < SITTING_BOTTOM) { + // we recenter more easily when in sitting state. + returnValue = true; + } + } else { + // in the standing state + returnValue = (offset.y > CYLINDER_TOP) || (offset.y < CYLINDER_BOTTOM); + // finally check for squats in standing + if (_squatDetected) { + returnValue = true; + } } } return returnValue; diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index 2b8f991174..34d80f50cf 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -260,27 +260,31 @@ void setupPreferences() { preferences->addPreference(preference); } { - auto getter = [myAvatar]()->int { switch (myAvatar->getUserRecenterModel()) { - case MyAvatar::SitStandModelType::Auto: - default: - return 0; - case MyAvatar::SitStandModelType::ForceSit: - return 1; - case MyAvatar::SitStandModelType::DisableHMDLean: - return 2; - }}; - auto setter = [myAvatar](int value) { switch (value) { - case 0: - default: - myAvatar->setUserRecenterModel(MyAvatar::SitStandModelType::Auto); - break; - case 1: - myAvatar->setUserRecenterModel(MyAvatar::SitStandModelType::ForceSit); - break; - case 2: - myAvatar->setUserRecenterModel(MyAvatar::SitStandModelType::DisableHMDLean); - break; - }}; + auto getter = [myAvatar]()->int { + switch (myAvatar->getUserRecenterModel()) { + case MyAvatar::SitStandModelType::Auto: + default: + return 0; + case MyAvatar::SitStandModelType::ForceSit: + return 1; + case MyAvatar::SitStandModelType::DisableHMDLean: + return 2; + } + }; + auto setter = [myAvatar](int value) { + switch (value) { + case 0: + default: + myAvatar->setUserRecenterModel(MyAvatar::SitStandModelType::Auto); + break; + case 1: + myAvatar->setUserRecenterModel(MyAvatar::SitStandModelType::ForceSit); + break; + case 2: + myAvatar->setUserRecenterModel(MyAvatar::SitStandModelType::DisableHMDLean); + break; + } + }; auto preference = new RadioButtonsPreference(VR_MOVEMENT, "Auto / Force Sit / Disable Recenter", getter, setter); QStringList items; items << "Auto - turns on avatar leaning when standing in real world" << "Seated - disables all avatar leaning while sitting in real world" << "Disabled - allows avatar sitting on the floor [Experimental]";