diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 24a25f314d..1adcfbd345 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1961,6 +1961,32 @@ void MyAvatar::updateOrientation(float deltaTime) { totalBodyYaw += (speedFactor * deltaAngle * (180.0f / PI)); } + // Use head/HMD roll to turn while walking or flying. + if (qApp->isHMDMode() && _hmdRollControlEnabled) { + // Turn with head roll. + const float MIN_CONTROL_SPEED = 0.01f; + float speed = glm::length(getVelocity()); + if (speed >= MIN_CONTROL_SPEED) { + // Feather turn when stopping moving. + float speedFactor; + if (getDriveKey(TRANSLATE_Z) != 0.0f || _lastDrivenSpeed == 0.0f) { + _lastDrivenSpeed = speed; + speedFactor = 1.0f; + } else { + speedFactor = glm::min(speed / _lastDrivenSpeed, 1.0f); + } + + float direction = glm::dot(getVelocity(), getRotation() * Vectors::UNIT_NEG_Z) > 0.0f ? 1.0f : -1.0f; + + float rollAngle = glm::degrees(asinf(glm::dot(IDENTITY_UP, _hmdSensorOrientation * IDENTITY_RIGHT))); + float rollSign = rollAngle < 0.0f ? -1.0f : 1.0f; + rollAngle = fabsf(rollAngle); + rollAngle = rollAngle > _hmdRollControlDeadZone ? rollSign * (rollAngle - _hmdRollControlDeadZone) : 0.0f; + + totalBodyYaw += speedFactor * direction * rollAngle * deltaTime * _hmdRollControlRate; + } + } + // update body orientation by movement inputs glm::quat initialOrientation = getOrientationOutbound(); setOrientation(getOrientation() * glm::quat(glm::radians(glm::vec3(0.0f, totalBodyYaw, 0.0f)))); diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index cfe66eb10e..f61f24fb11 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -132,6 +132,10 @@ class MyAvatar : public Avatar { Q_PROPERTY(bool characterControllerEnabled READ getCharacterControllerEnabled WRITE setCharacterControllerEnabled) Q_PROPERTY(bool useAdvancedMovementControls READ useAdvancedMovementControls WRITE setUseAdvancedMovementControls) + Q_PROPERTY(bool hmdRollControlEnabled READ getHMDRollControlEnabled WRITE setHMDRollControlEnabled) + Q_PROPERTY(float hmdRollControlDeadZone READ getHMDRollControlDeadZone WRITE setHMDRollControlDeadZone) + Q_PROPERTY(float hmdRollControlRate READ getHMDRollControlRate WRITE setHMDRollControlRate) + public: enum DriveKeys { TRANSLATE_X = 0, @@ -337,6 +341,13 @@ public: void setUseAdvancedMovementControls(bool useAdvancedMovementControls) { _useAdvancedMovementControls.set(useAdvancedMovementControls); } + void setHMDRollControlEnabled(bool value) { _hmdRollControlEnabled = value; } + bool getHMDRollControlEnabled() const { return _hmdRollControlEnabled; } + void setHMDRollControlDeadZone(float value) { _hmdRollControlDeadZone = value; } + float getHMDRollControlDeadZone() const { return _hmdRollControlDeadZone; } + void setHMDRollControlRate(float value) { _hmdRollControlRate = value; } + float getHMDRollControlRate() const { return _hmdRollControlRate; } + // get/set avatar data void saveData(); void loadData(); @@ -687,6 +698,13 @@ private: bool _useSnapTurn { true }; bool _clearOverlayWhenMoving { true }; + const float ROLL_CONTROL_DEAD_ZONE_DEFAULT = 8.0f; // deg + const float ROLL_CONTROL_RATE_DEFAULT = 2.5f; // deg/sec/deg + bool _hmdRollControlEnabled { true }; + float _hmdRollControlDeadZone { ROLL_CONTROL_DEAD_ZONE_DEFAULT }; + float _hmdRollControlRate { ROLL_CONTROL_RATE_DEFAULT }; + float _lastDrivenSpeed { 0.0f }; + // working copies -- see AvatarData for thread-safe _sensorToWorldMatrixCache, used for outward facing access glm::mat4 _sensorToWorldMatrix { glm::mat4() }; diff --git a/scripts/developer/hmdRollControlDisable.js b/scripts/developer/hmdRollControlDisable.js new file mode 100644 index 0000000000..fe8a85e3e5 --- /dev/null +++ b/scripts/developer/hmdRollControlDisable.js @@ -0,0 +1,17 @@ +// +// hmdRollControlDisable.js +// +// Created by David Rowe on 4 Jun 2017. +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0 +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +var hmdRollControlEnabled = false; + +//print("HMD roll control: " + hmdRollControlEnabled); + +MyAvatar.hmdRollControlEnabled = hmdRollControlEnabled; + +Script.stop(); diff --git a/scripts/developer/hmdRollControlEnable.js b/scripts/developer/hmdRollControlEnable.js new file mode 100644 index 0000000000..81318b7ddd --- /dev/null +++ b/scripts/developer/hmdRollControlEnable.js @@ -0,0 +1,21 @@ +// +// hmdRollControlEnable.js +// +// Created by David Rowe on 4 Jun 2017. +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0 +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +var hmdRollControlEnabled = true; +var hmdRollControlDeadZone = 8.0; // deg +var hmdRollControlRate = 2.5; // deg/sec/deg + +//print("HMD roll control: " + hmdRollControlEnabled + ", " + hmdRollControlDeadZone + ", " + hmdRollControlRate); + +MyAvatar.hmdRollControlEnabled = hmdRollControlEnabled; +MyAvatar.hmdRollControlDeadZone = hmdRollControlDeadZone; +MyAvatar.hmdRollControlRate = hmdRollControlRate; + +Script.stop();