MaterialCanvasViewportContent.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  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 <Atom/Feature/Utils/ModelPreset.h>
  10. #include <Atom/RPI.Edit/Common/AssetUtils.h>
  11. #include <Atom/RPI.Reflect/Asset/AssetUtils.h>
  12. #include <AtomLyIntegration/CommonFeatures/Grid/GridComponentBus.h>
  13. #include <AtomLyIntegration/CommonFeatures/Grid/GridComponentConfig.h>
  14. #include <AtomLyIntegration/CommonFeatures/Grid/GridComponentConstants.h>
  15. #include <AtomLyIntegration/CommonFeatures/ImageBasedLights/ImageBasedLightComponentBus.h>
  16. #include <AtomLyIntegration/CommonFeatures/ImageBasedLights/ImageBasedLightComponentConstants.h>
  17. #include <AtomLyIntegration/CommonFeatures/Material/MaterialComponentBus.h>
  18. #include <AtomLyIntegration/CommonFeatures/Material/MaterialComponentConstants.h>
  19. #include <AtomLyIntegration/CommonFeatures/Mesh/MeshComponentBus.h>
  20. #include <AtomLyIntegration/CommonFeatures/Mesh/MeshComponentConstants.h>
  21. #include <AtomLyIntegration/CommonFeatures/PostProcess/DisplayMapper/DisplayMapperComponentBus.h>
  22. #include <AtomLyIntegration/CommonFeatures/PostProcess/DisplayMapper/DisplayMapperComponentConstants.h>
  23. #include <AtomLyIntegration/CommonFeatures/PostProcess/ExposureControl/ExposureControlBus.h>
  24. #include <AtomLyIntegration/CommonFeatures/PostProcess/ExposureControl/ExposureControlComponentConstants.h>
  25. #include <AtomLyIntegration/CommonFeatures/PostProcess/PostFxLayerComponentConstants.h>
  26. #include <AtomLyIntegration/CommonFeatures/SkyBox/HDRiSkyboxBus.h>
  27. #include <AtomToolsFramework/EntityPreviewViewport/EntityPreviewViewportSettingsRequestBus.h>
  28. #include <AtomToolsFramework/Graph/GraphDocumentRequestBus.h>
  29. #include <AtomToolsFramework/Util/Util.h>
  30. #include <AzFramework/Components/NonUniformScaleComponent.h>
  31. #include <AzFramework/Components/TransformComponent.h>
  32. #include <Window/MaterialCanvasViewportContent.h>
  33. namespace MaterialCanvas
  34. {
  35. MaterialCanvasViewportContent::MaterialCanvasViewportContent(
  36. const AZ::Crc32& toolId,
  37. AtomToolsFramework::RenderViewportWidget* widget,
  38. AZStd::shared_ptr<AzFramework::EntityContext> entityContext)
  39. : AtomToolsFramework::EntityPreviewViewportContent(toolId, widget, entityContext)
  40. {
  41. // Configure tone mapper
  42. m_postFxEntity = CreateEntity(
  43. "PostFxEntity",
  44. { AZ::Render::PostFxLayerComponentTypeId, AZ::Render::DisplayMapperComponentTypeId, AZ::Render::ExposureControlComponentTypeId,
  45. azrtti_typeid<AzFramework::TransformComponent>() });
  46. // Create IBL
  47. m_environmentEntity = CreateEntity(
  48. "EnvironmentEntity",
  49. { AZ::Render::HDRiSkyboxComponentTypeId, AZ::Render::ImageBasedLightComponentTypeId,
  50. azrtti_typeid<AzFramework::TransformComponent>() });
  51. // Create model
  52. m_objectEntity = CreateEntity(
  53. "ObjectEntity",
  54. { AZ::Render::MeshComponentTypeId, AZ::Render::MaterialComponentTypeId, azrtti_typeid<AzFramework::TransformComponent>() });
  55. // Create shadow catcher
  56. m_shadowCatcherEntity = CreateEntity(
  57. "ShadowCatcherEntity",
  58. { AZ::Render::MeshComponentTypeId, AZ::Render::MaterialComponentTypeId, azrtti_typeid<AzFramework::TransformComponent>(),
  59. azrtti_typeid<AzFramework::NonUniformScaleComponent>() });
  60. AZ::NonUniformScaleRequestBus::Event(
  61. GetShadowCatcherEntityId(), &AZ::NonUniformScaleRequests::SetScale, AZ::Vector3(100, 100, 1.0));
  62. // Avoid z-fighting with the cube model when double-sided rendering is enabled
  63. AZ::TransformBus::Event(
  64. GetShadowCatcherEntityId(), &AZ::TransformInterface::SetWorldZ, -0.01f);
  65. AZ::Render::MeshComponentRequestBus::Event(
  66. GetShadowCatcherEntityId(), &AZ::Render::MeshComponentRequestBus::Events::SetModelAssetId,
  67. AZ::RPI::AssetUtils::GetAssetIdForProductPath("materialeditor/viewportmodels/plane_1x1.fbx.azmodel"));
  68. AZ::Render::MaterialComponentRequestBus::Event(
  69. GetShadowCatcherEntityId(), &AZ::Render::MaterialComponentRequestBus::Events::SetMaterialAssetId,
  70. AZ::Render::DefaultMaterialAssignmentId,
  71. AZ::RPI::AssetUtils::GetAssetIdForProductPath("materials/special/shadowcatcher.azmaterial"));
  72. // Create grid
  73. m_gridEntity = CreateEntity("GridEntity", { AZ::Render::GridComponentTypeId, azrtti_typeid<AzFramework::TransformComponent>() });
  74. AZ::Render::GridComponentRequestBus::Event(
  75. GetGridEntityId(),
  76. [&](AZ::Render::GridComponentRequests* gridComponentRequests)
  77. {
  78. gridComponentRequests->SetSize(4.0f);
  79. gridComponentRequests->SetAxisColor(AZ::Color(0.1f, 0.1f, 0.1f, 1.0f));
  80. gridComponentRequests->SetPrimaryColor(AZ::Color(0.1f, 0.1f, 0.1f, 1.0f));
  81. gridComponentRequests->SetSecondaryColor(AZ::Color(0.1f, 0.1f, 0.1f, 1.0f));
  82. });
  83. AtomToolsFramework::AtomToolsDocumentNotificationBus::Handler::BusConnect(m_toolId);
  84. AtomToolsFramework::GraphDocumentNotificationBus::Handler::BusConnect(m_toolId);
  85. OnDocumentOpened(AZ::Uuid::CreateNull());
  86. }
  87. MaterialCanvasViewportContent::~MaterialCanvasViewportContent()
  88. {
  89. AtomToolsFramework::GraphDocumentNotificationBus::Handler::BusDisconnect();
  90. AtomToolsFramework::AtomToolsDocumentNotificationBus::Handler::BusDisconnect();
  91. }
  92. AZ::EntityId MaterialCanvasViewportContent::GetObjectEntityId() const
  93. {
  94. return m_objectEntity ? m_objectEntity->GetId() : AZ::EntityId();
  95. }
  96. AZ::EntityId MaterialCanvasViewportContent::GetEnvironmentEntityId() const
  97. {
  98. return m_environmentEntity ? m_environmentEntity->GetId() : AZ::EntityId();
  99. }
  100. AZ::EntityId MaterialCanvasViewportContent::GetPostFxEntityId() const
  101. {
  102. return m_postFxEntity ? m_postFxEntity->GetId() : AZ::EntityId();
  103. }
  104. AZ::EntityId MaterialCanvasViewportContent::GetShadowCatcherEntityId() const
  105. {
  106. return m_shadowCatcherEntity ? m_shadowCatcherEntity->GetId() : AZ::EntityId();
  107. }
  108. AZ::EntityId MaterialCanvasViewportContent::GetGridEntityId() const
  109. {
  110. return m_gridEntity ? m_gridEntity->GetId() : AZ::EntityId();
  111. }
  112. void MaterialCanvasViewportContent::OnDocumentClosed([[maybe_unused]] const AZ::Uuid& documentId)
  113. {
  114. AZ::Render::MaterialComponentRequestBus::Event(
  115. GetObjectEntityId(), &AZ::Render::MaterialComponentRequestBus::Events::SetMaterialAssetIdOnDefaultSlot, AZ::Data::AssetId());
  116. }
  117. void MaterialCanvasViewportContent::OnDocumentOpened([[maybe_unused]] const AZ::Uuid& documentId)
  118. {
  119. m_lastOpenedDocumentId = documentId;
  120. ApplyMaterial(documentId);
  121. }
  122. void MaterialCanvasViewportContent::OnCompileGraphStarted(const AZ::Uuid& documentId)
  123. {
  124. if (m_lastOpenedDocumentId == documentId &&
  125. AtomToolsFramework::GetSettingsValue("/O3DE/Atom/MaterialCanvas/Viewport/ClearMaterialOnCompileGraphStarted", true))
  126. {
  127. ApplyMaterial({});
  128. }
  129. }
  130. void MaterialCanvasViewportContent::OnCompileGraphCompleted(const AZ::Uuid& documentId)
  131. {
  132. if (m_lastOpenedDocumentId == documentId)
  133. {
  134. ApplyMaterial(documentId);
  135. }
  136. }
  137. void MaterialCanvasViewportContent::OnCompileGraphFailed(const AZ::Uuid& documentId)
  138. {
  139. if (m_lastOpenedDocumentId == documentId &&
  140. AtomToolsFramework::GetSettingsValue("/O3DE/Atom/MaterialCanvas/Viewport/ClearMaterialOnCompileGraphFailed", true))
  141. {
  142. ApplyMaterial({});
  143. }
  144. }
  145. void MaterialCanvasViewportContent::OnViewportSettingsChanged()
  146. {
  147. AtomToolsFramework::EntityPreviewViewportContent::OnViewportSettingsChanged();
  148. AtomToolsFramework::EntityPreviewViewportSettingsRequestBus::Event(
  149. m_toolId,
  150. [this](AtomToolsFramework::EntityPreviewViewportSettingsRequestBus::Events* viewportRequests)
  151. {
  152. const auto& modelPreset = viewportRequests->GetModelPreset();
  153. const auto& lightingPreset = viewportRequests->GetLightingPreset();
  154. AZ::Render::MeshComponentRequestBus::Event(
  155. GetObjectEntityId(),
  156. [&](AZ::Render::MeshComponentRequests* meshComponentRequests)
  157. {
  158. if (meshComponentRequests->GetModelAsset() != modelPreset.m_modelAsset)
  159. {
  160. meshComponentRequests->SetModelAsset(modelPreset.m_modelAsset);
  161. }
  162. });
  163. AZ::Render::HDRiSkyboxRequestBus::Event(
  164. GetEnvironmentEntityId(),
  165. [&](AZ::Render::HDRiSkyboxRequests* skyboxComponentRequests)
  166. {
  167. skyboxComponentRequests->SetExposure(lightingPreset.m_skyboxExposure);
  168. skyboxComponentRequests->SetCubemapAsset(
  169. viewportRequests->GetAlternateSkyboxEnabled() ? lightingPreset.m_alternateSkyboxImageAsset
  170. : lightingPreset.m_skyboxImageAsset);
  171. });
  172. AZ::Render::MeshComponentRequestBus::Event(
  173. GetShadowCatcherEntityId(), &AZ::Render::MeshComponentRequestBus::Events::SetVisibility,
  174. viewportRequests->GetShadowCatcherEnabled());
  175. AZ::Render::MaterialComponentRequestBus::Event(
  176. GetShadowCatcherEntityId(), &AZ::Render::MaterialComponentRequestBus::Events::SetPropertyValue,
  177. AZ::Render::DefaultMaterialAssignmentId, "settings.opacity", AZStd::any(lightingPreset.m_shadowCatcherOpacity));
  178. AZ::Render::DisplayMapperComponentRequestBus::Event(
  179. GetPostFxEntityId(), &AZ::Render::DisplayMapperComponentRequestBus::Events::SetDisplayMapperOperationType,
  180. viewportRequests->GetDisplayMapperOperationType());
  181. AZ::Render::GridComponentRequestBus::Event(
  182. GetGridEntityId(), &AZ::Render::GridComponentRequestBus::Events::SetSize,
  183. viewportRequests->GetGridEnabled() ? 4.0f : 0.0f);
  184. });
  185. }
  186. void MaterialCanvasViewportContent::ApplyMaterial(const AZ::Uuid& documentId)
  187. {
  188. AZ::Data::AssetId assetId;
  189. AZStd::vector<AZStd::string> generatedFiles;
  190. AtomToolsFramework::GraphDocumentRequestBus::EventResult(
  191. generatedFiles, documentId, &AtomToolsFramework::GraphDocumentRequestBus::Events::GetGeneratedFilePaths);
  192. for (const auto& generatedFile : generatedFiles)
  193. {
  194. if (generatedFile.ends_with(".material"))
  195. {
  196. if (auto assetIdOutcome = AZ::RPI::AssetUtils::MakeAssetId(generatedFile, 0))
  197. {
  198. assetId = assetIdOutcome.GetValue();
  199. break;
  200. }
  201. }
  202. }
  203. // When material canvas generates assets, material input property values are assigned as default values in the material type instead
  204. // of overridden values in the material. The generated material asset is empty except for a single field referencing the material
  205. // type. Because the material asset never changes, it won't be reprocessed by the AP or treated as a unique asset in the asset
  206. // system. We force the viewport to create a unique material instance every time a change needs to be reflected in material canvas.
  207. AZ::Render::MaterialAssignment materialAssignment;
  208. materialAssignment.m_materialAsset.Create(assetId, AZ::Data::AssetLoadBehavior::PreLoad);
  209. materialAssignment.m_materialInstanceMustBeUnique = true;
  210. AZ::Render::MaterialAssignmentMap materialAssignmentMap;
  211. materialAssignmentMap.emplace(AZ::Render::DefaultMaterialAssignmentId, materialAssignment);
  212. AZ::Render::MaterialComponentRequestBus::Event(
  213. GetObjectEntityId(), &AZ::Render::MaterialComponentRequestBus::Events::SetMaterialMap, materialAssignmentMap);
  214. }
  215. } // namespace MaterialCanvas