CameraComponent.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413
  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 <Atom/Component/DebugCamera/CameraComponent.h>
  9. #include <AzCore/Component/TransformBus.h>
  10. #include <AzCore/IO/IOUtils.h>
  11. #include <AzCore/Serialization/SerializeContext.h>
  12. #include <AzCore/Component/Entity.h>
  13. #include <AzCore/Math/MatrixUtils.h>
  14. #include <Atom/RHI/RHISystemInterface.h>
  15. #include <Atom/RPI.Public/RPISystemInterface.h>
  16. #include <Atom/RPI.Public/AuxGeom/AuxGeomFeatureProcessorInterface.h>
  17. #include <Atom/RPI.Public/Scene.h>
  18. #include <Atom/RPI.Public/WindowContext.h>
  19. namespace AZ
  20. {
  21. namespace Debug
  22. {
  23. void CameraComponentConfig::Reflect(AZ::ReflectContext* context)
  24. {
  25. if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
  26. {
  27. serializeContext->Class<CameraComponentConfig, AZ::ComponentConfig>()
  28. ->Version(1)
  29. ->Field("FovY", &CameraComponentConfig::m_fovY)
  30. ->Field("DepthNear", &CameraComponentConfig::m_depthNear)
  31. ->Field("DepthFar", &CameraComponentConfig::m_depthFar)
  32. ->Field("AspectRatioOverride", &CameraComponentConfig::m_aspectRatioOverride)
  33. ;
  34. }
  35. }
  36. void CameraComponent::Reflect(AZ::ReflectContext* context)
  37. {
  38. CameraComponentConfig::Reflect(context);
  39. if (auto* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
  40. {
  41. serializeContext->Class<CameraComponent, AZ::Component>()
  42. ->Version(1)
  43. ->Field("Config", &CameraComponent::m_componentConfig)
  44. ;
  45. }
  46. }
  47. void CameraComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
  48. {
  49. required.push_back(AZ_CRC("TransformService", 0x8ee22c50));
  50. }
  51. void CameraComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
  52. {
  53. provided.push_back(AZ_CRC("CameraService", 0x1dd1caa4));
  54. }
  55. void CameraComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
  56. {
  57. incompatible.push_back(AZ_CRC("CameraService", 0x1dd1caa4));
  58. incompatible.push_back(AZ_CRC_CE("NonUniformScaleService"));
  59. }
  60. CameraComponent::CameraComponent()
  61. {
  62. m_cameraView = AZStd::make_shared<AZ::RPI::ViewGroup>();
  63. m_cameraView->Init(AZ::RPI::ViewGroup::Descriptor{ nullptr, nullptr });
  64. }
  65. void CameraComponent::Activate()
  66. {
  67. AZ::Name viewName = GetEntity() ?
  68. AZ::Name(AZStd::string::format("Camera View (entity: \"%s\")", GetEntity()->GetName().c_str())) :
  69. AZ::Name("Camera view (unknown entity)");
  70. m_cameraView->CreateMainView(viewName);
  71. m_cameraView->CreateStereoscopicViews(viewName);
  72. m_xrSystem = RPI::RPISystemInterface::Get()->GetXRSystem();
  73. if (m_xrSystem)
  74. {
  75. m_numXrViews = m_xrSystem->GetNumViews();
  76. }
  77. for (uint16_t i = 0; i < AZ::RPI::XRMaxNumViews; i++)
  78. {
  79. if (i < m_stereoscopicViewQuats.size())
  80. {
  81. m_stereoscopicViewQuats[i] = AZ::Quaternion::CreateIdentity();
  82. }
  83. else
  84. {
  85. m_stereoscopicViewQuats.insert(m_stereoscopicViewQuats.begin() + i, AZ::Quaternion::CreateIdentity());
  86. }
  87. }
  88. m_auxGeomFeatureProcessor = RPI::Scene::GetFeatureProcessorForEntity<RPI::AuxGeomFeatureProcessorInterface>(GetEntityId());
  89. if (m_auxGeomFeatureProcessor)
  90. {
  91. m_auxGeomFeatureProcessor->GetOrCreateDrawQueueForView(m_cameraView->GetView(RPI::ViewType::Default).get());
  92. }
  93. //Get transform at start
  94. Transform transform;
  95. TransformBus::BroadcastResult(transform, &TransformBus::Events::GetWorldTM);
  96. OnTransformChanged(transform, transform);
  97. TransformNotificationBus::Handler::BusConnect(GetEntityId());
  98. RPI::ViewProviderBus::Handler::BusConnect(GetEntityId());
  99. Camera::CameraRequestBus::Handler::BusConnect(GetEntityId());
  100. Camera::CameraNotificationBus::Broadcast(&Camera::CameraNotificationBus::Events::OnCameraAdded, GetEntityId());
  101. }
  102. void CameraComponent::Deactivate()
  103. {
  104. Camera::CameraNotificationBus::Broadcast(&Camera::CameraNotificationBus::Events::OnCameraRemoved, GetEntityId());
  105. Camera::CameraRequestBus::Handler::BusDisconnect();
  106. RPI::ViewProviderBus::Handler::BusDisconnect();
  107. TransformNotificationBus::Handler::BusDisconnect();
  108. RPI::WindowContextNotificationBus::Handler::BusDisconnect();
  109. if (m_auxGeomFeatureProcessor)
  110. {
  111. m_auxGeomFeatureProcessor->ReleaseDrawQueueForView(m_cameraView->GetView(RPI::ViewType::Default).get());
  112. }
  113. m_auxGeomFeatureProcessor = nullptr;
  114. m_stereoscopicViewQuats.clear();
  115. }
  116. RPI::ViewPtr CameraComponent::GetView() const
  117. {
  118. return m_cameraView->GetView(RPI::ViewType::Default);
  119. }
  120. RPI::ViewPtr CameraComponent::GetStereoscopicView(RPI::ViewType viewType) const
  121. {
  122. AZ_Assert(viewType == RPI::ViewType::XrLeft || viewType == RPI::ViewType::XrRight, "View type %i not stereoscopic", viewType);
  123. return m_cameraView->GetView(viewType);
  124. }
  125. bool CameraComponent::ReadInConfig(const AZ::ComponentConfig* baseConfig)
  126. {
  127. auto config = azrtti_cast<const CameraComponentConfig*>(baseConfig);
  128. if (config != nullptr)
  129. {
  130. m_componentConfig = *config;
  131. if (config->m_target != nullptr)
  132. {
  133. RPI::WindowContextNotificationBus::Handler::BusConnect(m_componentConfig.m_target->GetWindowHandle());
  134. }
  135. UpdateAspectRatio();
  136. return true;
  137. }
  138. return false;
  139. }
  140. bool CameraComponent::WriteOutConfig(AZ::ComponentConfig* outBaseConfig) const
  141. {
  142. auto config = azrtti_cast<CameraComponentConfig*>(outBaseConfig);
  143. if (config != nullptr)
  144. {
  145. *config = m_componentConfig;
  146. return true;
  147. }
  148. return false;
  149. }
  150. void CameraComponent::OnTransformChanged([[maybe_unused]] const AZ::Transform& local, const AZ::Transform& world)
  151. {
  152. //Apply transform to stereoscopic views
  153. for (AZ::u32 i = 0; i < m_numXrViews; i++)
  154. {
  155. RPI::ViewType xrViewType = i == 0 ? RPI::ViewType::XrLeft : RPI::ViewType::XrRight;
  156. if (m_stereoscopicViewUpdate)
  157. {
  158. // Apply the stereoscopic view provided by the device
  159. AZ::Matrix3x4 worldTransform =
  160. AZ::Matrix3x4::CreateFromQuaternionAndTranslation(m_stereoscopicViewQuats[i], world.GetTranslation());
  161. m_cameraView->SetCameraTransform(worldTransform, xrViewType);
  162. }
  163. else
  164. {
  165. // Apply the view using keyboard/mouse input
  166. m_cameraView->SetCameraTransform(AZ::Matrix3x4::CreateFromTransform(world), xrViewType);
  167. }
  168. }
  169. // Apply transform to non stereoscopic view (i.e default)
  170. if (m_stereoscopicViewUpdate)
  171. {
  172. //Handle the case when we have a PC window showing the view of the left eye
  173. AZ::Matrix3x4 worldTransform = AZ::Matrix3x4::CreateFromQuaternionAndTranslation(
  174. m_stereoscopicViewQuats[static_cast<uint32_t>(RPI::ViewType::XrLeft)], world.GetTranslation());
  175. m_cameraView->SetCameraTransform(worldTransform);
  176. }
  177. else
  178. {
  179. m_cameraView->SetCameraTransform(AZ::Matrix3x4::CreateFromTransform(world));
  180. }
  181. m_stereoscopicViewUpdate = false;
  182. UpdateViewToClipMatrix();
  183. }
  184. float CameraComponent::GetFovDegrees()
  185. {
  186. return RadToDeg(m_componentConfig.m_fovY);
  187. }
  188. float CameraComponent::GetFovRadians()
  189. {
  190. return m_componentConfig.m_fovY;
  191. }
  192. float CameraComponent::GetNearClipDistance()
  193. {
  194. return m_componentConfig.m_depthNear;
  195. }
  196. float CameraComponent::GetFarClipDistance()
  197. {
  198. return m_componentConfig.m_depthFar;
  199. }
  200. float CameraComponent::GetFrustumWidth()
  201. {
  202. return m_componentConfig.m_depthFar * tanf(m_componentConfig.m_fovY / 2) * m_aspectRatio * 2;
  203. }
  204. float CameraComponent::GetFrustumHeight()
  205. {
  206. return m_componentConfig.m_depthFar * tanf(m_componentConfig.m_fovY / 2) * 2;
  207. }
  208. bool CameraComponent::IsOrthographic()
  209. {
  210. return false;
  211. }
  212. float CameraComponent::GetOrthographicHalfWidth()
  213. {
  214. return 0.0f;
  215. }
  216. void CameraComponent::SetXRViewQuaternion(const AZ::Quaternion& viewQuat, uint32_t xrViewIndex)
  217. {
  218. AZ_Assert(xrViewIndex < AZ::RPI::XRMaxNumViews, "Xr view index is out of range.");
  219. m_stereoscopicViewQuats[xrViewIndex] = viewQuat;
  220. m_stereoscopicViewUpdate = true;
  221. }
  222. void CameraComponent::SetFovDegrees(float fov)
  223. {
  224. m_componentConfig.m_fovY = DegToRad(fov);
  225. UpdateViewToClipMatrix();
  226. }
  227. void CameraComponent::SetFovRadians(float fov)
  228. {
  229. m_componentConfig.m_fovY = fov;
  230. UpdateViewToClipMatrix();
  231. }
  232. void CameraComponent::SetNearClipDistance(float nearClipDistance)
  233. {
  234. m_componentConfig.m_depthNear = nearClipDistance;
  235. UpdateViewToClipMatrix();
  236. }
  237. void CameraComponent::SetFarClipDistance(float farClipDistance)
  238. {
  239. m_componentConfig.m_depthFar = farClipDistance;
  240. UpdateViewToClipMatrix();
  241. }
  242. void CameraComponent::SetFrustumWidth(float width)
  243. {
  244. AZ_Assert(m_componentConfig.m_depthFar > 0.f, "Depth Far has to be positive.");
  245. AZ_Assert(m_aspectRatio > 0.f, "Aspect ratio must be positive.");
  246. const float height = width / m_aspectRatio;
  247. m_componentConfig.m_fovY = atanf(height / 2 / m_componentConfig.m_depthFar) * 2;
  248. UpdateViewToClipMatrix();
  249. }
  250. void CameraComponent::SetFrustumHeight(float height)
  251. {
  252. AZ_Assert(m_componentConfig.m_depthFar > 0.f, "Depth Far has to be positive.");
  253. m_componentConfig.m_fovY = atanf(height / 2 / m_componentConfig.m_depthFar) * 2;
  254. UpdateViewToClipMatrix();
  255. }
  256. void CameraComponent::SetOrthographic([[maybe_unused]] bool orthographic)
  257. {
  258. AZ_Assert(!orthographic, "DebugCamera does not support orthographic projection");
  259. }
  260. void CameraComponent::SetOrthographicHalfWidth([[maybe_unused]] float halfWidth)
  261. {
  262. AZ_Assert(false, "DebugCamera does not support orthographic projection");
  263. }
  264. void CameraComponent::MakeActiveView()
  265. {
  266. // do nothing
  267. }
  268. bool CameraComponent::IsActiveView()
  269. {
  270. return false;
  271. }
  272. AZ::Vector3 CameraComponent::ScreenToWorld([[maybe_unused]] const AZ::Vector2& screenPosition, [[maybe_unused]] float depth)
  273. {
  274. // not implemented
  275. return AZ::Vector3::CreateZero();
  276. }
  277. AZ::Vector3 CameraComponent::ScreenNdcToWorld([[maybe_unused]] const AZ::Vector2& screenPosition, [[maybe_unused]] float depth)
  278. {
  279. // not implemented
  280. return AZ::Vector3::CreateZero();
  281. }
  282. AZ::Vector2 CameraComponent::WorldToScreen([[maybe_unused]] const AZ::Vector3& worldPosition)
  283. {
  284. // not implemented
  285. return AZ::Vector2::CreateZero();
  286. }
  287. AZ::Vector2 CameraComponent::WorldToScreenNdc([[maybe_unused]] const AZ::Vector3& worldPosition)
  288. {
  289. // not implemented
  290. return AZ::Vector2::CreateZero();
  291. }
  292. void CameraComponent::OnViewportResized(uint32_t width, uint32_t height)
  293. {
  294. AZ_UNUSED(width);
  295. AZ_UNUSED(height);
  296. UpdateAspectRatio();
  297. UpdateViewToClipMatrix();
  298. }
  299. void CameraComponent::UpdateAspectRatio()
  300. {
  301. if (m_componentConfig.m_aspectRatioOverride > 0.0f)
  302. {
  303. m_aspectRatio = m_componentConfig.m_aspectRatioOverride;
  304. }
  305. else if (m_componentConfig.m_target)
  306. {
  307. const auto& viewport = m_componentConfig.m_target->GetViewport();
  308. if (viewport.m_maxX > 0.0f && viewport.m_maxY > 0.0f)
  309. {
  310. m_aspectRatio = viewport.m_maxX / viewport.m_maxY;
  311. }
  312. }
  313. }
  314. void CameraComponent::UpdateViewToClipMatrix()
  315. {
  316. // O3de assumes a setup for reversed depth
  317. bool reverseDepth = true;
  318. AZ::Matrix4x4 viewToClipMatrix;
  319. MakePerspectiveFovMatrixRH(
  320. viewToClipMatrix,
  321. m_componentConfig.m_fovY,
  322. m_aspectRatio,
  323. m_componentConfig.m_depthNear,
  324. m_componentConfig.m_depthFar,
  325. reverseDepth);
  326. m_cameraView->SetViewToClipMatrix(viewToClipMatrix);
  327. //Update stereoscopic projection matrix
  328. if (m_xrSystem)
  329. {
  330. AZ::Matrix4x4 projection = AZ::Matrix4x4::CreateIdentity();
  331. for (AZ::u32 i = 0; i < m_numXrViews; i++)
  332. {
  333. RPI::ViewType xrViewType = i == 0 ? RPI::ViewType::XrLeft : RPI::ViewType::XrRight;
  334. AZ::RPI::FovData fovData;
  335. [[maybe_unused]] AZ::RHI::ResultCode resultCode = m_xrSystem->GetViewFov(i, fovData);
  336. projection = m_xrSystem->CreateStereoscopicProjection(
  337. fovData.m_angleLeft,
  338. fovData.m_angleRight,
  339. fovData.m_angleDown,
  340. fovData.m_angleUp,
  341. m_componentConfig.m_depthNear,
  342. m_componentConfig.m_depthFar,
  343. reverseDepth);
  344. m_cameraView->SetStereoscopicViewToClipMatrix(projection, reverseDepth, xrViewType);
  345. }
  346. }
  347. }
  348. } // namespace Debug
  349. } // namespace AZ