CameraInput.cpp 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project
  3. *
  4. * SPDX-License-Identifier: Apache-2.0 OR MIT
  5. *
  6. */
  7. #include "CameraInput.h"
  8. #include <AzCore/Console/IConsole.h>
  9. #include <AzCore/Math/MathUtils.h>
  10. #include <AzCore/Math/Plane.h>
  11. #include <AzCore/std/numeric.h>
  12. #include <AzFramework/Input/Devices/Keyboard/InputDeviceKeyboard.h>
  13. #include <AzFramework/Input/Devices/Mouse/InputDeviceMouse.h>
  14. namespace AzFramework
  15. {
  16. AZ_CVAR(
  17. float,
  18. ed_cameraSystemDefaultPlaneHeight,
  19. 34.0f,
  20. nullptr,
  21. AZ::ConsoleFunctorFlags::Null,
  22. "The default height of the ground plane to do intersection tests against when orbiting");
  23. AZ_CVAR(float, ed_cameraSystemMinOrbitDistance, 10.0f, nullptr, AZ::ConsoleFunctorFlags::Null, "");
  24. AZ_CVAR(float, ed_cameraSystemMaxOrbitDistance, 50.0f, nullptr, AZ::ConsoleFunctorFlags::Null, "");
  25. AZ_CVAR(
  26. AZ::CVarFixedString, ed_cameraSystemTranslateForwardKey, "keyboard_key_alphanumeric_W", nullptr, AZ::ConsoleFunctorFlags::Null, "");
  27. AZ_CVAR(
  28. AZ::CVarFixedString,
  29. ed_cameraSystemTranslateBackwardKey,
  30. "keyboard_key_alphanumeric_S",
  31. nullptr,
  32. AZ::ConsoleFunctorFlags::Null,
  33. "");
  34. AZ_CVAR(
  35. AZ::CVarFixedString, ed_cameraSystemTranslateLeftKey, "keyboard_key_alphanumeric_A", nullptr, AZ::ConsoleFunctorFlags::Null, "");
  36. AZ_CVAR(
  37. AZ::CVarFixedString, ed_cameraSystemTranslateRightKey, "keyboard_key_alphanumeric_D", nullptr, AZ::ConsoleFunctorFlags::Null, "");
  38. AZ_CVAR(AZ::CVarFixedString, ed_cameraSystemTranslateUpKey, "keyboard_key_alphanumeric_E", nullptr, AZ::ConsoleFunctorFlags::Null, "");
  39. AZ_CVAR(
  40. AZ::CVarFixedString, ed_cameraSystemTranslateDownKey, "keyboard_key_alphanumeric_Q", nullptr, AZ::ConsoleFunctorFlags::Null, "");
  41. AZ_CVAR(
  42. AZ::CVarFixedString, ed_cameraSystemTranslateBoostKey, "keyboard_key_modifier_shift_l", nullptr, AZ::ConsoleFunctorFlags::Null, "");
  43. AZ_CVAR(AZ::CVarFixedString, ed_cameraSystemOrbitKey, "keyboard_key_modifier_alt_l", nullptr, AZ::ConsoleFunctorFlags::Null, "");
  44. AZ_CVAR(AZ::CVarFixedString, ed_cameraSystemFreeLookButton, "mouse_button_right", nullptr, AZ::ConsoleFunctorFlags::Null, "");
  45. AZ_CVAR(AZ::CVarFixedString, ed_cameraSystemFreePanButton, "mouse_button_middle", nullptr, AZ::ConsoleFunctorFlags::Null, "");
  46. AZ_CVAR(AZ::CVarFixedString, ed_cameraSystemOrbitLookButton, "mouse_button_left", nullptr, AZ::ConsoleFunctorFlags::Null, "");
  47. AZ_CVAR(AZ::CVarFixedString, ed_cameraSystemOrbitDollyButton, "mouse_button_right", nullptr, AZ::ConsoleFunctorFlags::Null, "");
  48. AZ_CVAR(AZ::CVarFixedString, ed_cameraSystemOrbitPanButton, "mouse_button_middle", nullptr, AZ::ConsoleFunctorFlags::Null, "");
  49. static InputChannelId CameraTranslateForwardId;
  50. static InputChannelId CameraTranslateBackwardId;
  51. static InputChannelId CameraTranslateLeftId;
  52. static InputChannelId CameraTranslateRightId;
  53. static InputChannelId CameraTranslateDownId;
  54. static InputChannelId CameraTranslateUpId;
  55. static InputChannelId CameraTranslateBoostId;
  56. static InputChannelId CameraOrbitId;
  57. // externed elsewhere
  58. InputChannelId CameraFreeLookButton;
  59. InputChannelId CameraFreePanButton;
  60. InputChannelId CameraOrbitLookButton;
  61. InputChannelId CameraOrbitDollyButton;
  62. InputChannelId CameraOrbitPanButton;
  63. void ReloadCameraKeyBindings()
  64. {
  65. const AZ::CVarFixedString& forward = ed_cameraSystemTranslateForwardKey;
  66. CameraTranslateForwardId = InputChannelId(forward.c_str());
  67. const AZ::CVarFixedString& backward = ed_cameraSystemTranslateBackwardKey;
  68. CameraTranslateBackwardId = InputChannelId(backward.c_str());
  69. const AZ::CVarFixedString& left = ed_cameraSystemTranslateLeftKey;
  70. CameraTranslateLeftId = InputChannelId(left.c_str());
  71. const AZ::CVarFixedString& right = ed_cameraSystemTranslateRightKey;
  72. CameraTranslateRightId = InputChannelId(right.c_str());
  73. const AZ::CVarFixedString& down = ed_cameraSystemTranslateDownKey;
  74. CameraTranslateDownId = InputChannelId(down.c_str());
  75. const AZ::CVarFixedString& up = ed_cameraSystemTranslateUpKey;
  76. CameraTranslateUpId = InputChannelId(up.c_str());
  77. const AZ::CVarFixedString& boost = ed_cameraSystemTranslateBoostKey;
  78. CameraTranslateBoostId = InputChannelId(boost.c_str());
  79. const AZ::CVarFixedString& orbit = ed_cameraSystemOrbitKey;
  80. CameraOrbitId = InputChannelId(orbit.c_str());
  81. const AZ::CVarFixedString& freeLook = ed_cameraSystemFreeLookButton;
  82. CameraFreeLookButton = InputChannelId(freeLook.c_str());
  83. const AZ::CVarFixedString& freePan = ed_cameraSystemFreePanButton;
  84. CameraFreePanButton = InputChannelId(freePan.c_str());
  85. const AZ::CVarFixedString& orbitLook = ed_cameraSystemOrbitLookButton;
  86. CameraOrbitLookButton = InputChannelId(orbitLook.c_str());
  87. const AZ::CVarFixedString& orbitDolly = ed_cameraSystemOrbitDollyButton;
  88. CameraOrbitDollyButton = InputChannelId(orbitDolly.c_str());
  89. const AZ::CVarFixedString& orbitPan = ed_cameraSystemOrbitPanButton;
  90. CameraOrbitPanButton = InputChannelId(orbitPan.c_str());
  91. }
  92. static void ReloadCameraKeyBindingsConsole(const AZ::ConsoleCommandContainer&)
  93. {
  94. ReloadCameraKeyBindings();
  95. }
  96. AZ_CONSOLEFREEFUNC(ReloadCameraKeyBindingsConsole, AZ::ConsoleFunctorFlags::Null, "Reload keybindings for the modern camera system");
  97. //! return -1.0f if inverted, 1.0f otherwise
  98. constexpr static float Invert(const bool invert)
  99. {
  100. constexpr float Dir[] = { 1.0f, -1.0f };
  101. return Dir[aznumeric_cast<int>(invert)];
  102. };
  103. // Based on paper by David Eberly - https://www.geometrictools.com/Documentation/EulerAngles.pdf
  104. AZ::Vector3 EulerAngles(const AZ::Matrix3x3& orientation)
  105. {
  106. float x;
  107. float y;
  108. float z;
  109. // 2.4 Factor as RzRyRx
  110. if (orientation.GetElement(2, 0) < 1.0f)
  111. {
  112. if (orientation.GetElement(2, 0) > -1.0f)
  113. {
  114. x = AZStd::atan2(orientation.GetElement(2, 1), orientation.GetElement(2, 2));
  115. y = AZStd::asin(-orientation.GetElement(2, 0));
  116. z = AZStd::atan2(orientation.GetElement(1, 0), orientation.GetElement(0, 0));
  117. }
  118. else
  119. {
  120. x = 0.0f;
  121. y = AZ::Constants::Pi * 0.5f;
  122. z = -AZStd::atan2(-orientation.GetElement(2, 1), orientation.GetElement(1, 1));
  123. }
  124. }
  125. else
  126. {
  127. x = 0.0f;
  128. y = -AZ::Constants::Pi * 0.5f;
  129. z = AZStd::atan2(-orientation.GetElement(1, 2), orientation.GetElement(1, 1));
  130. }
  131. return { x, y, z };
  132. }
  133. void UpdateCameraFromTransform(Camera& camera, const AZ::Transform& transform)
  134. {
  135. const auto eulerAngles = AzFramework::EulerAngles(AZ::Matrix3x3::CreateFromTransform(transform));
  136. camera.m_pitch = eulerAngles.GetX();
  137. camera.m_yaw = eulerAngles.GetZ();
  138. // note: m_lookDist is negative so we must invert it here
  139. camera.m_lookAt = transform.GetTranslation() + (camera.Rotation().GetBasisY() * -camera.m_lookDist);
  140. }
  141. bool CameraSystem::HandleEvents(const InputEvent& event)
  142. {
  143. if (const auto& horizonalMotion = AZStd::get_if<HorizontalMotionEvent>(&event))
  144. {
  145. m_motionDelta.m_x = horizonalMotion->m_delta;
  146. }
  147. else if (const auto& verticalMotion = AZStd::get_if<VerticalMotionEvent>(&event))
  148. {
  149. m_motionDelta.m_y = verticalMotion->m_delta;
  150. }
  151. else if (const auto& scroll = AZStd::get_if<ScrollEvent>(&event))
  152. {
  153. m_scrollDelta = scroll->m_delta;
  154. }
  155. return m_cameras.HandleEvents(event, m_motionDelta, m_scrollDelta);
  156. }
  157. Camera CameraSystem::StepCamera(const Camera& targetCamera, const float deltaTime)
  158. {
  159. const auto nextCamera = m_cameras.StepCamera(targetCamera, m_motionDelta, m_scrollDelta, deltaTime);
  160. m_motionDelta = ScreenVector{ 0, 0 };
  161. m_scrollDelta = 0.0f;
  162. return nextCamera;
  163. }
  164. void Cameras::AddCamera(AZStd::shared_ptr<CameraInput> cameraInput)
  165. {
  166. m_idleCameraInputs.push_back(AZStd::move(cameraInput));
  167. }
  168. bool Cameras::HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, const float scrollDelta)
  169. {
  170. bool handling = false;
  171. for (auto& cameraInput : m_activeCameraInputs)
  172. {
  173. handling = cameraInput->HandleEvents(event, cursorDelta, scrollDelta) || handling;
  174. }
  175. for (auto& cameraInput : m_idleCameraInputs)
  176. {
  177. handling = cameraInput->HandleEvents(event, cursorDelta, scrollDelta) || handling;
  178. }
  179. return handling;
  180. }
  181. Camera Cameras::StepCamera(const Camera& targetCamera, const ScreenVector& cursorDelta, const float scrollDelta, const float deltaTime)
  182. {
  183. for (int i = 0; i < m_idleCameraInputs.size();)
  184. {
  185. auto& cameraInput = m_idleCameraInputs[i];
  186. const bool canBegin = cameraInput->Beginning() &&
  187. AZStd::all_of(m_activeCameraInputs.cbegin(), m_activeCameraInputs.cend(),
  188. [](const auto& input)
  189. {
  190. return !input->Exclusive();
  191. }) &&
  192. (!cameraInput->Exclusive() || (cameraInput->Exclusive() && m_activeCameraInputs.empty()));
  193. if (canBegin)
  194. {
  195. m_activeCameraInputs.push_back(cameraInput);
  196. using AZStd::swap;
  197. swap(m_idleCameraInputs[i], m_idleCameraInputs[m_idleCameraInputs.size() - 1]);
  198. m_idleCameraInputs.pop_back();
  199. }
  200. else
  201. {
  202. i++;
  203. }
  204. }
  205. const Camera nextCamera = AZStd::accumulate(
  206. AZStd::begin(m_activeCameraInputs), AZStd::end(m_activeCameraInputs), targetCamera,
  207. [cursorDelta, scrollDelta, deltaTime](Camera acc, auto& camera)
  208. {
  209. acc = camera->StepCamera(acc, cursorDelta, scrollDelta, deltaTime);
  210. return acc;
  211. });
  212. for (int i = 0; i < m_activeCameraInputs.size();)
  213. {
  214. auto& cameraInput = m_activeCameraInputs[i];
  215. if (cameraInput->Ending())
  216. {
  217. cameraInput->ClearActivation();
  218. m_idleCameraInputs.push_back(cameraInput);
  219. using AZStd::swap;
  220. swap(m_activeCameraInputs[i], m_activeCameraInputs[m_activeCameraInputs.size() - 1]);
  221. m_activeCameraInputs.pop_back();
  222. }
  223. else
  224. {
  225. cameraInput->ContinueActivation();
  226. i++;
  227. }
  228. }
  229. return nextCamera;
  230. }
  231. void Cameras::Reset()
  232. {
  233. for (int i = 0; i < m_activeCameraInputs.size();)
  234. {
  235. m_activeCameraInputs[i]->Reset();
  236. m_idleCameraInputs.push_back(m_activeCameraInputs[i]);
  237. using AZStd::swap;
  238. swap(m_activeCameraInputs[i], m_activeCameraInputs[m_activeCameraInputs.size() - 1]);
  239. m_activeCameraInputs.pop_back();
  240. }
  241. }
  242. void Cameras::Clear()
  243. {
  244. Reset();
  245. AZ_Assert(m_activeCameraInputs.empty(), "Active Camera Inputs is not empty");
  246. m_idleCameraInputs.clear();
  247. }
  248. bool Cameras::Exclusive() const
  249. {
  250. return AZStd::any_of(
  251. m_activeCameraInputs.begin(), m_activeCameraInputs.end(),
  252. [](const auto& cameraInput)
  253. {
  254. return cameraInput->Exclusive();
  255. });
  256. }
  257. RotateCameraInput::RotateCameraInput(const InputChannelId rotateChannelId)
  258. : m_rotateChannelId(rotateChannelId)
  259. {
  260. m_rotateSpeedFn = []() constexpr
  261. {
  262. return 0.005f;
  263. };
  264. m_invertPitchFn = []() constexpr
  265. {
  266. return false;
  267. };
  268. m_invertYawFn = []() constexpr
  269. {
  270. return false;
  271. };
  272. }
  273. bool RotateCameraInput::HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, [[maybe_unused]] const float scrollDelta)
  274. {
  275. const ClickDetector::ClickEvent clickEvent = [&event, this]
  276. {
  277. if (const auto& input = AZStd::get_if<DiscreteInputEvent>(&event))
  278. {
  279. if (input->m_channelId == m_rotateChannelId)
  280. {
  281. if (input->m_state == InputChannel::State::Began)
  282. {
  283. return ClickDetector::ClickEvent::Down;
  284. }
  285. else if (input->m_state == InputChannel::State::Ended)
  286. {
  287. return ClickDetector::ClickEvent::Up;
  288. }
  289. }
  290. }
  291. return ClickDetector::ClickEvent::Nil;
  292. }();
  293. switch (const auto outcome = m_clickDetector.DetectClick(clickEvent, cursorDelta); outcome)
  294. {
  295. case ClickDetector::ClickOutcome::Move:
  296. BeginActivation();
  297. break;
  298. case ClickDetector::ClickOutcome::Release:
  299. EndActivation();
  300. break;
  301. default:
  302. // noop
  303. break;
  304. }
  305. // note - must also check !ending to ensure the mouse up (release) event
  306. // is not consumed and can be propagated to other systems.
  307. // (don't swallow mouse up events)
  308. return !Idle() && !Ending();
  309. }
  310. Camera RotateCameraInput::StepCamera(
  311. const Camera& targetCamera,
  312. const ScreenVector& cursorDelta,
  313. [[maybe_unused]] const float scrollDelta,
  314. [[maybe_unused]] const float deltaTime)
  315. {
  316. Camera nextCamera = targetCamera;
  317. const float rotateSpeed = m_rotateSpeedFn();
  318. nextCamera.m_pitch -= float(cursorDelta.m_y) * rotateSpeed * Invert(m_invertPitchFn());
  319. nextCamera.m_yaw -= float(cursorDelta.m_x) * rotateSpeed * Invert(m_invertYawFn());
  320. const auto clampRotation = [](const float angle)
  321. {
  322. return AZStd::fmod(angle + AZ::Constants::TwoPi, AZ::Constants::TwoPi);
  323. };
  324. nextCamera.m_yaw = clampRotation(nextCamera.m_yaw);
  325. // clamp pitch to be +/-90 degrees
  326. nextCamera.m_pitch = AZ::GetClamp(nextCamera.m_pitch, -AZ::Constants::HalfPi, AZ::Constants::HalfPi);
  327. return nextCamera;
  328. }
  329. PanCameraInput::PanCameraInput(const InputChannelId panChannelId, PanAxesFn panAxesFn)
  330. : m_panAxesFn(AZStd::move(panAxesFn))
  331. , m_panChannelId(panChannelId)
  332. {
  333. m_panSpeedFn = []() constexpr
  334. {
  335. return 0.01f;
  336. };
  337. m_invertPanXFn = []() constexpr
  338. {
  339. return true;
  340. };
  341. m_invertPanYFn = []() constexpr
  342. {
  343. return true;
  344. };
  345. }
  346. bool PanCameraInput::HandleEvents(
  347. const InputEvent& event, [[maybe_unused]] const ScreenVector& cursorDelta, [[maybe_unused]] const float scrollDelta)
  348. {
  349. if (const auto& input = AZStd::get_if<DiscreteInputEvent>(&event))
  350. {
  351. if (input->m_channelId == m_panChannelId)
  352. {
  353. if (input->m_state == InputChannel::State::Began)
  354. {
  355. BeginActivation();
  356. }
  357. else if (input->m_state == InputChannel::State::Ended)
  358. {
  359. EndActivation();
  360. }
  361. }
  362. }
  363. return !Idle();
  364. }
  365. Camera PanCameraInput::StepCamera(
  366. const Camera& targetCamera,
  367. const ScreenVector& cursorDelta,
  368. [[maybe_unused]] const float scrollDelta,
  369. [[maybe_unused]] const float deltaTime)
  370. {
  371. Camera nextCamera = targetCamera;
  372. const auto panAxes = m_panAxesFn(nextCamera);
  373. const float panSpeed = m_panSpeedFn();
  374. const auto deltaPanX = float(cursorDelta.m_x) * panAxes.m_horizontalAxis * panSpeed;
  375. const auto deltaPanY = float(cursorDelta.m_y) * panAxes.m_verticalAxis * panSpeed;
  376. nextCamera.m_lookAt += deltaPanX * Invert(m_invertPanXFn());
  377. nextCamera.m_lookAt += deltaPanY * -Invert(m_invertPanYFn());
  378. return nextCamera;
  379. }
  380. TranslateCameraInput::TranslationType TranslateCameraInput::TranslationFromKey(InputChannelId channelId)
  381. {
  382. if (channelId == CameraTranslateForwardId)
  383. {
  384. return TranslationType::Forward;
  385. }
  386. if (channelId == CameraTranslateBackwardId)
  387. {
  388. return TranslationType::Backward;
  389. }
  390. if (channelId == CameraTranslateLeftId)
  391. {
  392. return TranslationType::Left;
  393. }
  394. if (channelId == CameraTranslateRightId)
  395. {
  396. return TranslationType::Right;
  397. }
  398. if (channelId == CameraTranslateDownId)
  399. {
  400. return TranslationType::Down;
  401. }
  402. if (channelId == CameraTranslateUpId)
  403. {
  404. return TranslationType::Up;
  405. }
  406. return TranslationType::Nil;
  407. }
  408. TranslateCameraInput::TranslateCameraInput(TranslationAxesFn translationAxesFn)
  409. : m_translationAxesFn(AZStd::move(translationAxesFn))
  410. {
  411. m_translateSpeedFn = []() constexpr
  412. {
  413. return 10.0f;
  414. };
  415. m_boostMultiplierFn = []() constexpr
  416. {
  417. return 3.0f;
  418. };
  419. }
  420. bool TranslateCameraInput::HandleEvents(
  421. const InputEvent& event, [[maybe_unused]] const ScreenVector& cursorDelta, [[maybe_unused]] float scrollDelta)
  422. {
  423. if (const auto& input = AZStd::get_if<DiscreteInputEvent>(&event))
  424. {
  425. if (input->m_state == InputChannel::State::Began)
  426. {
  427. m_translation |= TranslationFromKey(input->m_channelId);
  428. if (m_translation != TranslationType::Nil)
  429. {
  430. BeginActivation();
  431. }
  432. if (input->m_channelId == CameraTranslateBoostId)
  433. {
  434. m_boost = true;
  435. }
  436. }
  437. // ensure we don't process end events in the idle state
  438. else if (input->m_state == InputChannel::State::Ended && !Idle())
  439. {
  440. m_translation &= ~(TranslationFromKey(input->m_channelId));
  441. if (m_translation == TranslationType::Nil)
  442. {
  443. EndActivation();
  444. }
  445. if (input->m_channelId == CameraTranslateBoostId)
  446. {
  447. m_boost = false;
  448. }
  449. }
  450. }
  451. return !Idle();
  452. }
  453. Camera TranslateCameraInput::StepCamera(
  454. const Camera& targetCamera,
  455. [[maybe_unused]] const ScreenVector& cursorDelta,
  456. [[maybe_unused]] const float scrollDelta,
  457. const float deltaTime)
  458. {
  459. Camera nextCamera = targetCamera;
  460. const auto translationBasis = m_translationAxesFn(nextCamera);
  461. const auto axisX = translationBasis.GetBasisX();
  462. const auto axisY = translationBasis.GetBasisY();
  463. const auto axisZ = translationBasis.GetBasisZ();
  464. const float speed = [boost = m_boost, &translateSpeedFn = m_translateSpeedFn, &boostMultiplierFn = m_boostMultiplierFn]()
  465. {
  466. return translateSpeedFn() * (boost ? boostMultiplierFn() : 1.0f);
  467. }();
  468. if ((m_translation & TranslationType::Forward) == TranslationType::Forward)
  469. {
  470. nextCamera.m_lookAt += axisY * speed * deltaTime;
  471. }
  472. if ((m_translation & TranslationType::Backward) == TranslationType::Backward)
  473. {
  474. nextCamera.m_lookAt -= axisY * speed * deltaTime;
  475. }
  476. if ((m_translation & TranslationType::Left) == TranslationType::Left)
  477. {
  478. nextCamera.m_lookAt -= axisX * speed * deltaTime;
  479. }
  480. if ((m_translation & TranslationType::Right) == TranslationType::Right)
  481. {
  482. nextCamera.m_lookAt += axisX * speed * deltaTime;
  483. }
  484. if ((m_translation & TranslationType::Up) == TranslationType::Up)
  485. {
  486. nextCamera.m_lookAt += axisZ * speed * deltaTime;
  487. }
  488. if ((m_translation & TranslationType::Down) == TranslationType::Down)
  489. {
  490. nextCamera.m_lookAt -= axisZ * speed * deltaTime;
  491. }
  492. if (Ending())
  493. {
  494. m_translation = TranslationType::Nil;
  495. }
  496. return nextCamera;
  497. }
  498. void TranslateCameraInput::ResetImpl()
  499. {
  500. m_translation = TranslationType::Nil;
  501. m_boost = false;
  502. }
  503. bool OrbitCameraInput::HandleEvents(const InputEvent& event, const ScreenVector& cursorDelta, const float scrollDelta)
  504. {
  505. if (const auto* input = AZStd::get_if<DiscreteInputEvent>(&event))
  506. {
  507. if (input->m_channelId == CameraOrbitId)
  508. {
  509. if (input->m_state == InputChannel::State::Began)
  510. {
  511. BeginActivation();
  512. }
  513. else if (input->m_state == InputChannel::State::Ended)
  514. {
  515. EndActivation();
  516. }
  517. }
  518. }
  519. if (Active())
  520. {
  521. return m_orbitCameras.HandleEvents(event, cursorDelta, scrollDelta);
  522. }
  523. return !Idle();
  524. }
  525. Camera OrbitCameraInput::StepCamera(
  526. const Camera& targetCamera, const ScreenVector& cursorDelta, const float scrollDelta, const float deltaTime)
  527. {
  528. Camera nextCamera = targetCamera;
  529. if (Beginning())
  530. {
  531. const auto hasLookAt = [&nextCamera, &targetCamera, &lookAtFn = m_lookAtFn]
  532. {
  533. if (lookAtFn)
  534. {
  535. // pass through the camera's position and look vector for use in the lookAt function
  536. if (const auto lookAt = lookAtFn(targetCamera.Translation(), targetCamera.Rotation().GetBasisY()))
  537. {
  538. auto transform = AZ::Transform::CreateLookAt(targetCamera.m_lookAt, *lookAt);
  539. nextCamera.m_lookDist = -lookAt->GetDistance(targetCamera.m_lookAt);
  540. UpdateCameraFromTransform(nextCamera, transform);
  541. return true;
  542. }
  543. }
  544. return false;
  545. }();
  546. if (!hasLookAt)
  547. {
  548. float hit_distance = 0.0f;
  549. AZ::Plane::CreateFromNormalAndPoint(AZ::Vector3::CreateAxisZ(), AZ::Vector3::CreateAxisZ(ed_cameraSystemDefaultPlaneHeight))
  550. .CastRay(targetCamera.Translation(), targetCamera.Rotation().GetBasisY(), hit_distance);
  551. if (hit_distance > 0.0f)
  552. {
  553. hit_distance = AZStd::min<float>(hit_distance, ed_cameraSystemMaxOrbitDistance);
  554. nextCamera.m_lookDist = -hit_distance;
  555. nextCamera.m_lookAt = targetCamera.Translation() + targetCamera.Rotation().GetBasisY() * hit_distance;
  556. }
  557. else
  558. {
  559. nextCamera.m_lookDist = -ed_cameraSystemMinOrbitDistance;
  560. nextCamera.m_lookAt =
  561. targetCamera.Translation() + targetCamera.Rotation().GetBasisY() * ed_cameraSystemMinOrbitDistance;
  562. }
  563. }
  564. }
  565. if (Active())
  566. {
  567. nextCamera = m_orbitCameras.StepCamera(nextCamera, cursorDelta, scrollDelta, deltaTime);
  568. }
  569. if (Ending())
  570. {
  571. m_orbitCameras.Reset();
  572. nextCamera.m_lookAt = nextCamera.Translation();
  573. nextCamera.m_lookDist = 0.0f;
  574. }
  575. return nextCamera;
  576. }
  577. OrbitDollyScrollCameraInput::OrbitDollyScrollCameraInput()
  578. {
  579. m_scrollSpeedFn = []() constexpr
  580. {
  581. return 0.03f;
  582. };
  583. }
  584. bool OrbitDollyScrollCameraInput::HandleEvents(
  585. const InputEvent& event, [[maybe_unused]] const ScreenVector& cursorDelta, [[maybe_unused]] const float scrollDelta)
  586. {
  587. if (const auto* scroll = AZStd::get_if<ScrollEvent>(&event))
  588. {
  589. BeginActivation();
  590. }
  591. return !Idle();
  592. }
  593. Camera OrbitDollyScrollCameraInput::StepCamera(
  594. const Camera& targetCamera,
  595. [[maybe_unused]] const ScreenVector& cursorDelta,
  596. const float scrollDelta,
  597. [[maybe_unused]] const float deltaTime)
  598. {
  599. Camera nextCamera = targetCamera;
  600. nextCamera.m_lookDist = AZ::GetMin(nextCamera.m_lookDist + scrollDelta * m_scrollSpeedFn(), 0.0f);
  601. EndActivation();
  602. return nextCamera;
  603. }
  604. OrbitDollyCursorMoveCameraInput::OrbitDollyCursorMoveCameraInput(const InputChannelId dollyChannelId)
  605. : m_dollyChannelId(dollyChannelId)
  606. {
  607. m_cursorSpeedFn = []() constexpr
  608. {
  609. return 0.01f;
  610. };
  611. }
  612. bool OrbitDollyCursorMoveCameraInput::HandleEvents(
  613. const InputEvent& event, [[maybe_unused]] const ScreenVector& cursorDelta, [[maybe_unused]] const float scrollDelta)
  614. {
  615. if (const auto& input = AZStd::get_if<DiscreteInputEvent>(&event))
  616. {
  617. if (input->m_channelId == m_dollyChannelId)
  618. {
  619. if (input->m_state == InputChannel::State::Began)
  620. {
  621. BeginActivation();
  622. }
  623. else if (input->m_state == InputChannel::State::Ended)
  624. {
  625. EndActivation();
  626. }
  627. }
  628. }
  629. return !Idle();
  630. }
  631. Camera OrbitDollyCursorMoveCameraInput::StepCamera(
  632. const Camera& targetCamera,
  633. const ScreenVector& cursorDelta,
  634. [[maybe_unused]] const float scrollDelta,
  635. [[maybe_unused]] const float deltaTime)
  636. {
  637. Camera nextCamera = targetCamera;
  638. nextCamera.m_lookDist = AZ::GetMin(nextCamera.m_lookDist + float(cursorDelta.m_y) * m_cursorSpeedFn(), 0.0f);
  639. return nextCamera;
  640. }
  641. ScrollTranslationCameraInput::ScrollTranslationCameraInput()
  642. {
  643. m_scrollSpeedFn = []() constexpr
  644. {
  645. return 0.02f;
  646. };
  647. }
  648. bool ScrollTranslationCameraInput::HandleEvents(
  649. const InputEvent& event, [[maybe_unused]] const ScreenVector& cursorDelta, [[maybe_unused]] const float scrollDelta)
  650. {
  651. if (const auto* scroll = AZStd::get_if<ScrollEvent>(&event))
  652. {
  653. BeginActivation();
  654. }
  655. return !Idle();
  656. }
  657. Camera ScrollTranslationCameraInput::StepCamera(
  658. const Camera& targetCamera,
  659. [[maybe_unused]] const ScreenVector& cursorDelta,
  660. const float scrollDelta,
  661. [[maybe_unused]] const float deltaTime)
  662. {
  663. Camera nextCamera = targetCamera;
  664. const auto translation_basis = LookTranslation(nextCamera);
  665. const auto axisY = translation_basis.GetBasisY();
  666. nextCamera.m_lookAt += axisY * scrollDelta * m_scrollSpeedFn();
  667. EndActivation();
  668. return nextCamera;
  669. }
  670. Camera SmoothCamera(const Camera& currentCamera, const Camera& targetCamera, const CameraProps& cameraProps, const float deltaTime)
  671. {
  672. const auto clamp_rotation = [](const float angle)
  673. {
  674. return AZStd::fmod(angle + AZ::Constants::TwoPi, AZ::Constants::TwoPi);
  675. };
  676. // keep yaw in 0 - 360 range
  677. float targetYaw = clamp_rotation(targetCamera.m_yaw);
  678. const float currentYaw = clamp_rotation(currentCamera.m_yaw);
  679. // return the sign of the float input (-1, 0, 1)
  680. const auto sign = [](const float value)
  681. {
  682. return aznumeric_cast<float>((0.0f < value) - (value < 0.0f));
  683. };
  684. // ensure smooth transition when moving across 0 - 360 boundary
  685. const float yawDelta = targetYaw - currentYaw;
  686. if (AZStd::abs(yawDelta) >= AZ::Constants::Pi)
  687. {
  688. targetYaw -= AZ::Constants::TwoPi * sign(yawDelta);
  689. }
  690. Camera camera;
  691. // note: the math for the lerp smoothing implementation for camera rotation and translation was inspired by this excellent
  692. // article by Scott Lembcke: https://www.gamasutra.com/blogs/ScottLembcke/20180404/316046/Improved_Lerp_Smoothing.php
  693. const float lookRate = AZStd::exp2(cameraProps.m_rotateSmoothnessFn());
  694. const float lookT = AZStd::exp2(-lookRate * deltaTime);
  695. camera.m_pitch = AZ::Lerp(targetCamera.m_pitch, currentCamera.m_pitch, lookT);
  696. camera.m_yaw = AZ::Lerp(targetYaw, currentYaw, lookT);
  697. const float moveRate = AZStd::exp2(cameraProps.m_translateSmoothnessFn());
  698. const float moveT = AZStd::exp2(-moveRate * deltaTime);
  699. camera.m_lookDist = AZ::Lerp(targetCamera.m_lookDist, currentCamera.m_lookDist, moveT);
  700. camera.m_lookAt = targetCamera.m_lookAt.Lerp(currentCamera.m_lookAt, moveT);
  701. return camera;
  702. }
  703. InputEvent BuildInputEvent(const InputChannel& inputChannel)
  704. {
  705. const auto& inputChannelId = inputChannel.GetInputChannelId();
  706. const auto& inputDeviceId = inputChannel.GetInputDevice().GetInputDeviceId();
  707. const bool wasMouseButton = AZStd::any_of(
  708. InputDeviceMouse::Button::All.begin(), InputDeviceMouse::Button::All.end(),
  709. [inputChannelId](const auto& button)
  710. {
  711. return button == inputChannelId;
  712. });
  713. if (inputChannelId == InputDeviceMouse::Movement::X)
  714. {
  715. return HorizontalMotionEvent{ aznumeric_cast<int>(inputChannel.GetValue()) };
  716. }
  717. else if (inputChannelId == InputDeviceMouse::Movement::Y)
  718. {
  719. return VerticalMotionEvent{ aznumeric_cast<int>(inputChannel.GetValue()) };
  720. }
  721. else if (inputChannelId == InputDeviceMouse::Movement::Z)
  722. {
  723. return ScrollEvent{ inputChannel.GetValue() };
  724. }
  725. else if (wasMouseButton || InputDeviceKeyboard::IsKeyboardDevice(inputDeviceId))
  726. {
  727. return DiscreteInputEvent{ inputChannelId, inputChannel.GetState() };
  728. }
  729. return AZStd::monostate{};
  730. }
  731. } // namespace AzFramework