EditorModularViewportCameraComposer.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include <EditorModularViewportCameraComposer.h>
  9. #include <Atom/RPI.Public/ViewportContextBus.h>
  10. #include <AtomToolsFramework/Viewport/ModularViewportCameraControllerRequestBus.h>
  11. #include <AzCore/Component/TransformBus.h>
  12. #include <AzCore/std/smart_ptr/make_shared.h>
  13. #include <AzFramework/Render/IntersectorInterface.h>
  14. #include <AzToolsFramework/Viewport/ViewportMessages.h>
  15. #include <AzToolsFramework/ViewportSelection/EditorSelectionUtil.h>
  16. #include <AzToolsFramework/ViewportSelection/EditorTransformComponentSelectionRequestBus.h>
  17. #include <EditorViewportSettings.h>
  18. AZ_CVAR(
  19. bool,
  20. ed_cameraPinDefaultOrbit,
  21. true,
  22. nullptr,
  23. AZ::ConsoleFunctorFlags::Null,
  24. "Sets whether the default orbit point moves with the camera or not");
  25. AZ_CVAR(
  26. bool,
  27. ed_cameraDefaultOrbitAxesOrtho,
  28. true,
  29. nullptr,
  30. AZ::ConsoleFunctorFlags::Null,
  31. "Sets whether to draw the default orbit point as orthographic or not");
  32. AZ_CVAR(
  33. float,
  34. ed_cameraDefaultOrbitFadeDuration,
  35. 0.5f,
  36. nullptr,
  37. AZ::ConsoleFunctorFlags::Null,
  38. "Sets how long the default orbit point should take to appear and disappear");
  39. AZ_CVAR(
  40. float,
  41. ed_cameraPivotFadedOpacity,
  42. 0.5f,
  43. nullptr,
  44. AZ::ConsoleFunctorFlags::Null,
  45. "How faded should the camera pivot appear when it is set but no active rotation is happening");
  46. AZ_CVAR(float, ed_cameraPivotSize, 0.05f, nullptr, AZ::ConsoleFunctorFlags::Null, "Specify the size the camera pivot point should be");
  47. AZ_CVAR(
  48. AZ::Color,
  49. ed_cameraPivotColor,
  50. AZ::Color::CreateFromRgba(255, 0, 0, 255),
  51. nullptr,
  52. AZ::ConsoleFunctorFlags::Null,
  53. "Specify the color the camera pivot point should be");
  54. namespace SandboxEditor
  55. {
  56. static AzFramework::TranslateCameraInputChannelIds BuildTranslateCameraInputChannelIds()
  57. {
  58. AzFramework::TranslateCameraInputChannelIds translateCameraInputChannelIds;
  59. translateCameraInputChannelIds.m_leftChannelId = SandboxEditor::CameraTranslateLeftChannelId();
  60. translateCameraInputChannelIds.m_rightChannelId = SandboxEditor::CameraTranslateRightChannelId();
  61. translateCameraInputChannelIds.m_forwardChannelId = SandboxEditor::CameraTranslateForwardChannelId();
  62. translateCameraInputChannelIds.m_backwardChannelId = SandboxEditor::CameraTranslateBackwardChannelId();
  63. translateCameraInputChannelIds.m_upChannelId = SandboxEditor::CameraTranslateUpChannelId();
  64. translateCameraInputChannelIds.m_downChannelId = SandboxEditor::CameraTranslateDownChannelId();
  65. translateCameraInputChannelIds.m_boostChannelId = SandboxEditor::CameraTranslateBoostChannelId();
  66. return translateCameraInputChannelIds;
  67. }
  68. EditorModularViewportCameraComposer::EditorModularViewportCameraComposer(const AzFramework::ViewportId viewportId)
  69. : m_viewportId(viewportId)
  70. {
  71. EditorModularViewportCameraComposerNotificationBus::Handler::BusConnect(viewportId);
  72. Camera::EditorCameraNotificationBus::Handler::BusConnect();
  73. }
  74. EditorModularViewportCameraComposer::~EditorModularViewportCameraComposer()
  75. {
  76. Camera::EditorCameraNotificationBus::Handler::BusDisconnect();
  77. EditorModularViewportCameraComposerNotificationBus::Handler::BusDisconnect();
  78. }
  79. AZStd::shared_ptr<AtomToolsFramework::ModularViewportCameraController> EditorModularViewportCameraComposer::
  80. CreateModularViewportCameraController()
  81. {
  82. SetupCameras();
  83. auto controller = AZStd::make_shared<AtomToolsFramework::ModularViewportCameraController>();
  84. controller->SetCameraViewportContextBuilderCallback(
  85. [viewportId = m_viewportId](AZStd::unique_ptr<AtomToolsFramework::ModularCameraViewportContext>& cameraViewportContext)
  86. {
  87. cameraViewportContext = AZStd::make_unique<AtomToolsFramework::ModularCameraViewportContextImpl>(viewportId);
  88. });
  89. controller->SetCameraPriorityBuilderCallback(
  90. [](AtomToolsFramework::CameraControllerPriorityFn& cameraControllerPriorityFn)
  91. {
  92. cameraControllerPriorityFn = AtomToolsFramework::DefaultCameraControllerPriority;
  93. });
  94. controller->SetCameraPropsBuilderCallback(
  95. [](AzFramework::CameraProps& cameraProps)
  96. {
  97. cameraProps.m_rotateSmoothnessFn = []
  98. {
  99. return SandboxEditor::CameraRotateSmoothness();
  100. };
  101. cameraProps.m_translateSmoothnessFn = []
  102. {
  103. return SandboxEditor::CameraTranslateSmoothness();
  104. };
  105. cameraProps.m_rotateSmoothingEnabledFn = []
  106. {
  107. return SandboxEditor::CameraRotateSmoothingEnabled();
  108. };
  109. cameraProps.m_translateSmoothingEnabledFn = []
  110. {
  111. return SandboxEditor::CameraTranslateSmoothingEnabled();
  112. };
  113. });
  114. controller->SetCameraListBuilderCallback(
  115. [this](AzFramework::Cameras& cameras)
  116. {
  117. cameras.AddCamera(m_firstPersonRotateCamera);
  118. cameras.AddCamera(m_firstPersonPanCamera);
  119. cameras.AddCamera(m_firstPersonTranslateCamera);
  120. cameras.AddCamera(m_firstPersonScrollCamera);
  121. cameras.AddCamera(m_firstPersonFocusCamera);
  122. cameras.AddCamera(m_orbitCamera);
  123. });
  124. return controller;
  125. }
  126. void EditorModularViewportCameraComposer::SetupCameras()
  127. {
  128. const auto hideCursor = [viewportId = m_viewportId]
  129. {
  130. if (SandboxEditor::CameraCaptureCursorForLook())
  131. {
  132. AzToolsFramework::ViewportInteraction::ViewportMouseCursorRequestBus::Event(
  133. viewportId, &AzToolsFramework::ViewportInteraction::ViewportMouseCursorRequestBus::Events::BeginCursorCapture);
  134. }
  135. };
  136. const auto showCursor = [viewportId = m_viewportId]
  137. {
  138. if (SandboxEditor::CameraCaptureCursorForLook())
  139. {
  140. AzToolsFramework::ViewportInteraction::ViewportMouseCursorRequestBus::Event(
  141. viewportId, &AzToolsFramework::ViewportInteraction::ViewportMouseCursorRequestBus::Events::EndCursorCapture);
  142. }
  143. };
  144. const auto trackingTransform = [viewportId = m_viewportId]
  145. {
  146. bool tracking = false;
  147. AtomToolsFramework::ModularViewportCameraControllerRequestBus::EventResult(
  148. tracking, viewportId, &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::IsTrackingTransform);
  149. return tracking;
  150. };
  151. m_firstPersonRotateCamera = AZStd::make_shared<AzFramework::RotateCameraInput>(SandboxEditor::CameraFreeLookChannelId());
  152. m_firstPersonRotateCamera->m_rotateSpeedFn = []
  153. {
  154. return SandboxEditor::CameraRotateSpeed();
  155. };
  156. m_firstPersonRotateCamera->m_constrainPitch = [trackingTransform]
  157. {
  158. return !trackingTransform();
  159. };
  160. // default behavior is to hide the cursor but this can be disabled (useful for remote desktop)
  161. // note: See CaptureCursorLook in the Settings Registry
  162. m_firstPersonRotateCamera->SetActivationBeganFn(hideCursor);
  163. m_firstPersonRotateCamera->SetActivationEndedFn(showCursor);
  164. m_firstPersonPanCamera = AZStd::make_shared<AzFramework::PanCameraInput>(
  165. SandboxEditor::CameraFreePanChannelId(), AzFramework::LookPan, AzFramework::TranslatePivotLook);
  166. m_firstPersonPanCamera->m_panSpeedFn = []
  167. {
  168. return SandboxEditor::CameraPanSpeedScaled();
  169. };
  170. m_firstPersonPanCamera->m_invertPanXFn = []
  171. {
  172. return SandboxEditor::CameraPanInvertedX();
  173. };
  174. m_firstPersonPanCamera->m_invertPanYFn = []
  175. {
  176. return SandboxEditor::CameraPanInvertedY();
  177. };
  178. const auto translateCameraInputChannelIds = BuildTranslateCameraInputChannelIds();
  179. m_firstPersonTranslateCamera = AZStd::make_shared<AzFramework::TranslateCameraInput>(
  180. translateCameraInputChannelIds, AzFramework::LookTranslation, AzFramework::TranslatePivotLook);
  181. m_firstPersonTranslateCamera->m_translateSpeedFn = []
  182. {
  183. return SandboxEditor::CameraTranslateSpeedScaled();
  184. };
  185. m_firstPersonTranslateCamera->m_boostMultiplierFn = []
  186. {
  187. return SandboxEditor::CameraBoostMultiplier();
  188. };
  189. m_firstPersonScrollCamera = AZStd::make_shared<AzFramework::LookScrollTranslationCameraInput>();
  190. m_firstPersonScrollCamera->m_scrollSpeedFn = []
  191. {
  192. return SandboxEditor::CameraScrollSpeedScaled();
  193. };
  194. const auto focusPivotFn = []() -> AZStd::optional<AZ::Vector3>
  195. {
  196. // use the manipulator transform as the pivot point
  197. AZStd::optional<AZ::Transform> entityPivot;
  198. AzToolsFramework::EditorTransformComponentSelectionRequestBus::EventResult(
  199. entityPivot, AzToolsFramework::GetEntityContextId(),
  200. &AzToolsFramework::EditorTransformComponentSelectionRequestBus::Events::GetManipulatorTransform);
  201. if (entityPivot.has_value())
  202. {
  203. return entityPivot->GetTranslation();
  204. }
  205. return AZStd::nullopt;
  206. };
  207. m_firstPersonFocusCamera =
  208. AZStd::make_shared<AzFramework::FocusCameraInput>(SandboxEditor::CameraFocusChannelId(), AzFramework::FocusLook);
  209. m_firstPersonFocusCamera->SetPivotFn(focusPivotFn);
  210. m_orbitCamera = AZStd::make_shared<AzFramework::OrbitCameraInput>(SandboxEditor::CameraOrbitChannelId());
  211. m_orbitCamera->SetPivotFn(
  212. [this]([[maybe_unused]] const AZ::Vector3& position, [[maybe_unused]] const AZ::Vector3& direction)
  213. {
  214. return m_pivot.value_or(AZ::Vector3::CreateZero());
  215. });
  216. m_orbitCamera->SetActivationBeganFn(
  217. [this]
  218. {
  219. AZ::TickBus::Handler::BusConnect();
  220. AzFramework::ViewportDebugDisplayEventBus::Handler::BusConnect(AzToolsFramework::GetEntityContextId());
  221. // pivot should be displayed but not be 'active' (full when rotation behavior is happening)
  222. m_pivotDisplayState = PivotDisplayState::Faded;
  223. });
  224. m_orbitCamera->SetActivationEndedFn(
  225. [this]
  226. {
  227. // when the orbit camera ends, ensure that the internal camera returns to a look state
  228. // (internal offset value for camera is zero)
  229. AtomToolsFramework::ModularViewportCameraControllerRequestBus::Event(
  230. m_viewportId,
  231. &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::LookFromOrbit);
  232. // when the orbit behavior ends the pivot point should fade out and no longer display
  233. m_pivotDisplayState = PivotDisplayState::Hidden;
  234. });
  235. m_orbitRotateCamera = AZStd::make_shared<AzFramework::RotateCameraInput>(SandboxEditor::CameraOrbitLookChannelId());
  236. m_orbitRotateCamera->m_rotateSpeedFn = []
  237. {
  238. return SandboxEditor::CameraRotateSpeed();
  239. };
  240. m_orbitRotateCamera->m_invertYawFn = []
  241. {
  242. return SandboxEditor::CameraOrbitYawRotationInverted();
  243. };
  244. m_orbitRotateCamera->m_constrainPitch = [trackingTransform]
  245. {
  246. return !trackingTransform();
  247. };
  248. m_orbitRotateCamera->SetInitiateRotateFn(
  249. [this]
  250. {
  251. AZStd::optional<AzFramework::ScreenPoint> screenPoint;
  252. AzToolsFramework::ViewportInteraction::ViewportMouseCursorRequestBus::EventResult(
  253. screenPoint, m_viewportId,
  254. &AzToolsFramework::ViewportInteraction::ViewportMouseCursorRequestBus::Events::MousePosition);
  255. if (screenPoint.has_value())
  256. {
  257. const auto [origin, direction] =
  258. AzToolsFramework::ViewportInteraction::ViewportScreenToWorldRay(m_viewportId, screenPoint.value());
  259. AzToolsFramework::EntityIdList visibleEntityIds;
  260. AzToolsFramework::ViewportInteraction::EditorEntityViewportInteractionRequestBus::Event(
  261. m_viewportId,
  262. &AzToolsFramework::ViewportInteraction::EditorEntityViewportInteractionRequestBus::Events::FindVisibleEntities,
  263. visibleEntityIds);
  264. bool pickedEntity = false;
  265. float closestDistance = AZStd::numeric_limits<float>::max();
  266. for (const auto& entityId : visibleEntityIds)
  267. {
  268. float distance;
  269. if (AzToolsFramework::PickEntity(entityId, origin, direction, distance, m_viewportId))
  270. {
  271. pickedEntity = true;
  272. closestDistance = AZStd::min(distance, closestDistance);
  273. }
  274. }
  275. const float distance = pickedEntity ? closestDistance : AzToolsFramework::GetDefaultEntityPlacementDistance();
  276. m_pivot = origin + direction * distance;
  277. // ensure we immediately set the camera pivot to ensure no interpolation of current to target occurs
  278. AtomToolsFramework::ModularViewportCameraControllerRequestBus::Event(
  279. m_viewportId,
  280. &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::SetCameraPivotDetachedImmediate,
  281. m_pivot.value());
  282. }
  283. });
  284. m_orbitRotateCamera->SetActivationBeganFn(
  285. [this]
  286. {
  287. m_pivotDisplayState = PivotDisplayState::Full;
  288. });
  289. m_orbitRotateCamera->SetActivationEndedFn(
  290. [this]
  291. {
  292. m_pivotDisplayState = PivotDisplayState::Faded;
  293. });
  294. m_orbitTranslateCamera = AZStd::make_shared<AzFramework::TranslateCameraInput>(
  295. translateCameraInputChannelIds, AzFramework::LookTranslation, AzFramework::TranslateOffsetOrbit);
  296. m_orbitTranslateCamera->m_translateSpeedFn = []
  297. {
  298. return SandboxEditor::CameraTranslateSpeedScaled();
  299. };
  300. m_orbitTranslateCamera->m_boostMultiplierFn = []
  301. {
  302. return SandboxEditor::CameraBoostMultiplier();
  303. };
  304. m_orbitScrollDollyCamera = AZStd::make_shared<AzFramework::OrbitScrollDollyCameraInput>();
  305. m_orbitScrollDollyCamera->m_scrollSpeedFn = []
  306. {
  307. return SandboxEditor::CameraScrollSpeedScaled();
  308. };
  309. m_orbitMotionDollyCamera = AZStd::make_shared<AzFramework::OrbitMotionDollyCameraInput>(SandboxEditor::CameraOrbitDollyChannelId());
  310. m_orbitMotionDollyCamera->m_motionSpeedFn = []
  311. {
  312. return SandboxEditor::CameraDollyMotionSpeedScaled();
  313. };
  314. m_orbitPanCamera = AZStd::make_shared<AzFramework::PanCameraInput>(
  315. SandboxEditor::CameraOrbitPanChannelId(), AzFramework::LookPan, AzFramework::TranslateOffsetOrbit);
  316. m_orbitPanCamera->m_panSpeedFn = []
  317. {
  318. return SandboxEditor::CameraPanSpeedScaled();
  319. };
  320. m_orbitPanCamera->m_invertPanXFn = []
  321. {
  322. return SandboxEditor::CameraPanInvertedX();
  323. };
  324. m_orbitPanCamera->m_invertPanYFn = []
  325. {
  326. return SandboxEditor::CameraPanInvertedY();
  327. };
  328. m_orbitFocusCamera =
  329. AZStd::make_shared<AzFramework::FocusCameraInput>(SandboxEditor::CameraFocusChannelId(), AzFramework::FocusOrbit);
  330. m_orbitFocusCamera->SetPivotFn(focusPivotFn);
  331. m_orbitCamera->m_orbitCameras.AddCamera(m_orbitRotateCamera);
  332. m_orbitCamera->m_orbitCameras.AddCamera(m_orbitTranslateCamera);
  333. m_orbitCamera->m_orbitCameras.AddCamera(m_orbitScrollDollyCamera);
  334. m_orbitCamera->m_orbitCameras.AddCamera(m_orbitMotionDollyCamera);
  335. m_orbitCamera->m_orbitCameras.AddCamera(m_orbitPanCamera);
  336. m_orbitCamera->m_orbitCameras.AddCamera(m_orbitFocusCamera);
  337. }
  338. void EditorModularViewportCameraComposer::OnEditorModularViewportCameraComposerSettingsChanged()
  339. {
  340. const auto translateCameraInputChannelIds = BuildTranslateCameraInputChannelIds();
  341. m_firstPersonTranslateCamera->SetTranslateCameraInputChannelIds(translateCameraInputChannelIds);
  342. m_firstPersonPanCamera->SetPanInputChannelId(SandboxEditor::CameraFreePanChannelId());
  343. m_firstPersonRotateCamera->SetRotateInputChannelId(SandboxEditor::CameraFreeLookChannelId());
  344. m_firstPersonFocusCamera->SetFocusInputChannelId(SandboxEditor::CameraFocusChannelId());
  345. m_orbitCamera->SetOrbitInputChannelId(SandboxEditor::CameraOrbitChannelId());
  346. m_orbitTranslateCamera->SetTranslateCameraInputChannelIds(translateCameraInputChannelIds);
  347. m_orbitPanCamera->SetPanInputChannelId(SandboxEditor::CameraOrbitPanChannelId());
  348. m_orbitRotateCamera->SetRotateInputChannelId(SandboxEditor::CameraOrbitLookChannelId());
  349. m_orbitMotionDollyCamera->SetDollyInputChannelId(SandboxEditor::CameraOrbitDollyChannelId());
  350. m_orbitFocusCamera->SetFocusInputChannelId(SandboxEditor::CameraFocusChannelId());
  351. }
  352. void EditorModularViewportCameraComposer::OnViewportViewEntityChanged(const AZ::EntityId& viewEntityId)
  353. {
  354. if (viewEntityId.IsValid())
  355. {
  356. AZ::Transform worldFromLocal = AZ::Transform::CreateIdentity();
  357. AZ::TransformBus::EventResult(worldFromLocal, viewEntityId, &AZ::TransformBus::Events::GetWorldTM);
  358. AtomToolsFramework::ModularViewportCameraControllerRequestBus::Event(
  359. m_viewportId, &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::StartTrackingTransform,
  360. worldFromLocal);
  361. }
  362. else
  363. {
  364. AtomToolsFramework::ModularViewportCameraControllerRequestBus::Event(
  365. m_viewportId, &AtomToolsFramework::ModularViewportCameraControllerRequestBus::Events::StopTrackingTransform);
  366. }
  367. }
  368. void EditorModularViewportCameraComposer::OnTick(const float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time)
  369. {
  370. const float delta = [duration = &ed_cameraDefaultOrbitFadeDuration, deltaTime]
  371. {
  372. if (*duration == 0.0f)
  373. {
  374. return 1.0f;
  375. }
  376. return deltaTime / *duration;
  377. }();
  378. if (m_pivot.has_value())
  379. {
  380. const float opacity = ed_cameraPivotFadedOpacity;
  381. switch (m_pivotDisplayState)
  382. {
  383. case PivotDisplayState::Faded:
  384. if (m_orbitOpacity <= opacity)
  385. {
  386. m_orbitOpacity = AZStd::min(m_orbitOpacity + delta, opacity);
  387. }
  388. else
  389. {
  390. m_orbitOpacity = AZStd::max(m_orbitOpacity - delta, opacity);
  391. }
  392. break;
  393. case PivotDisplayState::Full:
  394. m_orbitOpacity = AZStd::min(m_orbitOpacity + delta, 1.0f);
  395. break;
  396. case PivotDisplayState::Hidden:
  397. m_orbitOpacity = AZStd::max(m_orbitOpacity - delta, 0.0f);
  398. if (m_orbitOpacity == 0.0f)
  399. {
  400. AZ::TickBus::Handler::BusDisconnect();
  401. AzFramework::ViewportDebugDisplayEventBus::Handler::BusDisconnect();
  402. }
  403. break;
  404. }
  405. }
  406. }
  407. void EditorModularViewportCameraComposer::DisplayViewport(
  408. [[maybe_unused]] const AzFramework::ViewportInfo& viewportInfo, AzFramework::DebugDisplayRequests& debugDisplay)
  409. {
  410. if (m_pivot.has_value())
  411. {
  412. debugDisplay.CullOff();
  413. const AZ::Color color = ed_cameraPivotColor;
  414. debugDisplay.SetColor(AZ::Color::CreateFromVector3AndFloat(color.GetAsVector3(), m_orbitOpacity));
  415. debugDisplay.DrawBall(m_pivot.value(), ed_cameraPivotSize, false);
  416. debugDisplay.CullOn();
  417. }
  418. }
  419. } // namespace SandboxEditor