3
0

HDRiSkyboxComponentController.cpp 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  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/Feature/SkyBox/SkyboxConstants.h>
  9. #include <SkyBox/HDRiSkyboxComponentController.h>
  10. #include <AzCore/RTTI/BehaviorContext.h>
  11. #include <AzCore/Serialization/SerializeContext.h>
  12. #include <Atom/RPI.Public/Scene.h>
  13. #include <Atom/Utils/Utils.h>
  14. namespace AZ
  15. {
  16. namespace Render
  17. {
  18. void HDRiSkyboxComponentController::Reflect(ReflectContext* context)
  19. {
  20. HDRiSkyboxComponentConfig::Reflect(context);
  21. if (auto* serializeContext = azrtti_cast<SerializeContext*>(context))
  22. {
  23. serializeContext->Class<HDRiSkyboxComponentController>()
  24. ->Version(1)
  25. ->Field("Configuration", &HDRiSkyboxComponentController::m_configuration);
  26. }
  27. if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
  28. {
  29. behaviorContext->EBus<HDRiSkyboxRequestBus>("HDRiSkyboxRequestBus")
  30. ->Event("SetExposure", &HDRiSkyboxRequestBus::Events::SetExposure)
  31. ->Event("GetExposure", &HDRiSkyboxRequestBus::Events::GetExposure)
  32. ->VirtualProperty("Exposure", "GetExposure", "SetExposure")
  33. ->Event("SetCubemapAssetPath", &HDRiSkyboxRequestBus::Events::SetCubemapAssetPath)
  34. ->Event("GetCubemapAssetPath", &HDRiSkyboxRequestBus::Events::GetCubemapAssetPath)
  35. ;
  36. }
  37. }
  38. void HDRiSkyboxComponentController::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
  39. {
  40. provided.push_back(AZ_CRC("SkyBoxService", 0x8169a709));
  41. }
  42. void HDRiSkyboxComponentController::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
  43. {
  44. incompatible.push_back(AZ_CRC("SkyBoxService", 0x8169a709));
  45. incompatible.push_back(AZ_CRC_CE("NonUniformScaleService"));
  46. }
  47. void HDRiSkyboxComponentController::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
  48. {
  49. required.push_back(AZ_CRC("TransformService"));
  50. }
  51. HDRiSkyboxComponentController::HDRiSkyboxComponentController(const HDRiSkyboxComponentConfig& config)
  52. : m_configuration(config)
  53. {
  54. }
  55. void HDRiSkyboxComponentController::Activate(EntityId entityId)
  56. {
  57. m_featureProcessorInterface = RPI::Scene::GetFeatureProcessorForEntity<SkyBoxFeatureProcessorInterface>(entityId);
  58. // only activate if there is no other skybox activate
  59. if (m_featureProcessorInterface && !m_featureProcessorInterface->IsEnabled())
  60. {
  61. m_featureProcessorInterface->SetSkyboxMode(SkyBoxMode::Cubemap);
  62. m_featureProcessorInterface->Enable(true);
  63. m_entityId = entityId;
  64. SetCubemapAsset(m_configuration.m_cubemapAsset);
  65. SetExposure(m_configuration.m_exposure);
  66. m_transformInterface = TransformBus::FindFirstHandler(m_entityId);
  67. AZ_Assert(m_transformInterface, "Unable to attach to a TransformBus handler. Entity transform will not affect to skybox.");
  68. const AZ::Transform& transform = m_transformInterface ? m_transformInterface->GetWorldTM() : Transform::Identity();
  69. m_featureProcessorInterface->SetCubemapRotationMatrix(GetInverseTransform(transform));
  70. HDRiSkyboxRequestBus::Handler::BusConnect(m_entityId);
  71. TransformNotificationBus::Handler::BusConnect(m_entityId);
  72. m_isActive = true;
  73. }
  74. else
  75. {
  76. m_featureProcessorInterface = nullptr;
  77. AZ_Warning("HDRiSkyboxComponentController", false, "There is already another HDRi Skybox or Physical Sky component in the scene!");
  78. }
  79. }
  80. void HDRiSkyboxComponentController::Deactivate()
  81. {
  82. // Run deactivate if this skybox is activate
  83. if (m_isActive)
  84. {
  85. HDRiSkyboxRequestBus::Handler::BusDisconnect(m_entityId);
  86. TransformNotificationBus::Handler::BusDisconnect(m_entityId);
  87. Data::AssetBus::MultiHandler::BusDisconnect();
  88. m_configuration.m_cubemapAsset.Release();
  89. m_featureProcessorInterface->Enable(false);
  90. m_featureProcessorInterface = nullptr;
  91. m_transformInterface = nullptr;
  92. m_isActive = false;
  93. }
  94. }
  95. void HDRiSkyboxComponentController::SetConfiguration(const HDRiSkyboxComponentConfig& config)
  96. {
  97. m_configuration = config;
  98. }
  99. const HDRiSkyboxComponentConfig& HDRiSkyboxComponentController::GetConfiguration() const
  100. {
  101. return m_configuration;
  102. }
  103. void HDRiSkyboxComponentController::OnAssetReady(Data::Asset<Data::AssetData> asset)
  104. {
  105. UpdateWithAsset(asset);
  106. }
  107. void HDRiSkyboxComponentController::OnAssetReloaded(Data::Asset<Data::AssetData> asset)
  108. {
  109. UpdateWithAsset(asset);
  110. }
  111. void HDRiSkyboxComponentController::OnAssetError(Data::Asset<Data::AssetData> asset)
  112. {
  113. UpdateWithAsset(asset);
  114. }
  115. void HDRiSkyboxComponentController::OnTransformChanged([[maybe_unused]] const AZ::Transform& local, const AZ::Transform& world)
  116. {
  117. m_featureProcessorInterface->SetCubemapRotationMatrix(GetInverseTransform(world));
  118. }
  119. Data::Asset<RPI::StreamingImageAsset> HDRiSkyboxComponentController::GetCubemapAsset() const
  120. {
  121. return m_configuration.m_cubemapAsset;
  122. }
  123. void HDRiSkyboxComponentController::SetCubemapAsset(const Data::Asset<RPI::StreamingImageAsset>& cubemapAsset)
  124. {
  125. Data::AssetBus::MultiHandler::BusDisconnect(m_configuration.m_cubemapAsset.GetId());
  126. m_configuration.m_cubemapAsset = cubemapAsset;
  127. LoadImage(m_configuration.m_cubemapAsset);
  128. }
  129. void HDRiSkyboxComponentController::SetCubemapAssetPath(const AZStd::string& path)
  130. {
  131. SetCubemapAsset(GetAssetFromPath<RPI::StreamingImageAsset>(path, m_configuration.m_cubemapAsset.GetAutoLoadBehavior()));
  132. }
  133. AZStd::string HDRiSkyboxComponentController::GetCubemapAssetPath() const
  134. {
  135. AZStd::string assetPathString;
  136. Data::AssetCatalogRequestBus::BroadcastResult(assetPathString, &Data::AssetCatalogRequests::GetAssetPathById, m_configuration.m_cubemapAsset.GetId());
  137. return assetPathString;
  138. }
  139. void HDRiSkyboxComponentController::SetExposure(float exposure)
  140. {
  141. m_configuration.m_exposure = exposure;
  142. m_featureProcessorInterface->SetCubemapExposure(exposure);
  143. }
  144. float HDRiSkyboxComponentController::GetExposure() const
  145. {
  146. return m_configuration.m_exposure;
  147. }
  148. void HDRiSkyboxComponentController::LoadImage(Data::Asset<RPI::StreamingImageAsset>& imageAsset)
  149. {
  150. Data::AssetBus::MultiHandler::BusDisconnect(imageAsset.GetId());
  151. if (imageAsset.GetId().IsValid())
  152. {
  153. // If the asset is already loaded it'll call OnAssetReady() immediately on BusConnect().
  154. Data::AssetBus::MultiHandler::BusConnect(imageAsset.GetId());
  155. imageAsset.QueueLoad();
  156. }
  157. else
  158. {
  159. // Call update for invalid assets so current assets can be cleared if necessary.
  160. UpdateWithAsset(imageAsset);
  161. }
  162. }
  163. void HDRiSkyboxComponentController::UpdateWithAsset(Data::Asset<Data::AssetData> updatedAsset)
  164. {
  165. if (m_configuration.m_cubemapAsset.GetId() == updatedAsset.GetId())
  166. {
  167. m_configuration.m_cubemapAsset = updatedAsset;
  168. if (IsAssetValid(m_configuration.m_cubemapAsset))
  169. {
  170. m_featureProcessorInterface->SetCubemap(RPI::StreamingImage::FindOrCreate(m_configuration.m_cubemapAsset));
  171. }
  172. else
  173. {
  174. m_featureProcessorInterface->SetCubemap(nullptr);
  175. }
  176. }
  177. }
  178. bool HDRiSkyboxComponentController::IsAssetValid(Data::Asset<RPI::StreamingImageAsset>& asset)
  179. {
  180. if (asset.GetId().IsValid() && asset->IsReady())
  181. {
  182. auto& descriptor = asset->GetImageDescriptor();
  183. bool isCubemap = descriptor.m_isCubemap || descriptor.m_arraySize == 6;
  184. if (isCubemap)
  185. {
  186. return true;
  187. }
  188. }
  189. return false;
  190. }
  191. AZ::Matrix4x4 HDRiSkyboxComponentController::GetInverseTransform(const AZ::Transform& world)
  192. {
  193. float matrix[16];
  194. // remove scale
  195. Transform worldNoScale = world;
  196. worldNoScale.ExtractUniformScale();
  197. AZ::Matrix3x4 transformMatrix = AZ::Matrix3x4::CreateFromTransform(worldNoScale);
  198. transformMatrix.StoreToRowMajorFloat12(matrix);
  199. // remove translation
  200. matrix[3] = 0;
  201. matrix[7] = 0;
  202. matrix[11] = 0;
  203. matrix[12] = 0;
  204. matrix[13] = 0;
  205. matrix[14] = 0;
  206. matrix[15] = 1;
  207. return AZ::Matrix4x4::CreateFromRowMajorFloat16(matrix).GetInverseFast();
  208. }
  209. } // namespace Render
  210. } // namespace AZ