From 0fac1e134f1fb0a66a1a8d6b54785646f56e7039 Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Mon, 30 Sep 2019 16:43:02 -0700 Subject: [PATCH 1/4] Allow avatar look at when in first person camera --- interface/src/Application.cpp | 17 ++++------ interface/src/avatar/MyAvatar.cpp | 53 ++++++++++++++++++++++--------- interface/src/avatar/MyAvatar.h | 1 + 3 files changed, 46 insertions(+), 25 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 6a320e53ee..7c08f7d978 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3601,10 +3601,9 @@ void Application::updateCamera(RenderArgs& renderArgs, float deltaTime) { mat4 camMat = myAvatar->getSensorToWorldMatrix() * myAvatar->getHMDSensorMatrix(); _myCamera.setPosition(extractTranslation(camMat)); _myCamera.setOrientation(glmExtractRotation(camMat)); - } - else { - _myCamera.setPosition(myAvatar->getDefaultEyePosition()); - _myCamera.setOrientation(myAvatar->getMyHead()->getHeadOrientation()); + } else { + _myCamera.setPosition(myAvatar->getLookAtPivotPoint()); + _myCamera.setOrientation(myAvatar->getLookAtRotation()); } } else if (mode == CAMERA_MODE_THIRD_PERSON || mode == CAMERA_MODE_LOOK_AT || mode == CAMERA_MODE_SELFIE) { if (isHMDMode()) { @@ -3638,9 +3637,9 @@ void Application::updateCamera(RenderArgs& renderArgs, float deltaTime) { if (mode == CAMERA_MODE_SELFIE) { lookAtRotation = lookAtRotation * glm::angleAxis(PI, myAvatar->getWorldOrientation() * Vectors::UP); } - _myCamera.setPosition(myAvatar->getDefaultEyePosition() + _myCamera.setPosition(myAvatar->getLookAtPivotPoint() + lookAtRotation * boomOffset); - _myCamera.lookAt(myAvatar->getDefaultEyePosition()); + _myCamera.lookAt(myAvatar->getLookAtPivotPoint()); } } } else if (mode == CAMERA_MODE_MIRROR) { @@ -3668,8 +3667,7 @@ void Application::updateCamera(RenderArgs& renderArgs, float deltaTime) { + glm::vec3(0, _raiseMirror * myAvatar->getModelScale(), 0) + mirrorBodyOrientation * glm::vec3(0.0f, 0.0f, 1.0f) * MIRROR_FULLSCREEN_DISTANCE * _scaleMirror + mirrorBodyOrientation * hmdOffset); - } - else { + } else { auto userInputMapper = DependencyManager::get(); const float YAW_SPEED = TWO_PI / 5.0f; float deltaYaw = userInputMapper->getActionState(controller::Action::YAW) * YAW_SPEED * deltaTime; @@ -3690,8 +3688,7 @@ void Application::updateCamera(RenderArgs& renderArgs, float deltaTime) { _myCamera.setOrientation(cameraEntity->getWorldOrientation() * hmdRotation); glm::vec3 hmdOffset = extractTranslation(myAvatar->getHMDSensorMatrix()); _myCamera.setPosition(cameraEntity->getWorldPosition() + (hmdRotation * hmdOffset)); - } - else { + } else { _myCamera.setOrientation(cameraEntity->getWorldOrientation()); _myCamera.setPosition(cameraEntity->getWorldPosition()); } diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 6f16e6e1bf..8728c2bd80 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -953,7 +953,7 @@ void MyAvatar::simulate(float deltaTime, bool inView) { head->setScale(getModelScale()); head->simulate(deltaTime); CameraMode mode = qApp->getCamera().getMode(); - if (_scriptControlsHeadLookAt || mode == CAMERA_MODE_LOOK_AT || mode == CAMERA_MODE_SELFIE) { + if (_scriptControlsHeadLookAt || mode == CAMERA_MODE_FIRST_PERSON || mode == CAMERA_MODE_LOOK_AT || mode == CAMERA_MODE_SELFIE) { updateHeadLookAt(deltaTime); } else if (_headLookAtActive){ resetHeadLookAt(); @@ -3429,8 +3429,10 @@ void MyAvatar::updateOrientation(float deltaTime) { // Smoothly rotate body with arrow keys float targetSpeed = getDriveKey(YAW) * _yawSpeed; CameraMode mode = qApp->getCamera().getMode(); - bool computeLookAt = (mode == CAMERA_MODE_LOOK_AT || mode == CAMERA_MODE_SELFIE) && isReadyForPhysics() && !qApp->isHMDMode(); - if (computeLookAt) { + bool computeLookAt = isReadyForPhysics() && !qApp->isHMDMode() && + (mode == CAMERA_MODE_FIRST_PERSON || mode == CAMERA_MODE_LOOK_AT || mode == CAMERA_MODE_SELFIE); + bool smoothCameraYaw = computeLookAt && mode != CAMERA_MODE_FIRST_PERSON; + if (smoothCameraYaw) { // For "Look At" and "Selfie" camera modes we also smooth the yaw rotation from right-click mouse movement. float speedFromDeltaYaw = deltaTime > FLT_EPSILON ? getDriveKey(DELTA_YAW) / deltaTime : 0.0f; speedFromDeltaYaw *= _yawSpeed / YAW_SPEED_DEFAULT; @@ -3459,7 +3461,7 @@ void MyAvatar::updateOrientation(float deltaTime) { } } float totalBodyYaw = _bodyYawDelta * deltaTime; - if (!computeLookAt) { + if (!smoothCameraYaw) { // Rotate directly proportional to delta yaw and delta pitch from right-click mouse movement. totalBodyYaw += getDriveKey(DELTA_YAW) * _yawSpeed / YAW_SPEED_DEFAULT; } @@ -3546,12 +3548,16 @@ void MyAvatar::updateOrientation(float deltaTime) { blend = 1.0f; } glm::quat faceRotation = _lookAtYaw; - if (isMovingFwdBwd && isMovingSideways) { - // Reorient avatar to face camera diagonal - blend = DIAGONAL_TURN_BLEND; - float turnSign = getDriveKey(TRANSLATE_Z) < 0.0f ? -1.0f : 1.0f; - turnSign = getDriveKey(TRANSLATE_X) > 0.0f ? -turnSign : turnSign; - faceRotation = _lookAtYaw * glm::angleAxis(turnSign * 0.25f * PI, Vectors::UP); + if (isMovingFwdBwd) { + if (isMovingSideways) { + // Reorient avatar to face camera diagonal + blend = mode == CAMERA_MODE_FIRST_PERSON ? 1.0f : DIAGONAL_TURN_BLEND; + float turnSign = getDriveKey(TRANSLATE_Z) < 0.0f ? -1.0f : 1.0f; + turnSign = getDriveKey(TRANSLATE_X) > 0.0f ? -turnSign : turnSign; + faceRotation = _lookAtYaw * glm::angleAxis(turnSign * 0.25f * PI, Vectors::UP); + } else if (mode == CAMERA_MODE_FIRST_PERSON) { + blend = 1.0f; + } } setWorldOrientation(glm::slerp(getWorldOrientation(), faceRotation, blend)); } else if (isRotatingWhileSeated) { @@ -3615,11 +3621,21 @@ void MyAvatar::updateOrientation(float deltaTime) { const float REORIENT_ANGLE = 65.0f; const float TRIGGER_REORIENT_ANGLE = 45.0f; + const float FIRST_PERSON_TRIGGER_REORIENT_ANGLE = 45.0f; glm::vec3 ajustedYawVector = cameraYawVector; - if (frontBackDot < 0.0f) { - ajustedYawVector = (leftRightDot < 0.0f ? -avatarVectorRight : avatarVectorRight); - cameraVector = (ajustedYawVector * _lookAtPitch) * Vectors::FRONT; - if (frontBackDot < -glm::sin(glm::radians(TRIGGER_REORIENT_ANGLE))) { + float limitAngle = 0.0f; + float triggerAngle = -glm::sin(glm::radians(TRIGGER_REORIENT_ANGLE)); + if (mode == CAMERA_MODE_FIRST_PERSON) { + limitAngle = glm::sin(glm::radians(FIRST_PERSON_TRIGGER_REORIENT_ANGLE)); + triggerAngle = limitAngle; + } + + if (frontBackDot < limitAngle) { + if (frontBackDot < 0.0f) { + ajustedYawVector = (leftRightDot < 0.0f ? -avatarVectorRight : avatarVectorRight); + cameraVector = (ajustedYawVector * _lookAtPitch) * Vectors::FRONT; + } + if (frontBackDot < triggerAngle) { _shouldTurnToFaceCamera = true; } } else if (frontBackDot > glm::sin(glm::radians(REORIENT_ANGLE))) { @@ -3716,7 +3732,8 @@ glm::vec3 MyAvatar::scaleMotorSpeed(const glm::vec3 forward, const glm::vec3 rig } else { // Desktop mode. direction = (zSpeed * forward) + (xSpeed * right); - if (qApp->getCamera().getMode() == CAMERA_MODE_LOOK_AT && zSpeed != 0.0f && xSpeed != 0.0f){ + CameraMode mode = qApp->getCamera().getMode(); + if ((mode == CAMERA_MODE_LOOK_AT || mode == CAMERA_MODE_FIRST_PERSON || mode == CAMERA_MODE_SELFIE) && zSpeed != 0.0f && xSpeed != 0.0f){ direction = (zSpeed * forward); } @@ -6732,3 +6749,9 @@ void MyAvatar::setHeadLookAt(const glm::vec3& lookAtTarget) { _scriptHeadControlTimer = 0.0f; _lookAtScriptTarget = lookAtTarget; } + +glm::vec3 MyAvatar::getLookAtPivotPoint() { + glm::vec3 avatarUp = getWorldOrientation() * Vectors::UP; + glm::vec3 yAxisEyePosition = getWorldPosition() + avatarUp * glm::dot(avatarUp, _skeletonModel->getDefaultEyeModelPosition()); + return yAxisEyePosition; +} \ No newline at end of file diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 7b63e8e86b..6f90af7ece 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -1896,6 +1896,7 @@ public: void debugDrawPose(controller::Action action, const char* channelName, float size); bool getIsJointOverridden(int jointIndex) const; + glm::vec3 getLookAtPivotPoint(); public slots: From 18af7c5d84771ed67939ffac518efc24ff6eeae3 Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Tue, 1 Oct 2019 13:44:27 -0700 Subject: [PATCH 2/4] Add recenter timer and temp API --- interface/src/avatar/MyAvatar.cpp | 56 +++++++++++++++++++++++++++---- interface/src/avatar/MyAvatar.h | 7 ++++ 2 files changed, 57 insertions(+), 6 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 8728c2bd80..ac762dcc44 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -3619,17 +3619,18 @@ void MyAvatar::updateOrientation(float deltaTime) { glm::vec3 avatarVectorRight = getWorldOrientation() * Vectors::RIGHT; float leftRightDot = glm::dot(cameraYawVector, avatarVectorRight); - const float REORIENT_ANGLE = 65.0f; + const float DEFAULT_REORIENT_ANGLE = 65.0f; + const float FIRST_PERSON_REORIENT_ANGLE = 95.0f; const float TRIGGER_REORIENT_ANGLE = 45.0f; - const float FIRST_PERSON_TRIGGER_REORIENT_ANGLE = 45.0f; + // const float FIRST_PERSON_TRIGGER_REORIENT_ANGLE = 45.0f; glm::vec3 ajustedYawVector = cameraYawVector; float limitAngle = 0.0f; float triggerAngle = -glm::sin(glm::radians(TRIGGER_REORIENT_ANGLE)); if (mode == CAMERA_MODE_FIRST_PERSON) { - limitAngle = glm::sin(glm::radians(FIRST_PERSON_TRIGGER_REORIENT_ANGLE)); + limitAngle = glm::sin(glm::radians(90.0f - _recenterAngle)); triggerAngle = limitAngle; } - + float reorientAngle = mode == CAMERA_MODE_FIRST_PERSON ? FIRST_PERSON_REORIENT_ANGLE : DEFAULT_REORIENT_ANGLE; if (frontBackDot < limitAngle) { if (frontBackDot < 0.0f) { ajustedYawVector = (leftRightDot < 0.0f ? -avatarVectorRight : avatarVectorRight); @@ -3637,8 +3638,9 @@ void MyAvatar::updateOrientation(float deltaTime) { } if (frontBackDot < triggerAngle) { _shouldTurnToFaceCamera = true; + _firstPersonSteadyHeadTimer = 0.0f; } - } else if (frontBackDot > glm::sin(glm::radians(REORIENT_ANGLE))) { + } else if (frontBackDot > glm::sin(glm::radians(reorientAngle))) { _shouldTurnToFaceCamera = false; } @@ -3660,6 +3662,22 @@ void MyAvatar::updateOrientation(float deltaTime) { _lookAtCameraTarget = targetPoint; } _headLookAtActive = true; + // const float FIRST_PERSON_RECENTER_SECONDS = 5.0f; + if (mode == CAMERA_MODE_FIRST_PERSON) { + if (getDriveKey(YAW) + getDriveKey(STEP_YAW) + getDriveKey(DELTA_YAW) == 0.0f) { + if (_firstPersonSteadyHeadTimer < _recenterSeconds) { + if (_firstPersonSteadyHeadTimer > 0.0f) { + _firstPersonSteadyHeadTimer += deltaTime; + } + } else { + _shouldTurnToFaceCamera = true; + _firstPersonSteadyHeadTimer = 0.0f; + } + } else { + _firstPersonSteadyHeadTimer = deltaTime; + } + } + } else { head->setBaseYaw(0.0f); head->setBasePitch(getHead()->getBasePitch() + getDriveKey(PITCH) * _pitchSpeed * deltaTime @@ -6754,4 +6772,30 @@ glm::vec3 MyAvatar::getLookAtPivotPoint() { glm::vec3 avatarUp = getWorldOrientation() * Vectors::UP; glm::vec3 yAxisEyePosition = getWorldPosition() + avatarUp * glm::dot(avatarUp, _skeletonModel->getDefaultEyeModelPosition()); return yAxisEyePosition; -} \ No newline at end of file +} + +QVariantMap MyAvatar::getLookAtCameraData() { + QVariantMap result; + if (QThread::currentThread() != thread()) { + BLOCKING_INVOKE_METHOD(this, "getLookAtCameraData", + Q_RETURN_ARG(QVariantMap, result)); + return result; + } + result.insert("recenterSeconds", _recenterSeconds); + result.insert("recenterAngle", _recenterAngle); + return result; +} + +Q_INVOKABLE void MyAvatar::setLookAtCameraData(const QVariantMap& data) { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "setLookAtCameraData", + Q_ARG(const QVariantMap&, data)); + return; + } + if (data.contains("recenterSeconds")) { + _recenterSeconds = data["recenterSeconds"].toFloat(); + } + if (data.contains("recenterAngle")) { + _recenterAngle = data["recenterAngle"].toFloat(); + } +} diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 6f90af7ece..c3a2f76f70 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -1857,6 +1857,9 @@ public: */ Q_INVOKABLE QVariantMap getFlowData(); + Q_INVOKABLE QVariantMap getLookAtCameraData(); + Q_INVOKABLE void setLookAtCameraData(const QVariantMap& data); + /**jsdoc * Gets the indexes of currently colliding flow joints. * @function MyAvatar.getCollidingFlowJoints @@ -2654,6 +2657,10 @@ private: bool _shouldTurnToFaceCamera { false }; bool _scriptControlsHeadLookAt { false }; float _scriptHeadControlTimer { 0.0f }; + float _firstPersonSteadyHeadTimer { 0.0f }; + + float _recenterSeconds { 5.0f }; + float _recenterAngle { 45.0f }; Setting::Handle _realWorldFieldOfView; Setting::Handle _useAdvancedMovementControls; From 521aa50356c9077a5364c7926a651aba3c8eda93 Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Wed, 2 Oct 2019 11:43:06 -0700 Subject: [PATCH 3/4] Set time and angle recentering parameters --- interface/src/avatar/MyAvatar.cpp | 33 ++++--------------------------- interface/src/avatar/MyAvatar.h | 6 ------ 2 files changed, 4 insertions(+), 35 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index ac762dcc44..4f6bd616b4 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -3622,12 +3622,12 @@ void MyAvatar::updateOrientation(float deltaTime) { const float DEFAULT_REORIENT_ANGLE = 65.0f; const float FIRST_PERSON_REORIENT_ANGLE = 95.0f; const float TRIGGER_REORIENT_ANGLE = 45.0f; - // const float FIRST_PERSON_TRIGGER_REORIENT_ANGLE = 45.0f; + const float FIRST_PERSON_TRIGGER_REORIENT_ANGLE = 65.0f; glm::vec3 ajustedYawVector = cameraYawVector; float limitAngle = 0.0f; float triggerAngle = -glm::sin(glm::radians(TRIGGER_REORIENT_ANGLE)); if (mode == CAMERA_MODE_FIRST_PERSON) { - limitAngle = glm::sin(glm::radians(90.0f - _recenterAngle)); + limitAngle = glm::sin(glm::radians(90.0f - FIRST_PERSON_TRIGGER_REORIENT_ANGLE)); triggerAngle = limitAngle; } float reorientAngle = mode == CAMERA_MODE_FIRST_PERSON ? FIRST_PERSON_REORIENT_ANGLE : DEFAULT_REORIENT_ANGLE; @@ -3662,10 +3662,10 @@ void MyAvatar::updateOrientation(float deltaTime) { _lookAtCameraTarget = targetPoint; } _headLookAtActive = true; - // const float FIRST_PERSON_RECENTER_SECONDS = 5.0f; + const float FIRST_PERSON_RECENTER_SECONDS = 15.0f; if (mode == CAMERA_MODE_FIRST_PERSON) { if (getDriveKey(YAW) + getDriveKey(STEP_YAW) + getDriveKey(DELTA_YAW) == 0.0f) { - if (_firstPersonSteadyHeadTimer < _recenterSeconds) { + if (_firstPersonSteadyHeadTimer < FIRST_PERSON_RECENTER_SECONDS) { if (_firstPersonSteadyHeadTimer > 0.0f) { _firstPersonSteadyHeadTimer += deltaTime; } @@ -6774,28 +6774,3 @@ glm::vec3 MyAvatar::getLookAtPivotPoint() { return yAxisEyePosition; } -QVariantMap MyAvatar::getLookAtCameraData() { - QVariantMap result; - if (QThread::currentThread() != thread()) { - BLOCKING_INVOKE_METHOD(this, "getLookAtCameraData", - Q_RETURN_ARG(QVariantMap, result)); - return result; - } - result.insert("recenterSeconds", _recenterSeconds); - result.insert("recenterAngle", _recenterAngle); - return result; -} - -Q_INVOKABLE void MyAvatar::setLookAtCameraData(const QVariantMap& data) { - if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "setLookAtCameraData", - Q_ARG(const QVariantMap&, data)); - return; - } - if (data.contains("recenterSeconds")) { - _recenterSeconds = data["recenterSeconds"].toFloat(); - } - if (data.contains("recenterAngle")) { - _recenterAngle = data["recenterAngle"].toFloat(); - } -} diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index c3a2f76f70..e099ab0dbe 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -1857,9 +1857,6 @@ public: */ Q_INVOKABLE QVariantMap getFlowData(); - Q_INVOKABLE QVariantMap getLookAtCameraData(); - Q_INVOKABLE void setLookAtCameraData(const QVariantMap& data); - /**jsdoc * Gets the indexes of currently colliding flow joints. * @function MyAvatar.getCollidingFlowJoints @@ -2659,9 +2656,6 @@ private: float _scriptHeadControlTimer { 0.0f }; float _firstPersonSteadyHeadTimer { 0.0f }; - float _recenterSeconds { 5.0f }; - float _recenterAngle { 45.0f }; - Setting::Handle _realWorldFieldOfView; Setting::Handle _useAdvancedMovementControls; Setting::Handle _showPlayArea; From 75f0b4ea54c84f85dff2c3e28196d42eef94515c Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Wed, 2 Oct 2019 14:17:57 -0700 Subject: [PATCH 4/4] Fix First Person Camera issues --- interface/src/avatar/MyAvatar.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 090694b639..7af563608d 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -2718,7 +2718,8 @@ void MyAvatar::updateMotors() { if (_motionBehaviors & AVATAR_MOTION_ACTION_MOTOR_ENABLED) { if (_characterController.getState() == CharacterController::State::Hover || _characterController.computeCollisionMask() == BULLET_COLLISION_MASK_COLLISIONLESS) { - if (qApp->getCamera().getMode() == CAMERA_MODE_LOOK_AT || qApp->getCamera().getMode() == CAMERA_MODE_SELFIE) { + CameraMode mode = qApp->getCamera().getMode(); + if (mode == CAMERA_MODE_FIRST_PERSON || mode == CAMERA_MODE_LOOK_AT || mode == CAMERA_MODE_SELFIE) { motorRotation = getLookAtRotation(); } else { motorRotation = getMyHead()->getHeadOrientation(); @@ -5434,7 +5435,7 @@ glm::quat MyAvatar::getOrientationForAudio() { case AudioListenerMode::FROM_HEAD: { // Using the camera's orientation instead, when the current mode is controlling the avatar's head. CameraMode mode = qApp->getCamera().getMode(); - bool headFollowsCamera = mode == CAMERA_MODE_LOOK_AT || mode == CAMERA_MODE_SELFIE; + bool headFollowsCamera = mode == CAMERA_MODE_FIRST_PERSON || mode == CAMERA_MODE_LOOK_AT || mode == CAMERA_MODE_SELFIE; result = headFollowsCamera ? qApp->getCamera().getOrientation() : getHead()->getFinalOrientationInWorldFrame(); break; }