diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index dc1222a36e..3405938084 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1299,9 +1299,9 @@ void Application::editPreferences() { horizontalFieldOfView->setValue(_horizontalFieldOfView); form->addRow("Horizontal field of view (degrees):", horizontalFieldOfView); - QDoubleSpinBox* headCameraPitchYawScale = new QDoubleSpinBox(); - headCameraPitchYawScale->setValue(_headCameraPitchYawScale); - form->addRow("Head Camera Pitch/Yaw Scale:", headCameraPitchYawScale); + QDoubleSpinBox* gyroCameraSensitivity = new QDoubleSpinBox(); + gyroCameraSensitivity->setValue(_gyroCameraSensitivity); + form->addRow("Gyro Camera Sensitivity (0 - 1):", gyroCameraSensitivity); QDoubleSpinBox* leanScale = new QDoubleSpinBox(); leanScale->setValue(_myAvatar.getLeanScale()); @@ -1351,7 +1351,7 @@ void Application::editPreferences() { _myAvatar.getVoxels()->setVoxelURL(url); sendAvatarVoxelURLMessage(url); - _headCameraPitchYawScale = headCameraPitchYawScale->value(); + _gyroCameraSensitivity = gyroCameraSensitivity->value(); _myAvatar.setLeanScale(leanScale->value()); _audioJitterBufferSamples = audioJitterBufferSamples->value(); if (!shouldDynamicallySetJitterBuffer()) { @@ -2564,7 +2564,7 @@ void Application::update(float deltaTime) { if (!avatar->isInitialized()) { avatar->init(); } - avatar->simulate(deltaTime, NULL); + avatar->simulate(deltaTime, NULL, 0.f); avatar->setMouseRay(mouseRayOrigin, mouseRayDirection); } node->unlock(); @@ -2579,9 +2579,9 @@ void Application::update(float deltaTime) { } if (_transmitterDrives->isChecked() && _myTransmitter.isConnected()) { - _myAvatar.simulate(deltaTime, &_myTransmitter); + _myAvatar.simulate(deltaTime, &_myTransmitter, _gyroCameraSensitivity); } else { - _myAvatar.simulate(deltaTime, NULL); + _myAvatar.simulate(deltaTime, NULL, _gyroCameraSensitivity); } if (!OculusManager::isConnected()) { @@ -2648,9 +2648,6 @@ void Application::updateAvatar(float deltaTime) { // Update my avatar's state from gyros and/or webcam _myAvatar.updateFromGyrosAndOrWebcam(_gyroLook->isChecked(), - glm::vec3(_headCameraPitchYawScale, - _headCameraPitchYawScale, - _headCameraPitchYawScale), _pitchFromTouch); if (_serialHeadSensor.isActive()) { @@ -4089,11 +4086,11 @@ void Application::saveAction(QSettings* set, QAction* action) { } void Application::loadSettings(QSettings* settings) { - if (!settings) { + if (!settings) { settings = getSettings(); } - _headCameraPitchYawScale = loadSetting(settings, "headCameraPitchYawScale", 0.0f); + _gyroCameraSensitivity = loadSetting(settings, "gyroCameraSensitivity", 0.5f); _audioJitterBufferSamples = loadSetting(settings, "audioJitterBufferSamples", 0); _horizontalFieldOfView = loadSetting(settings, "horizontalFieldOfView", HORIZONTAL_FIELD_OF_VIEW_DEGREES); @@ -4117,7 +4114,7 @@ void Application::saveSettings(QSettings* settings) { settings = getSettings(); } - settings->setValue("headCameraPitchYawScale", _headCameraPitchYawScale); + settings->setValue("gyroCameraSensitivity", _gyroCameraSensitivity); settings->setValue("audioJitterBufferSamples", _audioJitterBufferSamples); settings->setValue("horizontalFieldOfView", _horizontalFieldOfView); settings->beginGroup("View Frustum Offset Camera"); diff --git a/interface/src/Application.h b/interface/src/Application.h index e6abd5f8d9..21870914d7 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -366,7 +366,7 @@ private: Environment _environment; int _headMouseX, _headMouseY; - float _headCameraPitchYawScale; + float _gyroCameraSensitivity; int _audioJitterBufferSamples; // Number of extra samples to wait before starting audio playback diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index c52e990605..7d5b019e33 100755 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -294,7 +294,6 @@ void Avatar::reset() { // Update avatar head rotation with sensor data void Avatar::updateFromGyrosAndOrWebcam(bool gyroLook, - const glm::vec3& amplifyAngle, float pitchFromTouch) { _head.setMousePitch(pitchFromTouch); SerialInterface* gyros = Application::getInstance()->getSerialHeadSensor(); @@ -333,9 +332,15 @@ void Avatar::updateFromGyrosAndOrWebcam(bool gyroLook, } else { _head.getFace().clearFrame(); } - _head.setPitch(estimatedRotation.x * amplifyAngle.x); - _head.setYaw(estimatedRotation.y * amplifyAngle.y); - _head.setRoll(estimatedRotation.z * amplifyAngle.z); + + // Set the rotation of the avatar's head (as seen by others, not affecting view frustum) + // to be scaled. Pitch is greater to emphasize nodding behavior / synchrony. + const float AVATAR_HEAD_PITCH_MAGNIFY = 1.0f; + const float AVATAR_HEAD_YAW_MAGNIFY = 1.0f; + const float AVATAR_HEAD_ROLL_MAGNIFY = 1.0f; + _head.setPitch(estimatedRotation.x * AVATAR_HEAD_PITCH_MAGNIFY); + _head.setYaw(estimatedRotation.y * AVATAR_HEAD_YAW_MAGNIFY); + _head.setRoll(estimatedRotation.z * AVATAR_HEAD_ROLL_MAGNIFY); _head.setCameraFollowsHead(gyroLook); // Update torso lean distance based on accelerometer data @@ -390,7 +395,7 @@ void Avatar::updateThrust(float deltaTime, Transmitter * transmitter) { // // Gather thrust information from keyboard and sensors to apply to avatar motion // - glm::quat orientation = getHead().getOrientation(); + glm::quat orientation = getHead().getCameraOrientation(); glm::vec3 front = orientation * IDENTITY_FRONT; glm::vec3 right = orientation * IDENTITY_RIGHT; glm::vec3 up = orientation * IDENTITY_UP; @@ -502,7 +507,7 @@ void Avatar::follow(Avatar* leadingAvatar) { } } -void Avatar::simulate(float deltaTime, Transmitter* transmitter) { +void Avatar::simulate(float deltaTime, Transmitter* transmitter, float gyroCameraSensitivity) { glm::quat orientation = getOrientation(); glm::vec3 front = orientation * IDENTITY_FRONT; @@ -752,7 +757,7 @@ void Avatar::simulate(float deltaTime, Transmitter* transmitter) { _head.setPosition(_bodyBall[ BODY_BALL_HEAD_BASE ].position); _head.setScale(_scale); _head.setSkinColor(glm::vec3(SKIN_COLOR[0], SKIN_COLOR[1], SKIN_COLOR[2])); - _head.simulate(deltaTime, isMyAvatar()); + _head.simulate(deltaTime, isMyAvatar(), gyroCameraSensitivity); _hand.simulate(deltaTime, isMyAvatar()); diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index 69629f1b83..9b1029ce18 100755 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -119,11 +119,10 @@ public: void init(); void reset(); - void simulate(float deltaTime, Transmitter* transmitter); + void simulate(float deltaTime, Transmitter* transmitter, float gyroCameraSensitivity); void updateThrust(float deltaTime, Transmitter * transmitter); void follow(Avatar* leadingAvatar); void updateFromGyrosAndOrWebcam(bool gyroLook, - const glm::vec3& amplifyAngle, float pitchFromTouch); void addBodyYaw(float bodyYaw) {_bodyYaw += bodyYaw;}; void addBodyYawDelta(float bodyYawDelta) {_bodyYawDelta += bodyYawDelta;} diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp index 6cdb69fe5e..8f1d511b02 100644 --- a/interface/src/avatar/Head.cpp +++ b/interface/src/avatar/Head.cpp @@ -146,7 +146,7 @@ void Head::resetHairPhysics() { } -void Head::simulate(float deltaTime, bool isMine) { +void Head::simulate(float deltaTime, bool isMine, float gyroCameraSensitivity) { // Update eye saccades const float AVERAGE_MICROSACCADE_INTERVAL = 0.50f; @@ -228,15 +228,18 @@ void Head::simulate(float deltaTime, bool isMine) { } // Update camera pitch and yaw independently from motion of head (for gyro-based interface) - if (isMine && _cameraFollowsHead) { + if (isMine && _cameraFollowsHead && (gyroCameraSensitivity > 0.f)) { // If we are using gyros and using gyroLook, have the camera follow head but with a null region // to create stable rendering view with small head movements. - const float CAMERA_FOLLOW_HEAD_RATE_START = 0.01f; - const float CAMERA_FOLLOW_HEAD_RATE_MAX = 0.5f; + const float CAMERA_FOLLOW_HEAD_RATE_START = 0.1f; + const float CAMERA_FOLLOW_HEAD_RATE_MAX = 1.0f; const float CAMERA_FOLLOW_HEAD_RATE_RAMP_RATE = 1.05f; const float CAMERA_STOP_TOLERANCE_DEGREES = 0.5f; - const float CAMERA_PITCH_START_TOLERANCE_DEGREES = 20.0f; - const float CAMERA_YAW_START_TOLERANCE_DEGREES = 10.0f; + const float PITCH_START_RANGE = 20.f; + const float YAW_START_RANGE = 10.f; + float pitchStartTolerance = PITCH_START_RANGE * (1.f - gyroCameraSensitivity); + float yawStartTolerance = YAW_START_RANGE * (1.f - gyroCameraSensitivity); + float cameraHeadAngleDifference = glm::length(glm::vec2(_pitch - _cameraPitch, _yaw - _cameraYaw)); if (_isCameraMoving) { _cameraFollowHeadRate = glm::clamp(_cameraFollowHeadRate * CAMERA_FOLLOW_HEAD_RATE_RAMP_RATE, @@ -249,17 +252,13 @@ void Head::simulate(float deltaTime, bool isMine) { _isCameraMoving = false; } } else { - if ((fabs(_pitch - _cameraPitch) > CAMERA_PITCH_START_TOLERANCE_DEGREES) || - (fabs(_yaw - _cameraYaw) > CAMERA_YAW_START_TOLERANCE_DEGREES)) { + if ((fabs(_pitch - _cameraPitch) > pitchStartTolerance) || + (fabs(_yaw - _cameraYaw) > yawStartTolerance)) { _isCameraMoving = true; _cameraFollowHeadRate = CAMERA_FOLLOW_HEAD_RATE_START; } } - } else { - // Camera always locked to head - _cameraPitch = _pitch; - _cameraYaw = _yaw; - } + } } void Head::calculateGeometry() { diff --git a/interface/src/avatar/Head.h b/interface/src/avatar/Head.h index f31bc53f2a..ea9e7fab0e 100644 --- a/interface/src/avatar/Head.h +++ b/interface/src/avatar/Head.h @@ -41,7 +41,7 @@ public: void init(); void reset(); - void simulate(float deltaTime, bool isMine); + void simulate(float deltaTime, bool isMine, float gyroCameraSensitivity); void render(float alpha); void renderMohawk();