diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index bd87ec47d8..249a765d92 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -67,8 +67,8 @@ using namespace std; const float DEFAULT_REAL_WORLD_FIELD_OF_VIEW_DEGREES = 30.0f; -const float YAW_SPEED_DEFAULT = 100.0f; // degrees/sec -const float PITCH_SPEED_DEFAULT = 75.0f; // degrees/sec +const float YAW_SPEED_DEFAULT = 75.0f; // degrees/sec +const float PITCH_SPEED_DEFAULT = 50.0f; // degrees/sec const float MAX_BOOST_SPEED = 0.5f * DEFAULT_AVATAR_MAX_WALKING_SPEED; // action motor gets additive boost below this speed const float MIN_AVATAR_SPEED = 0.05f; @@ -2227,7 +2227,7 @@ void MyAvatar::updateActionMotor(float deltaTime) { } float boomChange = getDriveKey(ZOOM); - _boomLength += 2.0f * _boomLength * boomChange + boomChange * boomChange; + _boomLength += 4.0f * _boomLength * boomChange + boomChange * boomChange; _boomLength = glm::clamp(_boomLength, ZOOM_MIN, ZOOM_MAX); } @@ -2760,6 +2760,18 @@ bool MyAvatar::isDriveKeyDisabled(DriveKeys key) const { } } +void MyAvatar::triggerVerticalRecenter() { + _follow.setForceActivateVertical(true); +} + +void MyAvatar::triggerHorizontalRecenter() { + _follow.setForceActivateHorizontal(true); +} + +void MyAvatar::triggerRotationRecenter() { + _follow.setForceActivateRotation(true); +} + // old school meat hook style glm::mat4 MyAvatar::deriveBodyFromHMDSensor() const { glm::vec3 headPosition; @@ -2957,7 +2969,9 @@ void MyAvatar::FollowHelper::decrementTimeRemaining(float dt) { bool MyAvatar::FollowHelper::shouldActivateRotation(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const { const float FOLLOW_ROTATION_THRESHOLD = cosf(PI / 6.0f); // 30 degrees glm::vec2 bodyFacing = getFacingDir2D(currentBodyMatrix); + return glm::dot(-myAvatar.getHeadControllerFacingMovingAverage(), bodyFacing) < FOLLOW_ROTATION_THRESHOLD; + } bool MyAvatar::FollowHelper::shouldActivateHorizontal(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const { @@ -2974,6 +2988,7 @@ 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; } else if (forwardLeanAmount < 0 && forwardLeanAmount < -MAX_BACKWARD_LEAN) { @@ -2981,6 +2996,7 @@ bool MyAvatar::FollowHelper::shouldActivateHorizontal(const MyAvatar& myAvatar, } return fabs(lateralLeanAmount) > MAX_LATERAL_LEAN; + } bool MyAvatar::FollowHelper::shouldActivateVertical(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const { @@ -2988,6 +3004,7 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(const MyAvatar& myAvatar, co const float CYLINDER_BOTTOM = -1.5f; glm::vec3 offset = extractTranslation(desiredBodyMatrix) - extractTranslation(currentBodyMatrix); + return (offset.y > CYLINDER_TOP) || (offset.y < CYLINDER_BOTTOM); } @@ -3005,6 +3022,19 @@ 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); + setForceActivateRotation(false); + } + if (!isActive(Horizontal) && getForceActivateHorizontal()) { + activate(Horizontal); + setForceActivateHorizontal(false); + } + if (!isActive(Vertical) && getForceActivateVertical()) { + activate(Vertical); + setForceActivateVertical(false); + } } glm::mat4 desiredWorldMatrix = myAvatar.getSensorToWorldMatrix() * desiredBodyMatrix; @@ -3054,6 +3084,30 @@ glm::mat4 MyAvatar::FollowHelper::postPhysicsUpdate(const MyAvatar& myAvatar, co } } +bool MyAvatar::FollowHelper::getForceActivateRotation() const { + return _forceActivateRotation; +} + +void MyAvatar::FollowHelper::setForceActivateRotation(bool val) { + _forceActivateRotation = val; +} + +bool MyAvatar::FollowHelper::getForceActivateVertical() const { + return _forceActivateVertical; +} + +void MyAvatar::FollowHelper::setForceActivateVertical(bool val) { + _forceActivateVertical = val; +} + +bool MyAvatar::FollowHelper::getForceActivateHorizontal() const { + return _forceActivateHorizontal; +} + +void MyAvatar::FollowHelper::setForceActivateHorizontal(bool val) { + _forceActivateHorizontal = val; +} + float MyAvatar::getAccelerationEnergy() { glm::vec3 velocity = getWorldVelocity(); int changeInVelocity = abs(velocity.length() - priorVelocity.length()); diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 108daf87a3..989ef0b241 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -405,6 +405,32 @@ public: Q_INVOKABLE void enableDriveKey(DriveKeys key); Q_INVOKABLE bool isDriveKeyDisabled(DriveKeys key) const; + /**jsdoc + *The triggerVerticalRecenter function activates one time the recentering + *behaviour in the vertical direction. This call is only takes effect when the property + *MyAvatar.hmdLeanRecenterEnabled is set to false. + *@function MyAvatar.triggerVerticalRecenter + * + */ + + /**jsdoc + *The triggerHorizontalRecenter function activates one time the recentering behaviour + *in the horizontal direction. This call is only takes effect when the property + *MyAvatar.hmdLeanRecenterEnabled is set to false. + *@function MyAvatar.triggerHorizontalRecenter + */ + + /**jsdoc + *The triggerRotationRecenter function activates one time the recentering behaviour + *in the rotation of the root of the avatar. This call is only takes effect when the property + *MyAvatar.hmdLeanRecenterEnabled is set to false. + *@function MyAvatar.triggerRotationRecenter + */ + + Q_INVOKABLE void triggerVerticalRecenter(); + Q_INVOKABLE void triggerHorizontalRecenter(); + Q_INVOKABLE void triggerRotationRecenter(); + eyeContactTarget getEyeContactTarget(); const MyHead* getMyHead() const; @@ -807,6 +833,15 @@ private: bool shouldActivateHorizontal(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) 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; + void setForceActivateRotation(bool val); + bool getForceActivateVertical() const; + void setForceActivateVertical(bool val); + bool getForceActivateHorizontal() const; + void setForceActivateHorizontal(bool val); + std::atomic _forceActivateRotation{ false }; + std::atomic _forceActivateVertical{ false }; + std::atomic _forceActivateHorizontal{ false }; }; FollowHelper _follow; @@ -843,6 +878,7 @@ private: bool _hmdLeanRecenterEnabled { true }; bool _sprint { false }; + AnimPose _prePhysicsRoomPose; std::mutex _holdActionsMutex; std::vector _holdActions; diff --git a/interface/src/scripting/AssetMappingsScriptingInterface.cpp b/interface/src/scripting/AssetMappingsScriptingInterface.cpp index c9bee659af..c5769ef4bb 100644 --- a/interface/src/scripting/AssetMappingsScriptingInterface.cpp +++ b/interface/src/scripting/AssetMappingsScriptingInterface.cpp @@ -80,7 +80,7 @@ void AssetMappingsScriptingInterface::uploadFile(QString path, QString mapping, auto result = offscreenUi->inputDialog(OffscreenUi::ICON_INFORMATION, "Specify Asset Path", dropEvent ? dropHelpText : helpText, mapping); - if (!result.isValid()) { + if (!result.isValid() || result.toString() == "") { completedCallback.call({ -1 }); return; } diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index 848f384687..0833b28142 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -1246,6 +1246,7 @@ void Rig::updateHands(bool leftHandEnabled, bool rightHandEnabled, bool hipsEnab const FBXJointShapeInfo& hipsShapeInfo, const FBXJointShapeInfo& spineShapeInfo, const FBXJointShapeInfo& spine1ShapeInfo, const FBXJointShapeInfo& spine2ShapeInfo) { + const bool ENABLE_POLE_VECTORS = false; const float ELBOW_POLE_VECTOR_BLEND_FACTOR = 0.95f; int hipsIndex = indexOfJoint("Hips"); @@ -1268,7 +1269,7 @@ void Rig::updateHands(bool leftHandEnabled, bool rightHandEnabled, bool hipsEnab int handJointIndex = _animSkeleton->nameToJointIndex("LeftHand"); int armJointIndex = _animSkeleton->nameToJointIndex("LeftArm"); int elbowJointIndex = _animSkeleton->nameToJointIndex("LeftForeArm"); - if (!leftArmEnabled && handJointIndex >= 0 && armJointIndex >= 0 && elbowJointIndex >= 0) { + if (ENABLE_POLE_VECTORS && !leftArmEnabled && handJointIndex >= 0 && armJointIndex >= 0 && elbowJointIndex >= 0) { glm::vec3 poleVector = calculateElbowPoleVector(handJointIndex, elbowJointIndex, armJointIndex, hipsIndex, true); // smooth toward desired pole vector from previous pole vector... to reduce jitter @@ -1315,7 +1316,7 @@ void Rig::updateHands(bool leftHandEnabled, bool rightHandEnabled, bool hipsEnab int handJointIndex = _animSkeleton->nameToJointIndex("RightHand"); int armJointIndex = _animSkeleton->nameToJointIndex("RightArm"); int elbowJointIndex = _animSkeleton->nameToJointIndex("RightForeArm"); - if (!rightArmEnabled && handJointIndex >= 0 && armJointIndex >= 0 && elbowJointIndex >= 0) { + if (ENABLE_POLE_VECTORS && !rightArmEnabled && handJointIndex >= 0 && armJointIndex >= 0 && elbowJointIndex >= 0) { glm::vec3 poleVector = calculateElbowPoleVector(handJointIndex, elbowJointIndex, armJointIndex, hipsIndex, false); // smooth toward desired pole vector from previous pole vector... to reduce jitter @@ -1555,18 +1556,21 @@ void Rig::updateFromControllerParameters(const ControllerParameters& params, flo updateFeet(leftFootEnabled, rightFootEnabled, params.primaryControllerPoses[PrimaryControllerType_LeftFoot], params.primaryControllerPoses[PrimaryControllerType_RightFoot]); + + if (headEnabled) { + // Blend IK chains toward the joint limit centers, this should stablize head and hand ik. + _animVars.set("solutionSource", (int)AnimInverseKinematics::SolutionSource::RelaxToLimitCenterPoses); + } else { + // Blend IK chains toward the UnderPoses, so some of the animaton motion is present in the IK solution. + _animVars.set("solutionSource", (int)AnimInverseKinematics::SolutionSource::RelaxToUnderPoses); + } + // if the hips or the feet are being controlled. if (hipsEnabled || rightFootEnabled || leftFootEnabled) { - // for more predictable IK solve from the center of the joint limits, not from the underpose - _animVars.set("solutionSource", (int)AnimInverseKinematics::SolutionSource::RelaxToLimitCenterPoses); - // replace the feet animation with the default pose, this is to prevent unexpected toe wiggling. _animVars.set("defaultPoseOverlayAlpha", 1.0f); _animVars.set("defaultPoseOverlayBoneSet", (int)AnimOverlay::BothFeetBoneSet); } else { - // augment the IK with the underPose. - _animVars.set("solutionSource", (int)AnimInverseKinematics::SolutionSource::RelaxToUnderPoses); - // feet should follow source animation _animVars.unset("defaultPoseOverlayAlpha"); _animVars.unset("defaultPoseOverlayBoneSet"); diff --git a/scripts/system/bubble.js b/scripts/system/bubble.js index 994bde49eb..f1a403a49c 100644 --- a/scripts/system/bubble.js +++ b/scripts/system/bubble.js @@ -89,14 +89,8 @@ bubbleOverlayTimestamp = nowTimestamp; Script.update.connect(update); updateConnected = true; - - // Flash button - if (!bubbleFlashTimer) { - bubbleFlashTimer = Script.setInterval(function () { - writeButtonProperties(bubbleButtonFlashState); - bubbleButtonFlashState = !bubbleButtonFlashState; - }, 500); - } + writeButtonProperties(bubbleButtonFlashState); + bubbleButtonFlashState = !bubbleButtonFlashState; } // Called from the C++ scripting interface to show the bubble overlay