ReflectionProbeComponentController.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  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 <ReflectionProbe/ReflectionProbeComponentController.h>
  9. #include <ReflectionProbe/ReflectionProbeComponentConstants.h>
  10. #include <Atom/RPI.Public/Model/Model.h>
  11. #include <Atom/RPI.Public/Image/StreamingImage.h>
  12. #include <Atom/RPI.Public/Scene.h>
  13. #include <AzCore/Asset/AssetManager.h>
  14. #include <AzCore/Asset/AssetManagerBus.h>
  15. #include <AzCore/Asset/AssetSerializer.h>
  16. #include <AzCore/Serialization/SerializeContext.h>
  17. #include <AzFramework/Entity/EntityContextBus.h>
  18. #include <AzFramework/Entity/EntityContext.h>
  19. #include <AzFramework/Scene/Scene.h>
  20. #include <AzFramework/Scene/SceneSystemInterface.h>
  21. #include <AzCore/RTTI/BehaviorContext.h>
  22. namespace AZ
  23. {
  24. namespace Render
  25. {
  26. void ReflectionProbeComponentConfig::Reflect(ReflectContext* context)
  27. {
  28. if (auto* serializeContext = azrtti_cast<SerializeContext*>(context))
  29. {
  30. serializeContext->Class<ReflectionProbeComponentConfig>()
  31. ->Version(1)
  32. ->Field("OuterHeight", &ReflectionProbeComponentConfig::m_outerHeight)
  33. ->Field("OuterLength", &ReflectionProbeComponentConfig::m_outerLength)
  34. ->Field("OuterWidth", &ReflectionProbeComponentConfig::m_outerWidth)
  35. ->Field("InnerHeight", &ReflectionProbeComponentConfig::m_innerHeight)
  36. ->Field("InnerLength", &ReflectionProbeComponentConfig::m_innerLength)
  37. ->Field("InnerWidth", &ReflectionProbeComponentConfig::m_innerWidth)
  38. ->Field("UseBakedCubemap", &ReflectionProbeComponentConfig::m_useBakedCubemap)
  39. ->Field("BakedCubemapQualityLevel", &ReflectionProbeComponentConfig::m_bakedCubeMapQualityLevel)
  40. ->Field("BakedCubeMapRelativePath", &ReflectionProbeComponentConfig::m_bakedCubeMapRelativePath)
  41. ->Field("BakedCubeMapAsset", &ReflectionProbeComponentConfig::m_bakedCubeMapAsset)
  42. ->Field("AuthoredCubeMapAsset", &ReflectionProbeComponentConfig::m_authoredCubeMapAsset)
  43. ->Field("EntityId", &ReflectionProbeComponentConfig::m_entityId)
  44. ->Field("UseParallaxCorrection", &ReflectionProbeComponentConfig::m_useParallaxCorrection)
  45. ->Field("ShowVisualization", &ReflectionProbeComponentConfig::m_showVisualization)
  46. ->Field("RenderExposure", &ReflectionProbeComponentConfig::m_renderExposure)
  47. ->Field("BakeExposure", &ReflectionProbeComponentConfig::m_bakeExposure);
  48. }
  49. }
  50. void ReflectionProbeComponentController::Reflect(ReflectContext* context)
  51. {
  52. ReflectionProbeComponentConfig::Reflect(context);
  53. if (auto* serializeContext = azrtti_cast<SerializeContext*>(context))
  54. {
  55. serializeContext->Class<ReflectionProbeComponentController>()
  56. ->Version(0)
  57. ->Field("Configuration", &ReflectionProbeComponentController::m_configuration);
  58. }
  59. }
  60. void ReflectionProbeComponentController::GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent)
  61. {
  62. dependent.push_back(AZ_CRC_CE("TransformService"));
  63. }
  64. void ReflectionProbeComponentController::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
  65. {
  66. provided.push_back(AZ_CRC_CE("ReflectionProbeService"));
  67. }
  68. void ReflectionProbeComponentController::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
  69. {
  70. incompatible.push_back(AZ_CRC_CE("ReflectionProbeService"));
  71. incompatible.push_back(AZ_CRC_CE("NonUniformScaleService"));
  72. }
  73. void ReflectionProbeComponentController::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
  74. {
  75. required.push_back(AZ_CRC_CE("BoxShapeService"));
  76. }
  77. ReflectionProbeComponentController::ReflectionProbeComponentController(const ReflectionProbeComponentConfig& config)
  78. : m_configuration(config)
  79. {
  80. }
  81. void ReflectionProbeComponentController::Activate(AZ::EntityId entityId)
  82. {
  83. m_entityId = entityId;
  84. TransformNotificationBus::Handler::BusConnect(m_entityId);
  85. AzFramework::BoundsRequestBus::Handler::BusConnect(entityId);
  86. m_featureProcessor = RPI::Scene::GetFeatureProcessorForEntity<ReflectionProbeFeatureProcessorInterface>(entityId);
  87. AZ_Assert(m_featureProcessor, "ReflectionProbeComponentController was unable to find a ReflectionProbeFeatureProcessor on the EntityContext provided.");
  88. m_transformInterface = TransformBus::FindFirstHandler(entityId);
  89. AZ_Warning("ReflectionProbeComponentController", m_transformInterface, "Unable to attach to a TransformBus handler. This mesh will always be rendered at the origin.");
  90. LmbrCentral::ShapeComponentNotificationsBus::Handler::BusConnect(m_entityId);
  91. m_shapeBus = LmbrCentral::ShapeComponentRequestsBus::FindFirstHandler(m_entityId);
  92. m_boxShapeInterface = LmbrCentral::BoxShapeComponentRequestsBus::FindFirstHandler(m_entityId);
  93. AZ_Assert(m_boxShapeInterface, "ReflectionProbeComponentController was unable to find box shape component");
  94. // special handling is required if this component is being cloned in the editor:
  95. // if this probe is using a baked cubemap, check to see if it is already referenced by another probe
  96. if (m_configuration.m_useBakedCubemap)
  97. {
  98. if (m_featureProcessor->IsCubeMapReferenced(m_configuration.m_bakedCubeMapRelativePath))
  99. {
  100. // clear the cubeMapRelativePath to prevent the newly cloned reflection probe
  101. // from using the same cubemap path as the original reflection probe
  102. m_configuration.m_bakedCubeMapRelativePath = "";
  103. }
  104. }
  105. // add this reflection probe to the feature processor
  106. m_handle = m_featureProcessor->AddReflectionProbe(
  107. ComputeOverallTransform(m_transformInterface->GetWorldTM()), m_configuration.m_useParallaxCorrection);
  108. // set the visualization sphere option
  109. m_featureProcessor->ShowVisualization(m_handle, m_configuration.m_showVisualization);
  110. // if this is a new ReflectionProbe entity and the box shape has not been changed (i.e., it's still unit sized)
  111. // then set the shape to the default extents
  112. AZ::Vector3 boxDimensions = m_boxShapeInterface->GetBoxDimensions();
  113. if (m_configuration.m_entityId == EntityId::InvalidEntityId && boxDimensions == AZ::Vector3(1.0f))
  114. {
  115. AZ::Vector3 extents(m_configuration.m_outerWidth, m_configuration.m_outerLength, m_configuration.m_outerHeight);
  116. // resize the box shape, this will invoke OnShapeChanged
  117. m_boxShapeInterface->SetBoxDimensions(extents);
  118. }
  119. else
  120. {
  121. // update the outer extents from the box shape
  122. UpdateOuterExtents();
  123. }
  124. // set the inner extents
  125. m_featureProcessor->SetInnerExtents(m_handle, AZ::Vector3(m_configuration.m_innerWidth, m_configuration.m_innerLength, m_configuration.m_innerHeight));
  126. // load cubemap
  127. Data::Asset<RPI::StreamingImageAsset>& cubeMapAsset =
  128. m_configuration.m_useBakedCubemap ? m_configuration.m_bakedCubeMapAsset : m_configuration.m_authoredCubeMapAsset;
  129. if (cubeMapAsset.GetId().IsValid())
  130. {
  131. cubeMapAsset.QueueLoad();
  132. Data::AssetBus::MultiHandler::BusConnect(cubeMapAsset.GetId());
  133. }
  134. // set cubemap render exposure
  135. m_featureProcessor->SetRenderExposure(m_handle, m_configuration.m_renderExposure);
  136. }
  137. void ReflectionProbeComponentController::Deactivate()
  138. {
  139. if (m_featureProcessor)
  140. {
  141. m_featureProcessor->RemoveReflectionProbe(m_handle);
  142. m_handle = ReflectionProbeHandle{};
  143. }
  144. LmbrCentral::ShapeComponentNotificationsBus::Handler::BusDisconnect();
  145. Data::AssetBus::MultiHandler::BusDisconnect();
  146. AzFramework::BoundsRequestBus::Handler::BusDisconnect();
  147. TransformNotificationBus::Handler::BusDisconnect();
  148. m_transformInterface = nullptr;
  149. m_featureProcessor = nullptr;
  150. m_shapeBus = nullptr;
  151. m_boxShapeInterface = nullptr;
  152. }
  153. void ReflectionProbeComponentController::OnAssetReady(Data::Asset<Data::AssetData> asset)
  154. {
  155. if (!m_featureProcessor)
  156. {
  157. return;
  158. }
  159. const AZStd::string& relativePath =
  160. m_configuration.m_useBakedCubemap ? m_configuration.m_bakedCubeMapRelativePath : m_configuration.m_authoredCubeMapAsset.GetHint();
  161. Data::Instance<RPI::Image> image = RPI::StreamingImage::FindOrCreate(asset);
  162. m_featureProcessor->SetCubeMap(m_handle, image, relativePath);
  163. }
  164. void ReflectionProbeComponentController::OnAssetReloaded(Data::Asset<Data::AssetData> asset)
  165. {
  166. if (m_configuration.m_useBakedCubemap)
  167. {
  168. m_configuration.m_bakedCubeMapAsset = asset;
  169. }
  170. else
  171. {
  172. m_configuration.m_authoredCubeMapAsset = asset;
  173. }
  174. }
  175. void ReflectionProbeComponentController::SetConfiguration(const ReflectionProbeComponentConfig& config)
  176. {
  177. m_configuration = config;
  178. }
  179. const ReflectionProbeComponentConfig& ReflectionProbeComponentController::GetConfiguration() const
  180. {
  181. return m_configuration;
  182. }
  183. void ReflectionProbeComponentController::UpdateCubeMap()
  184. {
  185. // disconnect the asset bus since we might reconnect with a different asset
  186. Data::AssetBus::MultiHandler::BusDisconnect();
  187. Data::Asset<RPI::StreamingImageAsset>& cubeMapAsset =
  188. m_configuration.m_useBakedCubemap ? m_configuration.m_bakedCubeMapAsset : m_configuration.m_authoredCubeMapAsset;
  189. if (cubeMapAsset.GetId().IsValid())
  190. {
  191. cubeMapAsset.QueueLoad();
  192. // this will invoke OnAssetReady()
  193. Data::AssetBus::MultiHandler::BusConnect(cubeMapAsset.GetId());
  194. }
  195. else
  196. {
  197. // clear the current cubemap
  198. Data::Instance<RPI::Image> image = nullptr;
  199. m_featureProcessor->SetCubeMap(m_handle, image, {});
  200. }
  201. }
  202. void ReflectionProbeComponentController::OnTransformChanged([[maybe_unused]] const AZ::Transform& local, const AZ::Transform& world)
  203. {
  204. if (!m_featureProcessor)
  205. {
  206. return;
  207. }
  208. m_featureProcessor->SetTransform(m_handle, ComputeOverallTransform(world));
  209. }
  210. void ReflectionProbeComponentController::OnShapeChanged(ShapeChangeReasons changeReason)
  211. {
  212. if (!m_featureProcessor)
  213. {
  214. return;
  215. }
  216. AZ_Assert(m_featureProcessor->IsValidHandle(m_handle), "OnShapeChanged handler called before probe was registered with feature processor");
  217. if (changeReason == ShapeChangeReasons::ShapeChanged)
  218. {
  219. UpdateOuterExtents();
  220. // the shape translation offset may have changed, which would affect the overall transform
  221. m_featureProcessor->SetTransform(m_handle, ComputeOverallTransform(m_transformInterface->GetWorldTM()));
  222. }
  223. }
  224. void ReflectionProbeComponentController::UpdateOuterExtents()
  225. {
  226. if (!m_featureProcessor)
  227. {
  228. return;
  229. }
  230. AZ::Vector3 dimensions = m_boxShapeInterface->GetBoxDimensions();
  231. m_featureProcessor->SetOuterExtents(m_handle, dimensions);
  232. m_configuration.m_outerWidth = dimensions.GetX();
  233. m_configuration.m_outerLength = dimensions.GetY();
  234. m_configuration.m_outerHeight = dimensions.GetZ();
  235. AZ::Interface<AzFramework::IEntityBoundsUnion>::Get()->RefreshEntityLocalBoundsUnion(m_entityId);
  236. // clamp the inner extents to the outer extents
  237. m_configuration.m_innerWidth = AZStd::min(m_configuration.m_innerWidth, m_configuration.m_outerWidth);
  238. m_configuration.m_innerLength = AZStd::min(m_configuration.m_innerLength, m_configuration.m_outerLength);
  239. m_configuration.m_innerHeight = AZStd::min(m_configuration.m_innerHeight, m_configuration.m_outerHeight);
  240. m_innerExtentsChangedEvent.Signal(true);
  241. }
  242. void ReflectionProbeComponentController::SetBakeExposure(float bakeExposure)
  243. {
  244. if (!m_featureProcessor)
  245. {
  246. return;
  247. }
  248. m_featureProcessor->SetBakeExposure(m_handle, bakeExposure);
  249. }
  250. void ReflectionProbeComponentController::BakeReflectionProbe(BuildCubeMapCallback callback, const AZStd::string& relativePath)
  251. {
  252. if (!m_featureProcessor)
  253. {
  254. return;
  255. }
  256. m_featureProcessor->Bake(m_handle, callback, relativePath);
  257. }
  258. AZ::Aabb ReflectionProbeComponentController::GetAabb() const
  259. {
  260. return m_shapeBus ? m_shapeBus->GetEncompassingAabb() : AZ::Aabb();
  261. }
  262. AZ::Aabb ReflectionProbeComponentController::GetWorldBounds() const
  263. {
  264. return GetAabb();
  265. }
  266. AZ::Aabb ReflectionProbeComponentController::GetLocalBounds() const
  267. {
  268. if (!m_shapeBus)
  269. {
  270. return Aabb::CreateNull();
  271. }
  272. AZ::Transform unused;
  273. AZ::Aabb localBounds = AZ::Aabb::CreateNull();
  274. m_shapeBus->GetTransformAndLocalBounds(unused, localBounds);
  275. if (!m_boxShapeInterface->IsTypeAxisAligned())
  276. {
  277. return localBounds;
  278. }
  279. else
  280. {
  281. return localBounds.GetTransformedAabb(
  282. AZ::Transform::CreateFromQuaternion(m_transformInterface->GetWorldTM().GetRotation().GetInverseFast()));
  283. }
  284. }
  285. void ReflectionProbeComponentController::RegisterInnerExtentsChangedHandler(AZ::Event<bool>::Handler& handler)
  286. {
  287. handler.Connect(m_innerExtentsChangedEvent);
  288. }
  289. AZ::Transform ReflectionProbeComponentController::ComputeOverallTransform(const AZ::Transform& entityTransform) const
  290. {
  291. const bool isTypeAxisAligned = m_boxShapeInterface ? m_boxShapeInterface->IsTypeAxisAligned() : false;
  292. const AZ::Vector3 translationOffset = m_shapeBus ? m_shapeBus->GetTranslationOffset() : AZ::Vector3::CreateZero();
  293. const AZ::Transform translationOffsetTransform = AZ::Transform::CreateTranslation(translationOffset);
  294. if (isTypeAxisAligned)
  295. {
  296. AZ::Transform entityTransformNoRotation = entityTransform;
  297. entityTransformNoRotation.SetRotation(AZ::Quaternion::CreateIdentity());
  298. return entityTransformNoRotation * translationOffsetTransform;
  299. }
  300. return entityTransform * translationOffsetTransform;
  301. }
  302. } // namespace Render
  303. } // namespace AZ