EditorCameraComponent.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  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 <AzCore/Serialization/EditContext.h>
  9. #include <AzCore/Component/TransformBus.h>
  10. #include <AzFramework/Entity/EntityDebugDisplayBus.h>
  11. #include "EditorCameraComponent.h"
  12. #include "ViewportCameraSelectorWindow.h"
  13. #include "Entity/EditorEntityHelpers.h"
  14. #include <AzCore/RTTI/BehaviorContext.h>
  15. #include <AzToolsFramework/API/ToolsApplicationAPI.h>
  16. #include <AzToolsFramework/Entity/EditorEntityContextBus.h>
  17. #include <Atom/RPI.Public/ViewportContext.h>
  18. #include <Atom/RPI.Public/View.h>
  19. #include <AzToolsFramework/ToolsComponents/TransformComponent.h>
  20. namespace Camera
  21. {
  22. namespace ClassConverters
  23. {
  24. extern bool UpdateCameraComponentToUseController(AZ::SerializeContext& context, AZ::SerializeContext::DataElementNode& classElement);
  25. }
  26. void EditorCameraComponent::Activate()
  27. {
  28. // Ensure our Editor Entity ID is up-to-date to sync camera configurations between Edit & Game mode.
  29. CameraComponentConfig controllerConfig = m_controller.GetConfiguration();
  30. controllerConfig.m_editorEntityId = GetEntityId().operator AZ::u64();
  31. m_controller.SetConfiguration(controllerConfig);
  32. // Only allow our camera to activate with the component if we're currently in game mode.
  33. m_controller.SetShouldActivateFunction([]()
  34. {
  35. bool isInGameMode = true;
  36. AzToolsFramework::EditorEntityContextRequestBus::BroadcastResult(
  37. isInGameMode, &AzToolsFramework::EditorEntityContextRequestBus::Events::IsEditorRunningGame);
  38. return isInGameMode;
  39. });
  40. // Only allow our camera to move when the transform is not locked.
  41. m_controller.SetIsLockedFunction([this]()
  42. {
  43. bool locked = false;
  44. AzToolsFramework::Components::TransformComponentMessages::Bus::EventResult(
  45. locked, GetEntityId(), &AzToolsFramework::Components::TransformComponentMessages::IsTransformLocked);
  46. return locked;
  47. });
  48. // Call base class activate, which in turn calls Activate on our controller.
  49. EditorCameraComponentBase::Activate();
  50. AzFramework::EntityDebugDisplayEventBus::Handler::BusConnect(GetEntityId());
  51. EditorCameraViewRequestBus::Handler::BusConnect(GetEntityId());
  52. }
  53. void EditorCameraComponent::Deactivate()
  54. {
  55. EditorCameraViewRequestBus::Handler::BusDisconnect(GetEntityId());
  56. AzFramework::EntityDebugDisplayEventBus::Handler::BusDisconnect();
  57. EditorCameraComponentBase::Deactivate();
  58. }
  59. AZ::u32 EditorCameraComponent::OnConfigurationChanged()
  60. {
  61. bool isActiveEditorCamera = m_controller.IsActiveView();
  62. AZ::u32 configurationHash = EditorCameraComponentBase::OnConfigurationChanged();
  63. // If we were the active editor camera before, ensure we get reactivated after our controller gets disabled then re-enabled
  64. if (isActiveEditorCamera)
  65. {
  66. m_controller.MakeActiveView();
  67. }
  68. return configurationHash;
  69. }
  70. static bool UpdateEditorCameraComponentToUseController(AZ::SerializeContext& context, AZ::SerializeContext::DataElementNode& classElement)
  71. {
  72. if (!ClassConverters::UpdateCameraComponentToUseController(context, classElement))
  73. {
  74. return false;
  75. }
  76. classElement.Convert<EditorCameraComponent>(context);
  77. return true;
  78. }
  79. void EditorCameraComponent::Reflect(AZ::ReflectContext* reflection)
  80. {
  81. EditorCameraComponentBase::Reflect(reflection);
  82. AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(reflection);
  83. if (serializeContext)
  84. {
  85. serializeContext->ClassDeprecate("EditorCameraComponent", AZ::Uuid("{B99EFE3D-3F1D-4630-8A7B-31C70CC1F53C}"), &UpdateEditorCameraComponentToUseController);
  86. serializeContext->Class<EditorCameraComponent, EditorCameraComponentBase>()
  87. ->Version(0)
  88. ->Field("FrustumLengthPercent", &EditorCameraComponent::m_frustumViewPercentLength)
  89. ->Field("FrustumDrawColor", &EditorCameraComponent::m_frustumDrawColor)
  90. ;
  91. AZ::EditContext* editContext = serializeContext->GetEditContext();
  92. if (editContext)
  93. {
  94. editContext->Class<EditorCameraComponent>("Camera", "The Camera component allows an entity to be used as a camera")
  95. ->ClassElement(AZ::Edit::ClassElements::EditorData, "")
  96. ->Attribute(AZ::Edit::Attributes::Category, "Camera")
  97. ->Attribute(AZ::Edit::Attributes::Icon, "Editor/Icons/Components/Camera.svg")
  98. ->Attribute(AZ::Edit::Attributes::ViewportIcon, "Editor/Icons/Components/Viewport/Camera.svg")
  99. ->Attribute(AZ::Edit::Attributes::AutoExpand, true)
  100. ->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC_CE("Game"))
  101. ->Attribute(AZ::Edit::Attributes::HelpPageURL, "https://o3de.org/docs/user-guide/components/reference/camera/camera/")
  102. ->UIElement(AZ::Edit::UIHandlers::Button,"", "Sets the view to this camera")
  103. ->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorCameraComponent::OnPossessCameraButtonClicked)
  104. ->Attribute(AZ::Edit::Attributes::ButtonText, &EditorCameraComponent::GetCameraViewButtonText)
  105. ->UIElement(AZ::Edit::UIHandlers::Button,"", "Sets this camera to view")
  106. ->Attribute(AZ::Edit::Attributes::ChangeNotify, &EditorCameraComponent::OnMatchViewportClicked)
  107. ->Attribute(AZ::Edit::Attributes::ButtonText, "Match Viewport")
  108. ->Attribute(AZ::Edit::Attributes::AutoExpand, false)
  109. ->Attribute(AZ::Edit::Attributes::ReadOnly, &EditorCameraComponent::IsActiveCamera)
  110. ->ClassElement(AZ::Edit::ClassElements::Group, "Debug")
  111. ->DataElement(AZ::Edit::UIHandlers::Default, &EditorCameraComponent::m_frustumViewPercentLength, "Frustum length", "Frustum length percent .01 to 100")
  112. ->Attribute(AZ::Edit::Attributes::Min, 0.01f)
  113. ->Attribute(AZ::Edit::Attributes::Max, 100.f)
  114. ->Attribute(AZ::Edit::Attributes::Suffix, " percent")
  115. ->Attribute(AZ::Edit::Attributes::Step, 1.f)
  116. ->DataElement(AZ::Edit::UIHandlers::Color, &EditorCameraComponent::m_frustumDrawColor, "Frustum color", "Frustum draw color RGB")
  117. ;
  118. }
  119. }
  120. if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(reflection))
  121. {
  122. behaviorContext->Class<EditorCameraComponent>()->RequestBus("CameraRequestBus");
  123. behaviorContext->EBus<EditorCameraViewRequestBus>("EditorCameraViewRequestBus")
  124. ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Automation)
  125. ->Attribute(AZ::Script::Attributes::Module, "camera")
  126. ->Event("ToggleCameraAsActiveView", &EditorCameraViewRequests::ToggleCameraAsActiveView)
  127. ->Event("MatchViewport", &EditorCameraViewRequests::MatchViewport)
  128. ->Event("IsActiveCamera", &EditorCameraViewRequests::IsActiveCamera)
  129. ;
  130. }
  131. }
  132. bool EditorCameraComponent::GetCameraState(AzFramework::CameraState& cameraState)
  133. {
  134. const CameraComponentConfig& config = m_controller.GetConfiguration();
  135. AZ::RPI::ViewportContextPtr viewportContext = m_controller.GetViewportContext();
  136. AZ::RPI::ViewPtr view = m_controller.GetView();
  137. if (viewportContext == nullptr || view == nullptr)
  138. {
  139. return false;
  140. }
  141. AzFramework::SetCameraTransform(cameraState, view->GetCameraTransform());
  142. {
  143. const AzFramework::WindowSize viewportSize = viewportContext->GetViewportSize();
  144. cameraState.m_viewportSize = AzFramework::ScreenSize(viewportSize.m_width, viewportSize.m_height);
  145. }
  146. if (config.m_orthographic)
  147. {
  148. cameraState.m_fovOrZoom = aznumeric_cast<float>(cameraState.m_viewportSize.m_width) / (config.m_orthographicHalfWidth * 2.0f);
  149. cameraState.m_orthographic = true;
  150. }
  151. else
  152. {
  153. cameraState.m_fovOrZoom = config.m_fov;
  154. cameraState.m_orthographic = false;
  155. }
  156. cameraState.m_nearClip = config.m_nearClipDistance;
  157. cameraState.m_farClip = config.m_farClipDistance;
  158. return true;
  159. }
  160. AZ::Crc32 EditorCameraComponent::OnPossessCameraButtonClicked()
  161. {
  162. AZ::EntityId currentViewEntity;
  163. EditorCameraRequests::Bus::BroadcastResult(currentViewEntity, &EditorCameraRequests::GetCurrentViewEntityId);
  164. AzToolsFramework::EditorRequestBus::Broadcast(&AzToolsFramework::EditorRequestBus::Events::ShowViewPane, s_viewportCameraSelectorName);
  165. if (currentViewEntity != GetEntityId())
  166. {
  167. EditorCameraRequests::Bus::Broadcast(&EditorCameraRequests::SetViewFromEntityPerspective, GetEntityId());
  168. }
  169. else
  170. {
  171. // set the view entity id back to Invalid, thus enabling the editor camera
  172. EditorCameraRequests::Bus::Broadcast(&EditorCameraRequests::SetViewFromEntityPerspective, AZ::EntityId());
  173. }
  174. return AZ::Edit::PropertyRefreshLevels::AttributesAndValues;
  175. }
  176. AZ::Crc32 EditorCameraComponent::OnMatchViewportClicked()
  177. {
  178. if (IsActiveCamera())
  179. {
  180. AZ_Warning("EditorCameraComponent", false, "Camera %s is already active.", GetEntity()->GetName().c_str());
  181. return AZ::Edit::PropertyRefreshLevels::AttributesAndValues;
  182. }
  183. AZStd::optional<AZ::Transform> transform = AZStd::nullopt;
  184. EditorCameraRequests::Bus::BroadcastResult(transform, &EditorCameraRequests::GetActiveCameraTransform);
  185. if (!transform)
  186. {
  187. return AZ::Edit::PropertyRefreshLevels::AttributesAndValues;
  188. }
  189. AZStd::optional<float> fov = AZStd::nullopt;
  190. EditorCameraRequests::Bus::BroadcastResult(fov, &EditorCameraRequests::GetCameraFoV);
  191. if (!fov)
  192. {
  193. return AZ::Edit::PropertyRefreshLevels::AttributesAndValues;
  194. }
  195. const AZ::EntityId entityId = GetEntityId();
  196. AZ::TransformBus::Event(entityId, &AZ::TransformInterface::SetWorldTM, transform.value());
  197. CameraRequestBus::Event(entityId, &CameraComponentRequests::SetFovRadians, fov.value());
  198. EditorCameraRequests::Bus::Broadcast(&EditorCameraRequests::SetViewFromEntityPerspective, entityId);
  199. return AZ::Edit::PropertyRefreshLevels::AttributesAndValues;
  200. }
  201. AZStd::string EditorCameraComponent::GetCameraViewButtonText() const
  202. {
  203. if (IsActiveCamera())
  204. {
  205. return "Return to default editor camera";
  206. }
  207. else
  208. {
  209. return "Be this camera";
  210. }
  211. }
  212. void EditorCameraComponent::DisplayEntityViewport(
  213. [[maybe_unused]] const AzFramework::ViewportInfo& viewportInfo,
  214. AzFramework::DebugDisplayRequests& debugDisplay)
  215. {
  216. AZ::Transform transform = AZ::Transform::CreateIdentity();
  217. AZ::TransformBus::EventResult(transform, GetEntityId(), &AZ::TransformInterface::GetWorldTM);
  218. EditorDisplay(debugDisplay, transform);
  219. }
  220. void EditorCameraComponent::ToggleCameraAsActiveView()
  221. {
  222. OnPossessCameraButtonClicked();
  223. }
  224. void EditorCameraComponent::MatchViewport()
  225. {
  226. OnMatchViewportClicked();
  227. }
  228. bool EditorCameraComponent::IsActiveCamera() const
  229. {
  230. AZ::EntityId currentViewEntity;
  231. EditorCameraRequests::Bus::BroadcastResult(currentViewEntity, &EditorCameraRequests::GetCurrentViewEntityId);
  232. return currentViewEntity == GetEntityId();
  233. }
  234. void EditorCameraComponent::EditorDisplay(
  235. AzFramework::DebugDisplayRequests& debugDisplay, const AZ::Transform& world)
  236. {
  237. const CameraComponentConfig& config = m_controller.GetConfiguration();
  238. const float distance = config.m_farClipDistance * m_frustumViewPercentLength * 0.01f;
  239. float width;
  240. float height;
  241. if (config.m_orthographic)
  242. {
  243. width = config.m_orthographicHalfWidth;
  244. height = width / debugDisplay.GetAspectRatio();
  245. }
  246. else
  247. {
  248. const float tangent = static_cast<float>(tan(0.5f * AZ::DegToRad(config.m_fov)));
  249. height = distance * tangent;
  250. width = height * debugDisplay.GetAspectRatio();
  251. }
  252. AZ::Vector3 farPoints[4];
  253. farPoints[0] = AZ::Vector3( width, distance, height);
  254. farPoints[1] = AZ::Vector3(-width, distance, height);
  255. farPoints[2] = AZ::Vector3(-width, distance, -height);
  256. farPoints[3] = AZ::Vector3( width, distance, -height);
  257. AZ::Vector3 nearPoints[4];
  258. if (config.m_orthographic)
  259. {
  260. nearPoints[0] = AZ::Vector3( width, config.m_nearClipDistance, height);
  261. nearPoints[1] = AZ::Vector3(-width, config.m_nearClipDistance, height);
  262. nearPoints[2] = AZ::Vector3(-width, config.m_nearClipDistance, -height);
  263. nearPoints[3] = AZ::Vector3( width, config.m_nearClipDistance, -height);
  264. }
  265. else
  266. {
  267. nearPoints[0] = farPoints[0].GetNormalizedSafe() * config.m_nearClipDistance;
  268. nearPoints[1] = farPoints[1].GetNormalizedSafe() * config.m_nearClipDistance;
  269. nearPoints[2] = farPoints[2].GetNormalizedSafe() * config.m_nearClipDistance;
  270. nearPoints[3] = farPoints[3].GetNormalizedSafe() * config.m_nearClipDistance;
  271. }
  272. debugDisplay.PushMatrix(world);
  273. debugDisplay.SetColor(m_frustumDrawColor.GetAsVector4());
  274. debugDisplay.DrawLine(nearPoints[0], farPoints[0]);
  275. debugDisplay.DrawLine(nearPoints[1], farPoints[1]);
  276. debugDisplay.DrawLine(nearPoints[2], farPoints[2]);
  277. debugDisplay.DrawLine(nearPoints[3], farPoints[3]);
  278. debugDisplay.DrawPolyLine(nearPoints, AZ_ARRAY_SIZE(nearPoints));
  279. debugDisplay.DrawPolyLine(farPoints, AZ_ARRAY_SIZE(farPoints));
  280. debugDisplay.PopMatrix();
  281. }
  282. } //namespace Camera