HDRiSkyboxComponentController.cpp 11 KB

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