diff --git a/interface/resources/qml/TestControllers.qml b/interface/resources/qml/TestControllers.qml index f1b8640c02..54b3cbf655 100644 --- a/interface/resources/qml/TestControllers.qml +++ b/interface/resources/qml/TestControllers.qml @@ -27,7 +27,8 @@ HifiControls.VrDialog { testMapping = Controller.newMapping(); testMapping.from(standard.RY).invert().to(actions.Pitch); testMapping.makeAxis(standard.LB, standard.RB).to(actions.Yaw); - testMapping.from(standard.RX).to(actions.StepYaw); + // Step yaw takes a number of degrees + testMapping.from(standard.RX).scale(15.0).to(actions.StepYaw); } function toggleMapping() { diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 4418f94b3a..3b54562770 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2718,15 +2718,13 @@ void Application::update(float deltaTime) { } // Transfer the user inputs to the driveKeys + // FIXME can we drop drive keys and just have the avatar read the action states directly? myAvatar->clearDriveKeys(); if (_myCamera.getMode() != CAMERA_MODE_INDEPENDENT) { if (!_controllerScriptingInterface->areActionsCaptured()) { - myAvatar->setDriveKeys(FWD, userInputMapper->getActionState(controller::Action::LONGITUDINAL_FORWARD)); - myAvatar->setDriveKeys(BACK, userInputMapper->getActionState(controller::Action::LONGITUDINAL_BACKWARD)); - myAvatar->setDriveKeys(UP, userInputMapper->getActionState(controller::Action::VERTICAL_UP)); - myAvatar->setDriveKeys(DOWN, userInputMapper->getActionState(controller::Action::VERTICAL_DOWN)); - myAvatar->setDriveKeys(LEFT, userInputMapper->getActionState(controller::Action::LATERAL_LEFT)); - myAvatar->setDriveKeys(RIGHT, userInputMapper->getActionState(controller::Action::LATERAL_RIGHT)); + myAvatar->setDriveKeys(TRANSLATE_Z, -1.0f * userInputMapper->getActionState(controller::Action::TRANSLATE_Z)); + myAvatar->setDriveKeys(TRANSLATE_Y, userInputMapper->getActionState(controller::Action::TRANSLATE_Y)); + myAvatar->setDriveKeys(TRANSLATE_X, userInputMapper->getActionState(controller::Action::TRANSLATE_X)); if (deltaTime > FLT_EPSILON) { // For rotations what we really want are meausures of "angles per second" (in order to prevent // fps-dependent spin rates) so we need to scale the units of the controller contribution. @@ -2734,14 +2732,12 @@ void Application::update(float deltaTime) { // controllers to provide a delta_per_second value rather than a raw delta.) const float EXPECTED_FRAME_RATE = 60.0f; float timeFactor = EXPECTED_FRAME_RATE * deltaTime; - myAvatar->setDriveKeys(ROT_UP, userInputMapper->getActionState(controller::Action::PITCH_UP) / timeFactor); - myAvatar->setDriveKeys(ROT_DOWN, userInputMapper->getActionState(controller::Action::PITCH_DOWN) / timeFactor); - myAvatar->setDriveKeys(ROT_LEFT, userInputMapper->getActionState(controller::Action::YAW_LEFT) / timeFactor); - myAvatar->setDriveKeys(ROT_RIGHT, userInputMapper->getActionState(controller::Action::YAW_RIGHT) / timeFactor); + myAvatar->setDriveKeys(PITCH, userInputMapper->getActionState(controller::Action::PITCH) / timeFactor); + myAvatar->setDriveKeys(YAW, -1.0f * userInputMapper->getActionState(controller::Action::YAW) / timeFactor); + myAvatar->setDriveKeys(STEP_YAW, -1.0f * userInputMapper->getActionState(controller::Action::STEP_YAW) / timeFactor); } } - myAvatar->setDriveKeys(BOOM_IN, userInputMapper->getActionState(controller::Action::BOOM_IN)); - myAvatar->setDriveKeys(BOOM_OUT, userInputMapper->getActionState(controller::Action::BOOM_OUT)); + myAvatar->setDriveKeys(ZOOM, userInputMapper->getActionState(controller::Action::TRANSLATE_CAMERA_Z)); } controller::Pose leftHand = userInputMapper->getPoseState(controller::Action::LEFT_HAND); controller::Pose rightHand = userInputMapper->getPoseState(controller::Action::RIGHT_HAND); diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index 9a46a145c2..6a1f216089 100644 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -43,21 +43,6 @@ static const float BILLBOARD_DISTANCE = 5.56f; // meters extern const float CHAT_MESSAGE_SCALE; extern const float CHAT_MESSAGE_HEIGHT; -enum DriveKeys { - FWD = 0, - BACK, - LEFT, - RIGHT, - UP, - DOWN, - ROT_LEFT, - ROT_RIGHT, - ROT_UP, - ROT_DOWN, - BOOM_IN, - BOOM_OUT, - MAX_DRIVE_KEYS -}; enum ScreenTintLayer { SCREEN_TINT_BEFORE_LANDSCAPE = 0, diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 5202138147..8ada0ca481 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -242,6 +242,7 @@ void MyAvatar::simulate(float deltaTime) { PerformanceTimer perfTimer("transform"); updateOrientation(deltaTime); updatePosition(deltaTime); + _lastStepPulse = _thisStepPulse; } { @@ -1552,71 +1553,49 @@ bool MyAvatar::shouldRenderHead(const RenderArgs* renderArgs) const { !cameraInsideHead()); } +static quint64 COMFORT_MODE_PULSE_TIMING = USECS_PER_SECOND / 2; // turn once per half second + void MyAvatar::updateOrientation(float deltaTime) { // Smoothly rotate body with arrow keys - float targetSpeed = 0.0f; - - // FIXME - this comfort mode code is a total hack, remove it when we have new input mapping - bool isComfortMode = Menu::getInstance()->isOptionChecked(MenuOption::ComfortMode); - bool isHMDMode = qApp->getAvatarUpdater()->isHMDMode(); - - if (!isHMDMode || !isComfortMode) { - targetSpeed = (_driveKeys[ROT_LEFT] - _driveKeys[ROT_RIGHT]) * YAW_SPEED; - - if (targetSpeed != 0.0f) { - const float ROTATION_RAMP_TIMESCALE = 0.1f; - float blend = deltaTime / ROTATION_RAMP_TIMESCALE; - if (blend > 1.0f) { - blend = 1.0f; - } - _bodyYawDelta = (1.0f - blend) * _bodyYawDelta + blend * targetSpeed; - } else if (_bodyYawDelta != 0.0f) { - // attenuate body rotation speed - const float ROTATION_DECAY_TIMESCALE = 0.05f; - float attenuation = 1.0f - deltaTime / ROTATION_DECAY_TIMESCALE; - if (attenuation < 0.0f) { - attenuation = 0.0f; - } - _bodyYawDelta *= attenuation; - - float MINIMUM_ROTATION_RATE = 2.0f; - if (fabsf(_bodyYawDelta) < MINIMUM_ROTATION_RATE) { - _bodyYawDelta = 0.0f; - } + float targetSpeed = _driveKeys[YAW] * YAW_SPEED; + if (targetSpeed != 0.0f) { + const float ROTATION_RAMP_TIMESCALE = 0.1f; + float blend = deltaTime / ROTATION_RAMP_TIMESCALE; + if (blend > 1.0f) { + blend = 1.0f; } + _bodyYawDelta = (1.0f - blend) * _bodyYawDelta + blend * targetSpeed; + } else if (_bodyYawDelta != 0.0f) { + // attenuate body rotation speed + const float ROTATION_DECAY_TIMESCALE = 0.05f; + float attenuation = 1.0f - deltaTime / ROTATION_DECAY_TIMESCALE; + if (attenuation < 0.0f) { + attenuation = 0.0f; + } + _bodyYawDelta *= attenuation; - // update body orientation by movement inputs - setOrientation(getOrientation() * - glm::quat(glm::radians(glm::vec3(0.0f, _bodyYawDelta * deltaTime, 0.0f)))); - - } else { - // Comfort Mode: If you press any of the left/right rotation drive keys or input, you'll - // get an instantaneous 15 degree turn. If you keep holding the key down you'll get another - // snap turn every half second. - _bodyYawDelta = 0.0f; - - static quint64 lastPulse = 0; - quint64 now = usecTimestampNow(); - quint64 COMFORT_MODE_PULSE_TIMING = USECS_PER_SECOND / 2; // turn once per half second - - float driveLeft = _driveKeys[ROT_LEFT]; - float driveRight= _driveKeys[ROT_RIGHT]; - - if ((driveLeft != 0.0f || driveRight != 0.0f) && (now - lastPulse > COMFORT_MODE_PULSE_TIMING)) { - lastPulse = now; - - const float SNAP_TURN_DELTA = 15.0f; // degrees - float direction = (driveLeft - driveRight) < 0.0f ? -1.0f : 1.0f; - float turnAmount = direction * SNAP_TURN_DELTA; - - // update body orientation by movement inputs - setOrientation(getOrientation() * - glm::quat(glm::radians(glm::vec3(0.0f, turnAmount, 0.0f)))); - + float MINIMUM_ROTATION_RATE = 2.0f; + if (fabsf(_bodyYawDelta) < MINIMUM_ROTATION_RATE) { + _bodyYawDelta = 0.0f; } } - getHead()->setBasePitch(getHead()->getBasePitch() + (_driveKeys[ROT_UP] - _driveKeys[ROT_DOWN]) * PITCH_SPEED * deltaTime); + float totalBodyYaw = _bodyYawDelta * deltaTime; + + + // Comfort Mode: If you press any of the left/right rotation drive keys or input, you'll + // get an instantaneous 15 degree turn. If you keep holding the key down you'll get another + // snap turn every half second. + quint64 now = usecTimestampNow(); + if (_driveKeys[STEP_YAW] != 0.0f && now - _lastStepPulse > COMFORT_MODE_PULSE_TIMING) { + _thisStepPulse = now; + totalBodyYaw += _driveKeys[STEP_YAW]; + } + + // update body orientation by movement inputs + setOrientation(getOrientation() * glm::quat(glm::radians(glm::vec3(0.0f, totalBodyYaw, 0.0f)))); + + getHead()->setBasePitch(getHead()->getBasePitch() + _driveKeys[PITCH] * PITCH_SPEED * deltaTime); if (qApp->getAvatarUpdater()->isHMDMode()) { glm::quat orientation = glm::quat_cast(getSensorToWorldMatrix()) * getHMDSensorOrientation(); @@ -1676,15 +1655,20 @@ glm::vec3 MyAvatar::applyKeyboardMotor(float deltaTime, const glm::vec3& localVe float motorEfficiency = glm::clamp(deltaTime / timescale, 0.0f, 1.0f); glm::vec3 newLocalVelocity = localVelocity; - float keyboardInput = fabsf(_driveKeys[FWD] - _driveKeys[BACK]) + - (fabsf(_driveKeys[RIGHT] - _driveKeys[LEFT])) + - fabsf(_driveKeys[UP] - _driveKeys[DOWN]); - if (keyboardInput) { - // Compute keyboard input - glm::vec3 front = (_driveKeys[FWD] - _driveKeys[BACK]) * IDENTITY_FRONT; - glm::vec3 right = (_driveKeys[RIGHT] - _driveKeys[LEFT]) * IDENTITY_RIGHT; - glm::vec3 up = (_driveKeys[UP] - _driveKeys[DOWN]) * IDENTITY_UP; + float stepControllerInput = fabsf(_driveKeys[STEP_TRANSLATE_Z]) + fabsf(_driveKeys[STEP_TRANSLATE_Z]) + fabsf(_driveKeys[STEP_TRANSLATE_Z]); + quint64 now = usecTimestampNow(); + if (stepControllerInput && now - _lastStepPulse > COMFORT_MODE_PULSE_TIMING) { + _thisStepPulse = now; + } + float keyboardInput = fabsf(_driveKeys[TRANSLATE_Z]) + fabsf(_driveKeys[TRANSLATE_X]) + fabsf(_driveKeys[TRANSLATE_Y]); + if (keyboardInput || (_thisStepPulse == now)) { + // Compute keyboard input + glm::vec3 front = (_driveKeys[TRANSLATE_Z]) * IDENTITY_FRONT; + glm::vec3 right = (_driveKeys[TRANSLATE_X]) * IDENTITY_RIGHT; + glm::vec3 up = (_driveKeys[TRANSLATE_Y]) * IDENTITY_UP; + + // FIXME how do I implement step translation as well? glm::vec3 direction = front + right + up; float directionLength = glm::length(direction); @@ -1734,7 +1718,7 @@ glm::vec3 MyAvatar::applyKeyboardMotor(float deltaTime, const glm::vec3& localVe } } - float boomChange = _driveKeys[BOOM_OUT] - _driveKeys[BOOM_IN]; + float boomChange = _driveKeys[ZOOM]; _boomLength += 2.0f * _boomLength * boomChange + boomChange * boomChange; _boomLength = glm::clamp(_boomLength, ZOOM_MIN, ZOOM_MAX); @@ -1983,7 +1967,7 @@ void MyAvatar::clearDriveKeys() { } void MyAvatar::relayDriveKeysToCharacterController() { - if (_driveKeys[UP] > 0.0f) { + if (_driveKeys[TRANSLATE_Y] > 0.0f) { _characterController.jump(); } } diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 4a0ae514f6..64814974b2 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -21,6 +21,20 @@ class ModelItemID; +enum DriveKeys { + TRANSLATE_X = 0, + TRANSLATE_Y, + TRANSLATE_Z, + YAW, + STEP_TRANSLATE_X, + STEP_TRANSLATE_Y, + STEP_TRANSLATE_Z, + STEP_YAW, + PITCH, + ZOOM, + MAX_DRIVE_KEYS +}; + enum eyeContactTarget { LEFT_EYE, RIGHT_EYE, @@ -376,6 +390,8 @@ private: AtRestDetector _hmdAtRestDetector; glm::vec3 _lastPosition; bool _lastIsMoving = false; + quint64 _lastStepPulse = 0; + quint64 _thisStepPulse = 0; }; QScriptValue audioListenModeToScriptValue(QScriptEngine* engine, const AudioListenerMode& audioListenerMode);