123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501 |
- /*
- * Copyright (c) Contributors to the Open 3D Engine Project.
- * For complete copyright and license terms please see the LICENSE at the root of this distribution.
- *
- * SPDX-License-Identifier: Apache-2.0 OR MIT
- *
- */
- #include <Atom/Component/DebugCamera/NoClipControllerComponent.h>
- #include <AzCore/Component/TransformBus.h>
- #include <AzCore/Serialization/SerializeContext.h>
- #include <AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard.h>
- #include <AzFramework/Input/Devices/Mouse/InputDeviceMouse.h>
- #include <AzFramework/Input/Devices/Gamepad/InputDeviceGamepad.h>
- #include <AzFramework/Input/Devices/Touch/InputDeviceTouch.h>
- #include <AzFramework/Components/CameraBus.h>
- #include <DebugCameraUtils.h>
- namespace AZ
- {
- namespace Debug
- {
- const AzFramework::InputChannelId NoClipControllerComponent::TouchEvent::InvalidTouchChannelId = AzFramework::InputChannelId("InvalidChannel");
- static constexpr float MaxFov = 160.0f * Constants::Pi / 180.0f;
- static constexpr float MinFov = 1.0f * Constants::Pi / 180.0f;
- static constexpr float DefaultFov = Constants::QuarterPi;
- static constexpr float deadZone = 0.07f;
- void NoClipControllerProperties::Reflect(AZ::ReflectContext* context)
- {
- if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
- {
- serializeContext->Class<NoClipControllerProperties>()
- ->Version(2)
- ->Field("Mouse Sensitivity X", &NoClipControllerProperties::m_mouseSensitivityX)
- ->Field("Mouse Sensitivity Y", &NoClipControllerProperties::m_mouseSensitivityY)
- ->Field("Move Speed", &NoClipControllerProperties::m_moveSpeed)
- ->Field("Panning Speed", &NoClipControllerProperties::m_panningSpeed)
- ->Field("Touch Sensitivity", &NoClipControllerProperties::m_touchSensitivity);
- }
- }
- NoClipControllerComponent::NoClipControllerComponent()
- : AzFramework::InputChannelEventListener(AzFramework::InputChannelEventListener::GetPriorityDefault())
- {}
- void NoClipControllerComponent::Reflect(AZ::ReflectContext* reflection)
- {
- NoClipControllerProperties::Reflect(reflection);
- if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(reflection))
- {
- serializeContext->Class<NoClipControllerComponent, CameraControllerComponent, AZ::Component>()
- ->Version(1)
- ->Field("Properties", &NoClipControllerComponent::m_properties);
- }
- }
- void NoClipControllerComponent::OnEnabled()
- {
- // Reset parameters
- m_mouseLookEnabled = false;
- m_inputStates = 0;
- m_currentHeading = 0.0f;
- m_currentPitch = 0.0f;
- m_currentFov = DefaultFov;
- m_lastForward = 0.0f;
- m_lastStrafe = 0.0f;
- m_lastAscent = 0.0f;
- NoClipControllerRequestBus::Handler::BusConnect(GetEntityId());
- AzFramework::InputChannelEventListener::Connect();
- AZ::TickBus::Handler::BusConnect();
- }
- void NoClipControllerComponent::OnDisabled()
- {
- TickBus::Handler::BusDisconnect();
- AzFramework::InputChannelEventListener::Disconnect();
- NoClipControllerRequestBus::Handler::BusDisconnect();
- // Reset the Fov to default.
- Camera::CameraRequestBus::Event(GetEntityId(), &Camera::CameraRequestBus::Events::SetFovRadians, DefaultFov);
- }
- void NoClipControllerComponent::OnTick(float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time)
- {
- static const float normalSpeed = 3.0f;
- static const float sprintSpeed = 10.0f;
- float speedFactor = m_inputStates[CameraKeys::FastMode] ? sprintSpeed : normalSpeed;
- float forward = m_properties.m_moveSpeed * speedFactor * (
- (m_inputStates[CameraKeys::Forward] ? deltaTime : 0.0f) +
- (m_inputStates[CameraKeys::Back] ? -deltaTime : 0.0f));
- float strafe = m_properties.m_panningSpeed * speedFactor * (
- (m_inputStates[CameraKeys::Right] ? deltaTime : 0.0f) +
- (m_inputStates[CameraKeys::Left] ? -deltaTime : 0.0f));
- float ascent = m_properties.m_panningSpeed * speedFactor * (
- (m_inputStates[CameraKeys::Up] ? deltaTime : 0.0f) +
- (m_inputStates[CameraKeys::Down] ? -deltaTime : 0.0f));
- ApplyMomentum(m_lastForward, forward, deltaTime);
- ApplyMomentum(m_lastStrafe, strafe, deltaTime);
- ApplyMomentum(m_lastAscent, ascent, deltaTime);
- AZ::Vector3 worldPosition;
- AZ::TransformBus::EventResult(
- worldPosition, GetEntityId(), &AZ::TransformBus::Events::GetWorldTranslation);
- // The coordinate system is right-handed and Z-up. So heading is a rotation around the Z axis.
- // After that rotation we rotate around the (rotated by heading) X axis for pitch.
- AZ::Quaternion orientation = AZ::Quaternion::CreateRotationZ(m_currentHeading)
- * AZ::Quaternion::CreateRotationX(m_currentPitch);
- AZ::Vector3 position = orientation.TransformVector(AZ::Vector3(strafe, forward, ascent)) + worldPosition;
- AZ::Transform transform = AZ::Transform::CreateFromQuaternionAndTranslation(orientation, position);
- AZ::TransformBus::Event(
- GetEntityId(), &AZ::TransformBus::Events::SetWorldTM, transform);
- Camera::CameraRequestBus::Event(GetEntityId(), &Camera::CameraRequestBus::Events::SetFovRadians, m_currentFov);
- }
- bool NoClipControllerComponent::OnInputChannelEventFiltered(const AzFramework::InputChannel& inputChannel)
- {
- static const auto KeyCount = static_cast<uint32_t>(CameraKeys::Count);
- static const float PixelToDegree = 1.0 / 360.0f;
- static const AzFramework::InputChannelId CameraInputMap[KeyCount] =
- {
- AzFramework::InputDeviceKeyboard::Key::AlphanumericW, // Forward
- AzFramework::InputDeviceKeyboard::Key::AlphanumericS, // Back
- AzFramework::InputDeviceKeyboard::Key::AlphanumericA, // Left
- AzFramework::InputDeviceKeyboard::Key::AlphanumericD, // Right
- AzFramework::InputDeviceKeyboard::Key::AlphanumericQ, // Up
- AzFramework::InputDeviceKeyboard::Key::AlphanumericE, // Down
- AzFramework::InputDeviceKeyboard::Key::ModifierShiftL, // FastMode
- };
- static const AzFramework::InputChannelId CameraGamepadInputMap[KeyCount] =
- {
- AzFramework::InputDeviceGamepad::Button::DU, // Forward
- AzFramework::InputDeviceGamepad::Button::DD, // Back
- AzFramework::InputDeviceGamepad::Button::DL, // Left
- AzFramework::InputDeviceGamepad::Button::DR, // Right
- AzFramework::InputDeviceGamepad::Button::R1, // Up
- AzFramework::InputDeviceGamepad::Button::L1, // Down
- AzFramework::InputDeviceGamepad::Trigger::R2, // FastMode
- };
- uint32_t handledChannels = NoClipControllerChannel_None;
- const AzFramework::InputChannelId& inputChannelId = inputChannel.GetInputChannelId();
- switch (inputChannel.GetState())
- {
- case AzFramework::InputChannel::State::Began:
- case AzFramework::InputChannel::State::Updated: // update the camera rotation
- {
- //Keyboard & Mouse
- if (m_mouseLookEnabled && inputChannelId == AzFramework::InputDeviceMouse::Movement::X)
- {
- // modify yaw angle
- m_currentHeading -= inputChannel.GetValue() * m_properties.m_mouseSensitivityX * PixelToDegree;
- m_currentHeading = NormalizeAngle(m_currentHeading);
- }
- else if (m_mouseLookEnabled && inputChannelId == AzFramework::InputDeviceMouse::Movement::Y)
- {
- // modify pitch angle
- m_currentPitch -= inputChannel.GetValue() * m_properties.m_mouseSensitivityY * PixelToDegree;
- m_currentPitch = AZStd::max(m_currentPitch, -AZ::Constants::HalfPi);
- m_currentPitch = AZStd::min(m_currentPitch, AZ::Constants::HalfPi);
- }
- else if (inputChannelId == AzFramework::InputDeviceMouse::Movement::Z)
- {
- // modify field of view
- m_currentFov = GetClamp(m_currentFov - inputChannel.GetValue() * 0.0005f * m_currentFov, MinFov, MaxFov);
- handledChannels |= NoClipControllerChannel_Fov;
- }
- else if (inputChannelId == AzFramework::InputDeviceMouse::Button::Right)
- {
- m_mouseLookEnabled = true;
- handledChannels |= NoClipControllerChannel_Orientation;
- }
- else
- {
- for (uint32_t i = 0; i < KeyCount; ++i)
- {
- if (inputChannelId == CameraInputMap[i])
- {
- m_inputStates[i] = true;
- if (i != CameraKeys::FastMode)
- {
- handledChannels |= NoClipControllerChannel_Position;
- }
- break;
- }
- }
- }
- // Gamepad
- if (inputChannelId == AzFramework::InputDeviceGamepad::Trigger::L2)
- {
- m_mouseLookEnabled = true;
- handledChannels |= NoClipControllerChannel_Orientation;
- }
- else if (m_mouseLookEnabled)
- {
- if (inputChannelId == AzFramework::InputDeviceGamepad::ThumbStickAxis1D::RX)
- {
- // modify yaw angle
- m_currentHeading -= inputChannel.GetValue() * m_properties.m_mouseSensitivityX * PixelToDegree;
- m_currentHeading = NormalizeAngle(m_currentHeading);
- }
- else if (inputChannelId == AzFramework::InputDeviceGamepad::ThumbStickAxis1D::RY)
- {
- // modify pitch angle
- m_currentPitch += inputChannel.GetValue() * m_properties.m_mouseSensitivityY * PixelToDegree;
- m_currentPitch = AZStd::max(m_currentPitch, -AZ::Constants::HalfPi);
- m_currentPitch = AZStd::min(m_currentPitch, AZ::Constants::HalfPi);
- }
- for (uint32_t i = 0; i < KeyCount; ++i)
- {
- if (inputChannelId == CameraGamepadInputMap[i])
- {
- m_inputStates[i] = true;
- if (i != CameraKeys::FastMode)
- {
- handledChannels |= NoClipControllerChannel_Position;
- }
- break;
- }
- }
- }
- // Touch controls works like two virtual joysticks.
- // The left "joystick" controls forward/backward/left and right movements.
- // The right "joystick" controls the camera heading and pitch.
- // There's no control to move up and down.
- if (inputChannelId == AzFramework::InputDeviceTouch::Touch::Index0 || inputChannelId == AzFramework::InputDeviceTouch::Touch::Index1)
- {
- auto* positionData = inputChannel.GetCustomData<AzFramework::InputChannel::PositionData2D>();
- AZ::Vector2 screenPos = positionData->m_normalizedPosition;
- if (inputChannelId == m_mouseLookTouch.m_channelId)
- {
- // modify yaw angle
- AZ::Vector2 deltaPos = screenPos - m_mouseLookTouch.m_initialPos;
- AZ::Vector2 inputValue = AZ::Vector2(fabsf(deltaPos.GetX()) > deadZone ? 1.0f : 0, fabsf(deltaPos.GetY()) > deadZone ? 1.0f : 0);
- m_currentHeading -= inputValue.GetX() * AZ::GetSign(deltaPos.GetX()) * m_properties.m_touchSensitivity * m_properties.m_mouseSensitivityX * PixelToDegree;
- m_currentHeading = NormalizeAngle(m_currentHeading);
- // modify pitch angle
- m_currentPitch -= inputValue.GetY() * AZ::GetSign(deltaPos.GetY()) * m_properties.m_touchSensitivity * m_properties.m_mouseSensitivityY * PixelToDegree;
- m_currentPitch = AZStd::max(m_currentPitch, -AZ::Constants::HalfPi);
- m_currentPitch = AZStd::min(m_currentPitch, AZ::Constants::HalfPi);
- handledChannels |= NoClipControllerChannel_Orientation;
- }
- else if (inputChannelId == m_movementTouch.m_channelId)
- {
- AZ::Vector2 deltaPos = screenPos - m_movementTouch.m_initialPos;
- m_inputStates[Forward] = deltaPos.GetY() < -deadZone ? true : false;
- m_inputStates[Back] = deltaPos.GetY() > deadZone ? true : false;
- m_inputStates[Left] = deltaPos.GetX() < -deadZone ? true : false;
- m_inputStates[Right] = deltaPos.GetX() > deadZone ? true : false;
- handledChannels |= NoClipControllerChannel_Position;
- }
- else
- {
- bool isMouseLook = (screenPos.GetX() > 0.5);
- auto& touchEvent = isMouseLook ? m_mouseLookTouch : m_movementTouch;
- if (touchEvent.m_channelId == TouchEvent::InvalidTouchChannelId)
- {
- touchEvent.m_channelId = inputChannelId;
- touchEvent.m_initialPos = screenPos;
- }
- if (isMouseLook)
- {
- handledChannels |= NoClipControllerChannel_Orientation;
- }
- else
- {
- handledChannels |= NoClipControllerChannel_Position;
- }
- }
- }
- if (handledChannels && AzFramework::InputChannel::State::Began == inputChannel.GetState())
- {
- CameraControllerNotificationBus::Broadcast(&CameraControllerNotifications::OnCameraMoveBegan, RTTI_GetType(), handledChannels);
- }
- break;
- }
- case AzFramework::InputChannel::State::Ended: // update the released input state
- {
- if (inputChannelId == AzFramework::InputDeviceMouse::Button::Right)
- {
- m_mouseLookEnabled = false;
- handledChannels |= NoClipControllerChannel_Orientation;
- }
- else if (inputChannelId == AzFramework::InputDeviceMouse::Movement::Z)
- {
- handledChannels |= NoClipControllerChannel_Fov;
- }
- else if (inputChannelId == AzFramework::InputDeviceGamepad::Trigger::L2)
- {
- m_mouseLookEnabled = false;
- handledChannels |= NoClipControllerChannel_Orientation;
- // On gamepads, Trigger::L2 also indicates positional movement, see above.
- handledChannels |= NoClipControllerChannel_Position;
- }
- else if (inputChannelId == m_movementTouch.m_channelId)
- {
- m_movementTouch.m_channelId = TouchEvent::InvalidTouchChannelId;
- for (uint32_t i = 0; i < KeyCount; ++i)
- {
- m_inputStates[i] = false;
- if (i != CameraKeys::FastMode)
- {
- handledChannels |= NoClipControllerChannel_Position;
- }
- }
- }
- else if (inputChannelId == m_mouseLookTouch.m_channelId)
- {
- m_mouseLookTouch.m_channelId = TouchEvent::InvalidTouchChannelId;
- handledChannels |= NoClipControllerChannel_Orientation;
- }
- else
- {
- for (uint32_t i = 0; i < KeyCount; ++i)
- {
- if (inputChannelId == CameraInputMap[i] || inputChannelId == CameraGamepadInputMap[i])
- {
- m_inputStates[i] = false;
- if (i != CameraKeys::FastMode)
- {
- handledChannels |= NoClipControllerChannel_Position;
- }
- break;
- }
- }
- }
- if (handledChannels)
- {
- CameraControllerNotificationBus::Broadcast(&CameraControllerNotifications::OnCameraMoveEnded, RTTI_GetType(), handledChannels);
- }
- break;
- }
- default:
- {
- break;
- }
- }
- return false;
- }
- void NoClipControllerComponent::SetMouseSensitivityX(float mouseSensitivityX)
- {
- m_properties.m_mouseSensitivityX = mouseSensitivityX;
- }
- void NoClipControllerComponent::SetMouseSensitivityY(float mouseSensitivityY)
- {
- m_properties.m_mouseSensitivityY = mouseSensitivityY;
- }
- void NoClipControllerComponent::SetMoveSpeed(float moveSpeed)
- {
- m_properties.m_moveSpeed = moveSpeed;
- }
- void NoClipControllerComponent::SetPanningSpeed(float panningSpeed)
- {
- m_properties.m_panningSpeed = panningSpeed;
- }
- void NoClipControllerComponent::SetControllerProperties(const NoClipControllerProperties& properties)
- {
- m_properties = properties;
- }
- void NoClipControllerComponent::SetTouchSensitivity(float touchSensitivity)
- {
- m_properties.m_touchSensitivity = touchSensitivity;
- }
- void NoClipControllerComponent::SetPosition(AZ::Vector3 position)
- {
- AZ::TransformBus::Event(GetEntityId(), &AZ::TransformBus::Events::SetWorldTranslation, position);
- }
- void NoClipControllerComponent::SetHeading(float heading)
- {
- m_currentHeading = heading;
- m_currentHeading = NormalizeAngle(m_currentHeading);
- }
- void NoClipControllerComponent::SetCameraStateForward(float value)
- {
- m_inputStates[CameraKeys::Forward] = value >= -deadZone;
- }
- void NoClipControllerComponent::SetCameraStateBack(float value)
- {
- m_inputStates[Back] = value <= deadZone;
- }
- void NoClipControllerComponent::SetCameraStateLeft(float value)
- {
- m_inputStates[Left] = value < -deadZone;
- }
- void NoClipControllerComponent::SetCameraStateRight(float value)
- {
- m_inputStates[Right] = value > deadZone;
- }
- void NoClipControllerComponent::SetCameraStateUp(float value)
- {
- m_inputStates[Up] = value > deadZone;
- }
- void NoClipControllerComponent::SetCameraStateDown(float value)
- {
- m_inputStates[Down] = value > deadZone;
- }
- void NoClipControllerComponent::SetPitch(float pitch)
- {
- m_currentPitch = pitch;
- m_currentPitch = AZStd::max(m_currentPitch, -AZ::Constants::HalfPi);
- m_currentPitch = AZStd::min(m_currentPitch, AZ::Constants::HalfPi);
- }
- void NoClipControllerComponent::SetFov(float fov)
- {
- m_currentFov = GetClamp(fov, MinFov, MaxFov);
- }
- float NoClipControllerComponent::GetMouseSensitivityX()
- {
- return m_properties.m_mouseSensitivityX;
- }
- float NoClipControllerComponent::GetMouseSensitivityY()
- {
- return m_properties.m_mouseSensitivityY;
- }
- float NoClipControllerComponent::GetMoveSpeed()
- {
- return m_properties.m_moveSpeed;
- }
- float NoClipControllerComponent::GetPanningSpeed()
- {
- return m_properties.m_panningSpeed;
- }
- float NoClipControllerComponent::GetTouchSensitivity()
- {
- return m_properties.m_touchSensitivity;
- }
- NoClipControllerProperties NoClipControllerComponent::GetControllerProperties()
- {
- return m_properties;
- }
- AZ::Vector3 NoClipControllerComponent::GetPosition()
- {
- AZ::Vector3 position;
- AZ::TransformBus::EventResult(position, GetEntityId(), &AZ::TransformBus::Events::GetWorldTranslation);
- return position;
- }
- float NoClipControllerComponent::GetHeading()
- {
- return m_currentHeading;
- }
- float NoClipControllerComponent::GetPitch()
- {
- return m_currentPitch;
- }
- float NoClipControllerComponent::GetFov()
- {
- return m_currentFov;
- }
- } // namespace Debug
- } // namespace AZ
|