Browse Source

merging dev

Signed-off-by: antonmic <[email protected]>
antonmic 3 years ago
parent
commit
fc7ece1f22
100 changed files with 2399 additions and 1202 deletions
  1. 4 3
      Gem/Code/Source/AtomSampleViewerSystemComponent.cpp
  2. 1 1
      Gem/Code/Source/Automation/ScriptReporter.cpp
  3. 1 0
      Gem/Code/Source/Automation/ScriptableImGui.h
  4. 10 0
      Gem/Code/Source/CommonSampleComponentBase.cpp
  5. 127 125
      Gem/Code/Source/CommonSampleComponentBase.h
  6. 5 1
      Gem/Code/Source/DynamicMaterialTestComponent.cpp
  7. 60 7
      Gem/Code/Source/EntityLatticeTestComponent.cpp
  8. 21 0
      Gem/Code/Source/EntityLatticeTestComponent.h
  9. 0 103
      Gem/Code/Source/HighInstanceExampleComponent.h
  10. 1 1
      Gem/Code/Source/LightCullingExampleComponent.cpp
  11. 0 3
      Gem/Code/Source/MeshExampleComponent.h
  12. 66 0
      Gem/Code/Source/Performance/100KDraw_10KDrawable_MultiView_ExampleComponent.cpp
  13. 34 0
      Gem/Code/Source/Performance/100KDraw_10KDrawable_MultiView_ExampleComponent.h
  14. 60 0
      Gem/Code/Source/Performance/100KDrawable_SingleView_ExampleComponent.cpp
  15. 33 0
      Gem/Code/Source/Performance/100KDrawable_SingleView_ExampleComponent.h
  16. 211 47
      Gem/Code/Source/Performance/HighInstanceExampleComponent.cpp
  17. 179 0
      Gem/Code/Source/Performance/HighInstanceExampleComponent.h
  18. 0 11
      Gem/Code/Source/Platform/Android/HighInstanceTestComponent_Traits_Platform.h
  19. 0 1
      Gem/Code/Source/Platform/Android/atomsampleviewer_android_files.cmake
  20. 1 1
      Gem/Code/Source/Platform/Linux/EntityLatticeTestComponent_Traits_Platform.h
  21. 0 11
      Gem/Code/Source/Platform/Linux/HighInstanceTestComponent_Traits_Platform.h
  22. 0 1
      Gem/Code/Source/Platform/Linux/atomsampleviewer_linux_files.cmake
  23. 1 1
      Gem/Code/Source/Platform/Mac/EntityLatticeTestComponent_Traits_Platform.h
  24. 0 11
      Gem/Code/Source/Platform/Mac/HighInstanceTestComponent_Traits_Platform.h
  25. 0 1
      Gem/Code/Source/Platform/Mac/atomsampleviewer_mac_files.cmake
  26. 1 1
      Gem/Code/Source/Platform/Windows/EntityLatticeTestComponent_Traits_Platform.h
  27. 0 11
      Gem/Code/Source/Platform/Windows/HighInstanceTestComponent_Traits_Platform.h
  28. 0 1
      Gem/Code/Source/Platform/Windows/atomsampleviewer_windows_files.cmake
  29. 0 11
      Gem/Code/Source/Platform/iOS/HighInstanceTestComponent_Traits_Platform.h
  30. 0 1
      Gem/Code/Source/Platform/iOS/atomsampleviewer_ios_files.cmake
  31. 436 0
      Gem/Code/Source/RenderTargetTextureExampleComponent.cpp
  32. 101 0
      Gem/Code/Source/RenderTargetTextureExampleComponent.h
  33. 26 9
      Gem/Code/Source/SampleComponentManager.cpp
  34. 1 1
      Gem/Code/Source/SampleComponentManager.h
  35. 112 105
      Gem/Code/Source/Utils/ImGuiHistogramQueue.cpp
  36. 59 55
      Gem/Code/Source/Utils/ImGuiHistogramQueue.h
  37. 8 2
      Gem/Code/atomsampleviewergem_private_files.cmake
  38. 16 34
      Materials/Decal/airship_nose_number_decal.material
  39. 16 34
      Materials/Decal/airship_symbol_decal.material
  40. 16 34
      Materials/Decal/airship_tail_01_decal.material
  41. 16 34
      Materials/Decal/airship_tail_02_decal.material
  42. 16 34
      Materials/Decal/am_mud_decal.material
  43. 16 34
      Materials/Decal/am_road_dust_decal.material
  44. 16 34
      Materials/Decal/brushstoke_01_decal.material
  45. 15 31
      Materials/Decal/scorch_01_decal.material
  46. 2 3
      Materials/DefaultPBR.material
  47. 3 6
      Materials/DefaultPBRTransparent.material
  48. 14 19
      Materials/DiffuseGIExample/blue.material
  49. 14 19
      Materials/DiffuseGIExample/green.material
  50. 14 19
      Materials/DiffuseGIExample/red.material
  51. 14 19
      Materials/DiffuseGIExample/white.material
  52. 14 19
      Materials/DiffuseGIExample/yellow.material
  53. 9 13
      Materials/DynamicMaterialTest/EmissiveWithCppFunctors.material
  54. 9 13
      Materials/DynamicMaterialTest/EmissiveWithLuaFunctors.material
  55. 17 25
      Materials/HotReloadTest/TestData/VariantSelection_FullyBaked.material
  56. 16 24
      Materials/HotReloadTest/TestData/VariantSelection_Root.material
  57. 9 13
      Materials/MinimalPBR/MinimalPBR_BlueMetal.material
  58. 0 2
      Materials/MinimalPBR/MinimalPBR_Default.material
  59. 8 12
      Materials/MinimalPBR/MinimalPBR_RedDielectric.material
  60. 15 26
      Materials/SSRExample/Cube.material
  61. 13 25
      Materials/SSRExample/GroundPlaneAluminum.material
  62. 13 27
      Materials/SSRExample/GroundPlaneChrome.material
  63. 12 24
      Materials/SSRExample/GroundPlaneMirror.material
  64. 5 15
      Materials/SSRExample/GroundPlaneWood.material
  65. 20 31
      Materials/SSRExample/ShaderBall.material
  66. 4 7
      Materials/TransparentDoubleSide.material
  67. 24 0
      Materials/Types/MinimalMultilayerExample.material
  68. 61 0
      Materials/Types/MinimalMultilayerPBR.materialtype
  69. 163 0
      Materials/Types/MinimalMultilayerPBR_ForwardPass.azsl
  70. 46 0
      Materials/Types/MinimalMultilayerPBR_ForwardPass.shader
  71. 75 0
      Materials/Types/MinimalMultilayerPBR_LayerProperties.json
  72. 5 2
      Scripts/DynamicMaterialTest.bv.lua
  73. 2 2
      Scripts/ExpectedScreenshots/Checkerboard/frame1.png
  74. 2 2
      Scripts/ExpectedScreenshots/DynamicMaterialTest/01_defaultsetup_A.png
  75. 2 2
      Scripts/ExpectedScreenshots/DynamicMaterialTest/01_defaultsetup_B.png
  76. 2 2
      Scripts/ExpectedScreenshots/DynamicMaterialTest/02_manyentities_A.png
  77. 2 2
      Scripts/ExpectedScreenshots/DynamicMaterialTest/02_manyentities_B.png
  78. 3 0
      Scripts/ExpectedScreenshots/MinimalPBR/minimalmultilayerexample.png
  79. 2 2
      Scripts/ExpectedScreenshots/PassTree/albedo.png
  80. 2 2
      Scripts/ExpectedScreenshots/PassTree/brdf.png
  81. 2 2
      Scripts/ExpectedScreenshots/PassTree/depthStencilMs.png
  82. 2 2
      Scripts/ExpectedScreenshots/PassTree/depthStencilResolve.png
  83. 2 2
      Scripts/ExpectedScreenshots/PassTree/linearDepth.png
  84. 2 2
      Scripts/ExpectedScreenshots/PassTree/specularResolved.png
  85. 3 0
      Scripts/ExpectedScreenshots/RenderTargetTexture/screenshot_1.png
  86. 3 0
      Scripts/ExpectedScreenshots/RenderTargetTexture/screenshot_2.png
  87. 2 2
      Scripts/ExpectedScreenshots/SceneReloadSoakTest/screenshot.png
  88. 2 2
      Scripts/ExpectedScreenshots/ShadowedSponza/directional_filter.png
  89. 2 2
      Scripts/ExpectedScreenshots/ShadowedSponza/directional_nofilter.png
  90. 2 2
      Scripts/ExpectedScreenshots/ShadowedSponza/initial.png
  91. 2 2
      Scripts/ExpectedScreenshots/ShadowedSponza/spot_filter.png
  92. 2 2
      Scripts/ExpectedScreenshots/ShadowedSponza/spot_nofilter.png
  93. 2 2
      Scripts/ExpectedScreenshots/StandardMultilayerPBR/002_parallaxpdo.png
  94. 2 2
      Scripts/ExpectedScreenshots/StandardPBR/015_subsurfacescattering_transmission.png
  95. 2 2
      Scripts/ExpectedScreenshots/StandardPBR/015_subsurfacescattering_transmission_thin.png
  96. 2 2
      Scripts/ExpectedScreenshots/msaa_rpi/screenshot_msaa4x_cylinder.png
  97. 10 0
      Scripts/MaterialScreenshotTests.bv.lua
  98. 12 1
      Scripts/PassTree.bv.lua
  99. 39 0
      Scripts/RenderTargetTexture.bv.lua
  100. 2 1
      Scripts/_AutomatedPeriodicBenchmarkSuite_.bv.lua

+ 4 - 3
Gem/Code/Source/AtomSampleViewerSystemComponent.cpp

@@ -59,6 +59,10 @@ namespace AtomSampleViewer
         StacksShaderInputFunctor::Reflect(context);
 
         ImageComparisonConfig::Reflect(context);
+
+        // Abstract base components is used by multiple components and needs to be reflected in a single location.
+        CommonSampleComponentBase::Reflect(context);
+        EntityLatticeTestComponent::Reflect(context);
     }
 
     void AtomSampleViewerSystemComponent::PerfMetrics::Reflect(AZ::ReflectContext* context)
@@ -72,9 +76,6 @@ namespace AtomSampleViewer
                 ->Field("SecondsToRender", &PerfMetrics::m_timeToFirstRenderSeconds)
                 ;
         }
-
-        // Abstract base component is used by multiple components and needs to be reflected in a single location.
-        EntityLatticeTestComponent::Reflect(context);
     }
 
 

+ 1 - 1
Gem/Code/Source/Automation/ScriptReporter.cpp

@@ -1182,7 +1182,7 @@ namespace AtomSampleViewer
         memcpy(buffer.data() + bufferSize, actualScreenshot.GetBuffer().data(), bufferSize);
         memcpy(buffer.data() + bufferSize * 2, diffBuffer.data(), bufferSize);
 
-        PngFile imageDiff = PngFile::Create(RHI::Size(officialBaseline.GetWidth(), officialBaseline.GetHeight() * 3, 1), RHI::Format::R8G8B8A8_UNORM, buffer);
+        PngFile imageDiff = PngFile::Create(AZ::RHI::Size(officialBaseline.GetWidth(), officialBaseline.GetHeight() * 3, 1), AZ::RHI::Format::R8G8B8A8_UNORM, buffer);
         imageDiff.Save(filePath);
     }
 

+ 1 - 0
Gem/Code/Source/Automation/ScriptableImGui.h

@@ -12,6 +12,7 @@
 #include <AzCore/std/string/string.h>
 #include <AzCore/std/containers/unordered_map.h>
 #include <AzCore/Math/Vector3.h>
+#include <AzCore/Memory/SystemAllocator.h>
 #include <imgui/imgui.h>
 
 #define SCRIPTABLE_IMGUI

+ 10 - 0
Gem/Code/Source/CommonSampleComponentBase.cpp

@@ -21,6 +21,16 @@ namespace AtomSampleViewer
     using namespace AZ;
     using namespace RPI;
 
+    void CommonSampleComponentBase::Reflect(ReflectContext* context)
+    {
+        if (SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context))
+        {
+            serializeContext->Class<CommonSampleComponentBase, Component>()
+                ->Version(0)
+                ;
+        }
+    }
+
     bool CommonSampleComponentBase::ReadInConfig(const ComponentConfig* baseConfig)
     {
         m_scene = RPI::RPISystemInterface::Get()->GetSceneByName(AZ::Name("RPI"));

+ 127 - 125
Gem/Code/Source/CommonSampleComponentBase.h

@@ -1,125 +1,127 @@
-/*
- * Copyright (c) Contributors to the Open 3D Engine Project.
- * For complete copyright and license terms please see the LICENSE at the root of this distribution.
- *
- * SPDX-License-Identifier: Apache-2.0 OR MIT
- *
- */
-
-#pragma once
-
-#include <AzCore/Component/Component.h>
-#include <AzCore/Component/TransformBus.h>
-#include <AzCore/Component/EntityBus.h>
-#include <AzFramework/Entity/EntityContextBus.h>
-#include <Atom/Feature/Mesh/MeshFeatureProcessorInterface.h>
-#include <Atom/Feature/Utils/LightingPreset.h>
-#include <Atom/Feature/SkyBox/SkyBoxFeatureProcessorInterface.h>
-#include <Atom/Feature/PostProcess/PostProcessFeatureProcessorInterface.h>
-#include <Atom/Feature/ImageBasedLights/ImageBasedLightFeatureProcessorInterface.h>
-#include <Atom/Feature/CoreLights/DirectionalLightFeatureProcessorInterface.h>
-#include <Atom/Utils/AssetCollectionAsyncLoader.h>
-
-#include <Utils/ImGuiProgressList.h>
-
-namespace AtomSampleViewer
-{
-    class CommonSampleComponentBase
-        : public AZ::Component
-        , public AZ::TransformNotificationBus::MultiHandler
-        , public AZ::EntityBus::MultiHandler
-    {
-    public:
-        AZ_TYPE_INFO(MaterialHotReloadTestComponent, "{7EECDF09-B774-46C1-AD6E-060CE5717C05}");
-
-        // AZ::Component overrides...
-        bool ReadInConfig(const AZ::ComponentConfig* baseConfig) override;
-
-    protected:
-        //! Init and shut down should be called in derived components' Activate() and Deactivate().
-        //! @param loadDefaultLightingPresets if true, it will scan all lighting presets in the project and load them.
-        void InitLightingPresets(bool loadDefaultLightingPresets = false);
-        void ShutdownLightingPresets();
-
-        //! Add a drop down list to select lighting preset for this sample.
-        //! Lighting presets must be loaded before calling this function, otherwise the list will be hide.
-        //! It should be called between ImGui::Begin() and ImGui::End().
-        //! e.g. Calling it between ImGuiSidebar::Begin() and ImGuiSidebar::End() will embed this list into the side bar.
-        void ImGuiLightingPreset();
-
-        //! Load lighting presets from an asset.
-        //! It will clear any presets loaded previously.
-        void LoadLightingPresetsFromAsset(const AZStd::string& assetPath);
-
-        //! Load lighting presets from an asset.
-        //! Append the presets to the current existing presets.
-        void AppendLightingPresetsFromAsset(const AZStd::string& assetPath);
-
-        //! Clear all lighting presets.
-        void ClearLightingPresets();
-
-        //! Reset internal scene related data
-        void ResetScene();
-
-        //! Apply lighting presets to the scene.
-        //! Derived samples can override this function to have custom behaviors.
-        virtual void OnLightingPresetSelected(const AZ::Render::LightingPreset& preset, bool useAltSkybox);
-
-        //! Return the AtomSampleViewer EntityContextId, retrieved from the ComponentConfig
-        AzFramework::EntityContextId GetEntityContextId() const;
-
-        //! Return the AtomSampleViewer camera EntityId, retrieved from the ComponentConfig
-        AZ::EntityId GetCameraEntityId() const;
-
-        AZ::Render::MeshFeatureProcessorInterface* GetMeshFeatureProcessor() const;
-
-        void OnLightingPresetEntityShutdown(const AZ::EntityId& entityId);
-
-        // Preload assets 
-        void PreloadAssets(const AZStd::vector<AZ::AssetCollectionAsyncLoader::AssetToLoadInfo>& assetList);
-
-        //! Async asset load
-        AZ::AssetCollectionAsyncLoader m_assetLoadManager;
-
-        //! Showing the loading progress of preload assets
-        ImGuiProgressList m_imguiProgressList;
-
-        // The callback might be called more than one time if there are more than one asset are ready in one frame.
-        // Use this flag to prevent OnAllAssetsReadyActivate be called more than one time.
-        bool m_isAllAssetsReady = false;
-
-        AZStd::string m_sampleName;
-
-        AZ::RPI::Scene* m_scene = nullptr;
-
-    private:
-        // AZ::TransformNotificationBus::MultiHandler overrides...
-        void OnTransformChanged(const AZ::Transform&, const AZ::Transform&) override;
-
-        // virtual call back function which is called when all preloaded assets are loaded.
-        virtual void OnAllAssetsReadyActivate() {};
-
-        AzFramework::EntityContextId m_entityContextId;
-        AZ::EntityId m_cameraEntityId;
-        mutable AZ::Render::MeshFeatureProcessorInterface* m_meshFeatureProcessor = nullptr;
-
-        //! All loaded lighting presets.
-        AZStd::vector<AZ::Render::LightingPreset> m_lightingPresets;
-
-        //! Lights created by lighting presets.
-        AZStd::vector<AZ::Render::DirectionalLightFeatureProcessorInterface::LightHandle> m_lightHandles;
-
-        //! Post process entity to handle ExposureControlSettings.
-        AZ::Entity* m_postProcessEntity = nullptr;
-
-        //! Dirty flag is set to true when m_lightingPresets is modified.
-        bool m_lightingPresetsDirty = true;
-
-        //! Current active lighting preset.
-        constexpr static int32_t InvalidLightingPresetIndex = -1;
-        int32_t m_currentLightingPresetIndex = InvalidLightingPresetIndex;
-        bool m_useAlternateSkybox = false; //!< LightingPresets have an alternate skybox that can be used, when this is true. This is usually a blurred version of the primary skybox.
-
-    };
-
-} // namespace AtomSampleViewer
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#pragma once
+
+#include <AzCore/Component/Component.h>
+#include <AzCore/Component/TransformBus.h>
+#include <AzCore/Component/EntityBus.h>
+#include <AzFramework/Entity/EntityContextBus.h>
+#include <Atom/Feature/Mesh/MeshFeatureProcessorInterface.h>
+#include <Atom/Feature/Utils/LightingPreset.h>
+#include <Atom/Feature/SkyBox/SkyBoxFeatureProcessorInterface.h>
+#include <Atom/Feature/PostProcess/PostProcessFeatureProcessorInterface.h>
+#include <Atom/Feature/ImageBasedLights/ImageBasedLightFeatureProcessorInterface.h>
+#include <Atom/Feature/CoreLights/DirectionalLightFeatureProcessorInterface.h>
+#include <Atom/Utils/AssetCollectionAsyncLoader.h>
+
+#include <Utils/ImGuiProgressList.h>
+
+namespace AtomSampleViewer
+{
+    class CommonSampleComponentBase
+        : public AZ::Component
+        , public AZ::TransformNotificationBus::MultiHandler
+        , public AZ::EntityBus::MultiHandler
+    {
+    public:
+        AZ_TYPE_INFO(CommonSampleComponentBase, "{7EECDF09-B774-46C1-AD6E-060CE5717C05}");
+
+        static void Reflect(AZ::ReflectContext* context);
+
+        // AZ::Component overrides...
+        bool ReadInConfig(const AZ::ComponentConfig* baseConfig) override;
+
+    protected:
+        //! Init and shut down should be called in derived components' Activate() and Deactivate().
+        //! @param loadDefaultLightingPresets if true, it will scan all lighting presets in the project and load them.
+        void InitLightingPresets(bool loadDefaultLightingPresets = false);
+        void ShutdownLightingPresets();
+
+        //! Add a drop down list to select lighting preset for this sample.
+        //! Lighting presets must be loaded before calling this function, otherwise the list will be hide.
+        //! It should be called between ImGui::Begin() and ImGui::End().
+        //! e.g. Calling it between ImGuiSidebar::Begin() and ImGuiSidebar::End() will embed this list into the side bar.
+        void ImGuiLightingPreset();
+
+        //! Load lighting presets from an asset.
+        //! It will clear any presets loaded previously.
+        void LoadLightingPresetsFromAsset(const AZStd::string& assetPath);
+
+        //! Load lighting presets from an asset.
+        //! Append the presets to the current existing presets.
+        void AppendLightingPresetsFromAsset(const AZStd::string& assetPath);
+
+        //! Clear all lighting presets.
+        void ClearLightingPresets();
+
+        //! Reset internal scene related data
+        void ResetScene();
+
+        //! Apply lighting presets to the scene.
+        //! Derived samples can override this function to have custom behaviors.
+        virtual void OnLightingPresetSelected(const AZ::Render::LightingPreset& preset, bool useAltSkybox);
+
+        //! Return the AtomSampleViewer EntityContextId, retrieved from the ComponentConfig
+        AzFramework::EntityContextId GetEntityContextId() const;
+
+        //! Return the AtomSampleViewer camera EntityId, retrieved from the ComponentConfig
+        AZ::EntityId GetCameraEntityId() const;
+
+        AZ::Render::MeshFeatureProcessorInterface* GetMeshFeatureProcessor() const;
+
+        void OnLightingPresetEntityShutdown(const AZ::EntityId& entityId);
+
+        // Preload assets 
+        void PreloadAssets(const AZStd::vector<AZ::AssetCollectionAsyncLoader::AssetToLoadInfo>& assetList);
+
+        //! Async asset load
+        AZ::AssetCollectionAsyncLoader m_assetLoadManager;
+
+        //! Showing the loading progress of preload assets
+        ImGuiProgressList m_imguiProgressList;
+
+        // The callback might be called more than one time if there are more than one asset are ready in one frame.
+        // Use this flag to prevent OnAllAssetsReadyActivate be called more than one time.
+        bool m_isAllAssetsReady = false;
+
+        AZStd::string m_sampleName;
+
+        AZ::RPI::Scene* m_scene = nullptr;
+
+    private:
+        // AZ::TransformNotificationBus::MultiHandler overrides...
+        void OnTransformChanged(const AZ::Transform&, const AZ::Transform&) override;
+
+        // virtual call back function which is called when all preloaded assets are loaded.
+        virtual void OnAllAssetsReadyActivate() {};
+
+        AzFramework::EntityContextId m_entityContextId;
+        AZ::EntityId m_cameraEntityId;
+        mutable AZ::Render::MeshFeatureProcessorInterface* m_meshFeatureProcessor = nullptr;
+
+        //! All loaded lighting presets.
+        AZStd::vector<AZ::Render::LightingPreset> m_lightingPresets;
+
+        //! Lights created by lighting presets.
+        AZStd::vector<AZ::Render::DirectionalLightFeatureProcessorInterface::LightHandle> m_lightHandles;
+
+        //! Post process entity to handle ExposureControlSettings.
+        AZ::Entity* m_postProcessEntity = nullptr;
+
+        //! Dirty flag is set to true when m_lightingPresets is modified.
+        bool m_lightingPresetsDirty = true;
+
+        //! Current active lighting preset.
+        constexpr static int32_t InvalidLightingPresetIndex = -1;
+        int32_t m_currentLightingPresetIndex = InvalidLightingPresetIndex;
+        bool m_useAlternateSkybox = false; //!< LightingPresets have an alternate skybox that can be used, when this is true. This is usually a blurred version of the primary skybox.
+
+    };
+
+} // namespace AtomSampleViewer

+ 5 - 1
Gem/Code/Source/DynamicMaterialTestComponent.cpp

@@ -302,7 +302,11 @@ namespace AtomSampleViewer
         if (updateMaterials)
         {
             m_materialConfigs[m_currentMaterialConfig].m_updateLatticeMaterials();
-            CompileMaterials();
         }
+
+        // Even if materials weren't changed on this frame, they still might need to be compiled to apply changes
+        // from a previous frame. This could be the result of a material that was just loaded or reinitialized on
+        // the previous frame, possibly caused by a shader variant hot-loading.
+        CompileMaterials();
     }
 } // namespace AtomSampleViewer

+ 60 - 7
Gem/Code/Source/EntityLatticeTestComponent.cpp

@@ -27,6 +27,10 @@ namespace AtomSampleViewer
     using namespace RPI;
 
     constexpr int32_t s_latticeSizeMax = ENTITY_LATTEST_TEST_COMPONENT_MAX;
+    constexpr float s_spacingMax = 100.0f;
+    constexpr float s_spacingMin = 0.5f;
+    constexpr float s_entityScaleMax = 10.0f;
+    constexpr float s_entityScaleMin = 0.1f;
 
     void EntityLatticeTestComponent::Reflect(ReflectContext* context)
     {
@@ -68,8 +72,8 @@ namespace AtomSampleViewer
         // We first rotate the model by 180 degrees before translating it. This is to make it face the camera as it did
         // when the world was Y-up.
         Transform transform = Transform::CreateRotationZ(Constants::Pi);
+        m_worldAabb = AZ::Aabb::CreateNull();
 
-        static Vector3 distance(5.0f, 5.0f, 5.0f);
         for (int32_t x = 0; x < m_latticeWidth; ++x)
         {
             for (int32_t y = 0; y < m_latticeDepth; ++y)
@@ -77,12 +81,14 @@ namespace AtomSampleViewer
                 for (int32_t z = 0; z < m_latticeHeight; ++z)
                 {
                     Vector3 position(
-                        static_cast<float>(x) * distance.GetX(),
-                        static_cast<float>(y) * distance.GetY(),
-                        static_cast<float>(z) * distance.GetZ());
+                        static_cast<float>(x) * m_spacingX,
+                        static_cast<float>(y) * m_spacingY,
+                        static_cast<float>(z) * m_spacingZ);
 
                     transform.SetTranslation(position);
+                    transform.SetUniformScale(m_entityScale);
                     CreateLatticeInstance(transform);
+                    m_worldAabb.AddPoint(transform.GetTranslation());
                 }
             }
         }
@@ -94,11 +100,33 @@ namespace AtomSampleViewer
         return m_latticeWidth * m_latticeHeight * m_latticeDepth;
     }
 
+    AZ::Aabb EntityLatticeTestComponent::GetLatticeAabb() const
+    {
+        return m_worldAabb;
+    }
+
     void EntityLatticeTestComponent::SetLatticeDimensions(uint32_t width, uint32_t depth, uint32_t height)
     {
-        m_latticeWidth = GetClamp<int32_t>(width, 1, s_latticeSizeMax);
-        m_latticeHeight = GetClamp<int32_t>(height, 1, s_latticeSizeMax);
-        m_latticeDepth = GetClamp<int32_t>(depth, 1, s_latticeSizeMax);
+        m_latticeWidth  = AZ::GetClamp<int32_t>(width, 1, s_latticeSizeMax);
+        m_latticeHeight = AZ::GetClamp<int32_t>(height, 1, s_latticeSizeMax);
+        m_latticeDepth  = AZ::GetClamp<int32_t>(depth, 1, s_latticeSizeMax);
+    }
+
+    void EntityLatticeTestComponent::SetLatticeSpacing( float spaceX, float spaceY, float spaceZ)
+    {
+        m_spacingX = AZ::GetClamp<float>(spaceX, s_spacingMin, s_spacingMax);
+        m_spacingY = AZ::GetClamp<float>(spaceY, s_spacingMin, s_spacingMax);
+        m_spacingZ = AZ::GetClamp<float>(spaceZ, s_spacingMin, s_spacingMax);
+    }
+
+    void EntityLatticeTestComponent::SetLatticeEntityScale(float scale)
+    {
+        m_entityScale = AZ::GetClamp<float>(scale, s_entityScaleMin, s_entityScaleMax);
+    }
+
+    void EntityLatticeTestComponent::SetIBLExposure(float exposure)
+    {
+        m_defaultIbl.SetExposure(exposure);
     }
 
     void EntityLatticeTestComponent::RenderImGuiLatticeControls()
@@ -118,6 +146,31 @@ namespace AtomSampleViewer
         ImGui::Text("Lattice Depth");
         latticeChanged |= ScriptableImGui::SliderInt("##LatticeDepth", &m_latticeDepth, 1, s_latticeSizeMax);
 
+        ImGui::Spacing();
+        ImGui::Separator();
+        ImGui::Spacing();
+
+        ImGui::Text("Lattice Spacing X");
+        latticeChanged |= ScriptableImGui::SliderFloat("##LatticeSpaceX", &m_spacingX, 0.5, s_spacingMax);
+
+        ImGui::Spacing();
+
+        ImGui::Text("Lattice Spacing Y");
+        latticeChanged |= ScriptableImGui::SliderFloat("##LatticeSpaceY", &m_spacingY, 0.5, s_spacingMax);
+
+        ImGui::Spacing();
+
+        ImGui::Text("Lattice Spacing Z");
+        latticeChanged |= ScriptableImGui::SliderFloat("##LatticeSpaceZ", &m_spacingZ, 0.5, s_spacingMax);
+
+        ImGui::Spacing();
+        ImGui::Separator();
+        ImGui::Spacing();
+
+        ImGui::Text("Entity Scale");
+        latticeChanged |= ScriptableImGui::SliderFloat("##EntityScale", &m_entityScale, 0.01, s_entityScaleMax);
+
+
         if (latticeChanged)
         {
             RebuildLattice();

+ 21 - 0
Gem/Code/Source/EntityLatticeTestComponent.h

@@ -12,6 +12,8 @@
 #include <Utils/Utils.h>
 #include <EntityLatticeTestComponent_Traits_Platform.h>
 
+#include <AzCore/Math/Aabb.h>
+
 struct ImGuiContext;
 
 namespace AtomSampleViewer
@@ -34,6 +36,10 @@ namespace AtomSampleViewer
         //! Returns total number of instances (width * height * depth)
         uint32_t GetInstanceCount() const;
         
+        //! Returns world space Aabb for the lattice.
+        //! The returned Aabb contains all the entity lattice positions. It does not include the mesh Aabb at each position.
+        AZ::Aabb GetLatticeAabb() const;
+
         //! Call this to render ImGui controls for controlling the size of the lattice.
         void RenderImGuiLatticeControls();
         
@@ -41,6 +47,10 @@ namespace AtomSampleViewer
         virtual void RebuildLattice();
 
         void SetLatticeDimensions(uint32_t width, uint32_t depth, uint32_t height);
+        void SetLatticeSpacing(float spaceX, float spaceY, float spaceZ);
+        void SetLatticeEntityScale(float scale);
+
+        void SetIBLExposure(float exposure);
 
     private:
 
@@ -59,10 +69,21 @@ namespace AtomSampleViewer
 
         void BuildLattice();
 
+    protected:
+        //! Contains the world space Aabb of the lattice positions. Doesn't include the mesh Aabb at each position.
+        AZ::Aabb m_worldAabb;
+
+    private:
         // These are signed to avoid casting with imgui controls.
         int32_t m_latticeWidth = ENTITY_LATTICE_TEST_COMPONENT_WIDTH;
         int32_t m_latticeHeight = ENTITY_LATTICE_TEST_COMPONENT_HEIGHT;
         int32_t m_latticeDepth = ENTITY_LATTICE_TEST_COMPONENT_DEPTH;
+
+        float m_spacingX = 5.0f;
+        float m_spacingY = 5.0f;
+        float m_spacingZ = 5.0f;
+
+        float m_entityScale = 1.0f;
         
         Utils::DefaultIBL m_defaultIbl;
     };

+ 0 - 103
Gem/Code/Source/HighInstanceExampleComponent.h

@@ -1,103 +0,0 @@
-/*
- * Copyright (c) Contributors to the Open 3D Engine Project.
- * For complete copyright and license terms please see the LICENSE at the root of this distribution.
- *
- * SPDX-License-Identifier: Apache-2.0 OR MIT
- *
- */
-
-#pragma once
-
-#include <EntityLatticeTestComponent.h>
-#include <Utils/ImGuiSidebar.h>
-#include <Utils/ImGuiAssetBrowser.h>
-#include <AzCore/Component/TickBus.h>
-
-namespace AtomSampleViewer
-{
-    /*
-        This test loads a 22x22x22 lattice of entities with randomized meshes and materials. This test is used as a simple cpu performance stress test for Atom.
-
-        The assets that are applied to the entities are chosen from the 
-        "allow-list" of models and materials.
-    */
-    class HighInstanceTestComponent final
-        : public EntityLatticeTestComponent
-        , public AZ::TickBus::Handler
-    {
-        using Base = EntityLatticeTestComponent;
-
-    public:
-        AZ_COMPONENT(HighInstanceTestComponent, "{DAA2B63B-7CC0-4696-A44F-49E53C6390B9}", EntityLatticeTestComponent);
-
-        static void Reflect(AZ::ReflectContext* context);
-
-        HighInstanceTestComponent();
-        
-        //! AZ::Component overrides...
-        void Activate() override;
-        void Deactivate() override;
-
-    private:
-        AZ_DISABLE_COPY_MOVE(HighInstanceTestComponent);
-
-        // CommonSampleComponentBase overrides...
-        void OnAllAssetsReadyActivate() override;
-
-        //! EntityLatticeTestComponent overrides...
-        void PrepareCreateLatticeInstances(uint32_t instanceCount) override;
-        void CreateLatticeInstance(const AZ::Transform& transform) override;
-        void FinalizeLatticeInstances() override;
-        void DestroyLatticeInstances() override;
-
-        void DestroyHandles();
-
-        AZ::Data::AssetId GetRandomModelId() const;
-        AZ::Data::AssetId GetRandomMaterialId() const;
-
-        void OnTick(float deltaTime, AZ::ScriptTimePoint scriptTime) override;
-
-        void ResetNoClipController();
-        void SaveCameraConfiguration();
-        void RestoreCameraConfiguration();
-        
-        struct ModelInstanceData
-        {
-            AZ::Transform m_transform;
-            AZ::Data::AssetId m_modelAssetId;
-            AZ::Data::AssetId m_materialAssetId;
-            AZ::Render::MeshFeatureProcessorInterface::MeshHandle m_meshHandle;
-        };
-
-        ImGuiSidebar m_imguiSidebar;
-        ImGuiAssetBrowser m_materialBrowser;
-        ImGuiAssetBrowser m_modelBrowser;
-        
-        AZStd::vector<ModelInstanceData> m_modelInstanceData;
-
-        struct Compare
-        {
-            bool operator()(const AZ::Data::Asset<AZ::RPI::MaterialAsset>& lhs, const AZ::Data::Asset<AZ::RPI::MaterialAsset>& rhs) const
-            {
-                if (lhs.GetId().m_guid == rhs.GetId().m_guid)
-                {
-                    return lhs.GetId().m_subId > rhs.GetId().m_subId;
-                }
-                return lhs.GetId().m_guid > rhs.GetId().m_guid;
-            }
-        };
-
-        using MaterialAssetSet = AZStd::set<AZ::Data::Asset<AZ::RPI::MaterialAsset>, Compare>;
-        MaterialAssetSet m_cachedMaterials;
-        uint32_t m_pinnedMaterialCount = 0;
-        uint32_t m_preActivateVSyncInterval = 0;
-        
-        AZStd::vector<AZStd::string> m_expandedModelList; // has models that are more expensive on the gpu
-        AZStd::vector<AZStd::string> m_simpleModelList; // Aims to keep the test cpu bottlenecked by using trivial geometry such as a cube
-        size_t m_lastPinnedModelCount = 0;
-
-        float m_originalFarClipDistance;
-        bool m_updateTransformEnabled = false;
-        bool m_useSimpleModels = true;
-    };
-} // namespace AtomSampleViewer

+ 1 - 1
Gem/Code/Source/LightCullingExampleComponent.cpp

@@ -96,7 +96,7 @@ namespace AtomSampleViewer
         m_sampleName = "LightCullingExampleComponent";
 
         // Add some initial lights to illuminate the scene
-        m_settings[(int)LightType::Point].m_numActive = 150;
+        m_settings[(int)LightType::Point].m_numActive = 10;
         m_settings[(int)LightType::Disk].m_intensity = 40.0f;
         m_settings[(int)LightType::Capsule].m_intensity = 10.0f;
     }

+ 0 - 3
Gem/Code/Source/MeshExampleComponent.h

@@ -86,9 +86,6 @@ namespace AtomSampleViewer
         static const char* CameraControllerNameTable[CameraControllerCount];
         CameraControllerType m_currentCameraControllerType = CameraControllerType::ArcBall;
 
-        // Not owned by this sample, we look this up
-        AZ::Component* m_cameraControlComponent = nullptr;
-
         AZ::Render::MeshFeatureProcessorInterface::ModelChangedEvent::Handler m_changedHandler;
         
         static constexpr float ArcballRadiusMinModifier = 0.01f;

+ 66 - 0
Gem/Code/Source/Performance/100KDraw_10KDrawable_MultiView_ExampleComponent.cpp

@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#include <Performance/100KDraw_10KDrawable_MultiView_ExampleComponent.h>
+#include <SampleComponentManager.h>
+#include <SampleComponentConfig.h>
+
+#include <AzCore/Serialization/SerializeContext.h>
+
+AZ_DECLARE_BUDGET(AtomSampleViewer);
+
+namespace AtomSampleViewer
+{
+    using namespace AZ;
+
+    void _100KDraw10KDrawableExampleComponent::Reflect(AZ::ReflectContext* context)
+    {
+        Base::Reflect(context);
+        if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
+        {
+            serializeContext->Class<_100KDraw10KDrawableExampleComponent, HighInstanceTestComponent>()
+                ->Version(0)
+                ;
+        }
+    }
+
+
+    _100KDraw10KDrawableExampleComponent::_100KDraw10KDrawableExampleComponent() 
+    {
+        m_sampleName = "100KDraw10KEntityTest";
+        InitDefaultValues(m_testParameters);
+    }
+
+    void _100KDraw10KDrawableExampleComponent::InitDefaultValues(HighInstanceTestParameters& defaultParameters)
+    {
+        defaultParameters.m_latticeSize[0] = 22;
+        defaultParameters.m_latticeSize[1] = 22;
+        defaultParameters.m_latticeSize[2] = 22;
+
+        defaultParameters.m_latticeSpacing[0] = 3.0f;
+        defaultParameters.m_latticeSpacing[1] = 3.0f;
+        defaultParameters.m_latticeSpacing[2] = 3.0f;
+
+        defaultParameters.m_numShadowCastingSpotLights = 7;
+        defaultParameters.m_shadowSpotlightInnerAngleDeg = 30.0f;
+        defaultParameters.m_shadowSpotlightOuterAngleDeg = 30.0f;
+        defaultParameters.m_shadowSpotlightMaxDistance = 200.0f;
+        defaultParameters.m_shadowSpotlightIntensity = 50000.f;
+
+        defaultParameters.m_activateDirectionalLight = true;
+        defaultParameters.m_directionalLightIntensity = 5.0f;
+
+        defaultParameters.m_cameraPosition[0] = -81.0f;
+        defaultParameters.m_cameraPosition[1] = 31.0f;
+        defaultParameters.m_cameraPosition[2] = 32.0f;
+        defaultParameters.m_cameraHeadingDeg = -90.0f;
+        defaultParameters.m_cameraPitchDeg = 0.0f;
+        defaultParameters.m_iblExposure = -10.0f;
+    }
+
+} // namespace AtomSampleViewer

+ 34 - 0
Gem/Code/Source/Performance/100KDraw_10KDrawable_MultiView_ExampleComponent.h

@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#pragma once
+
+#include <Performance/HighInstanceExampleComponent.h>
+
+namespace AtomSampleViewer
+{
+    //! This test loads a 22x22x22 (~10K) lattice of cubes with a white material, shadowed lights are added to the scene until 100K draws are required. 
+    //! This test benchmarks how well atom scales cpu time with the number of draws. 
+    class _100KDraw10KDrawableExampleComponent
+        : public HighInstanceTestComponent
+    {
+        using Base = HighInstanceTestComponent;
+
+    public:
+        AZ_COMPONENT(_100KDraw10KDrawableExampleComponent, "{85C4BEE0-9FBC-4E9A-8425-12555703CC61}", HighInstanceTestComponent);
+
+        static void Reflect(AZ::ReflectContext* context);
+
+        _100KDraw10KDrawableExampleComponent();
+
+    private:
+        AZ_DISABLE_COPY_MOVE(_100KDraw10KDrawableExampleComponent);
+
+        static void InitDefaultValues(HighInstanceTestParameters& defaultParameters);
+    };
+} // namespace AtomSampleViewer

+ 60 - 0
Gem/Code/Source/Performance/100KDrawable_SingleView_ExampleComponent.cpp

@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#include <Performance/100KDrawable_SingleView_ExampleComponent.h>
+#include <SampleComponentManager.h>
+#include <SampleComponentConfig.h>
+
+#include <AzCore/Serialization/SerializeContext.h>
+
+AZ_DECLARE_BUDGET(AtomSampleViewer);
+
+namespace AtomSampleViewer
+{
+    using namespace AZ;
+
+    void _100KDrawableExampleComponent::Reflect(AZ::ReflectContext* context)
+    {
+        if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
+        {
+            serializeContext->Class<_100KDrawableExampleComponent, HighInstanceTestComponent>()
+                ->Version(0)
+                ;
+        }
+    }
+
+
+    _100KDrawableExampleComponent::_100KDrawableExampleComponent() 
+    {
+        m_sampleName = "100KEntityTest";
+        InitDefaultValues(m_testParameters);
+    }
+
+    void _100KDrawableExampleComponent::InitDefaultValues(HighInstanceTestParameters& defaultParameters)
+    {
+        defaultParameters.m_latticeSize[0] = 46;
+        defaultParameters.m_latticeSize[1] = 46;
+        defaultParameters.m_latticeSize[2] = 46;
+
+        defaultParameters.m_latticeSpacing[0] = 3.0f;
+        defaultParameters.m_latticeSpacing[1] = 3.0f;
+        defaultParameters.m_latticeSpacing[2] = 3.0f;
+
+        defaultParameters.m_numShadowCastingSpotLights = 0;
+        defaultParameters.m_activateDirectionalLight = false;
+
+        defaultParameters.m_cameraPosition[0] = -173.0f;
+        defaultParameters.m_cameraPosition[1] = 66.0f;
+        defaultParameters.m_cameraPosition[2] = 68.0f;
+        defaultParameters.m_cameraHeadingDeg = -90.0f;
+        defaultParameters.m_cameraPitchDeg = 0.0f;
+        defaultParameters.m_iblExposure = 0.0f;
+    }
+
+    
+} // namespace AtomSampleViewer

+ 33 - 0
Gem/Code/Source/Performance/100KDrawable_SingleView_ExampleComponent.h

@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#pragma once
+
+#include <Performance/HighInstanceExampleComponent.h>
+
+namespace AtomSampleViewer
+{
+    //! This test loads a 46x46x46 lattice of cubes with a white material. This test is used as a simple cpu performance stress test for Atom.
+    class _100KDrawableExampleComponent
+        : public HighInstanceTestComponent
+    {
+        using Base = HighInstanceTestComponent;
+
+    public:
+        AZ_COMPONENT(_100KDrawableExampleComponent, "{A373EDC7-399F-49BB-A3A9-D81FA7E05E60}", HighInstanceTestComponent);
+
+        static void Reflect(AZ::ReflectContext* context);
+
+        _100KDrawableExampleComponent();
+
+    private:
+        AZ_DISABLE_COPY_MOVE(_100KDrawableExampleComponent);
+
+        static void InitDefaultValues(HighInstanceTestParameters& defaultParameters);
+    };
+} // namespace AtomSampleViewer

+ 211 - 47
Gem/Code/Source/HighInstanceExampleComponent.cpp → Gem/Code/Source/Performance/HighInstanceExampleComponent.cpp

@@ -6,7 +6,7 @@
  *
  */
 
-#include <HighInstanceExampleComponent.h>
+#include <Performance/HighInstanceExampleComponent.h>
 #include <SampleComponentManager.h>
 #include <SampleComponentConfig.h>
 
@@ -15,6 +15,8 @@
 #include <Atom/RPI.Reflect/Model/ModelAsset.h>
 #include <Atom/RPI.Reflect/Material/MaterialAsset.h>
 #include <Atom/RPI.Reflect/Asset/AssetUtils.h>
+#include <Atom/RPI.Public/AuxGeom/AuxGeomFeatureProcessorInterface.h>
+#include <Atom/RPI.Public/AuxGeom/AuxGeomDraw.h>
 
 #include <Automation/ScriptRunnerBus.h>
 
@@ -23,8 +25,6 @@
 
 #include <RHI/BasicRHIComponent.h>
 
-#include <HighInstanceTestComponent_Traits_Platform.h>
-
 AZ_DECLARE_BUDGET(AtomSampleViewer);
 
 namespace AtomSampleViewer
@@ -47,8 +47,6 @@ namespace AtomSampleViewer
         , m_modelBrowser("@user@/HighInstanceTestComponent/model_browser.xml")
         , m_imguiSidebar("@user@/HighInstanceTestComponent/sidebar.xml")
     {
-        m_sampleName = "HighInstanceTest";
-
         m_materialBrowser.SetFilter([](const AZ::Data::AssetInfo& assetInfo)
         {
             return assetInfo.m_assetType == azrtti_typeid<AZ::RPI::MaterialAsset>();
@@ -59,45 +57,10 @@ namespace AtomSampleViewer
             return assetInfo.m_assetType == azrtti_typeid<AZ::RPI::ModelAsset>();
         });
 
+        // Only use a diffuse white material so light colors are easily visible.
         const AZStd::vector<AZStd::string> materialAllowlist =
         {
-            "materials/presets/pbr/metal_aluminum.azmaterial",
-            "materials/presets/pbr/metal_aluminum_matte.azmaterial",
-            "materials/presets/pbr/metal_aluminum_polished.azmaterial",
-            "materials/presets/pbr/metal_brass.azmaterial",
-            "materials/presets/pbr/metal_brass_matte.azmaterial",
-            "materials/presets/pbr/metal_brass_polished.azmaterial",
-            "materials/presets/pbr/metal_chrome.azmaterial",
-            "materials/presets/pbr/metal_chrome_matte.azmaterial",
-            "materials/presets/pbr/metal_chrome_polished.azmaterial",
-            "materials/presets/pbr/metal_cobalt.azmaterial",
-            "materials/presets/pbr/metal_cobalt_matte.azmaterial",
-            "materials/presets/pbr/metal_cobalt_polished.azmaterial",
-            "materials/presets/pbr/metal_copper.azmaterial",
-            "materials/presets/pbr/metal_copper_matte.azmaterial",
-            "materials/presets/pbr/metal_copper_polished.azmaterial",
-            "materials/presets/pbr/metal_gold.azmaterial",
-            "materials/presets/pbr/metal_gold_matte.azmaterial",
-            "materials/presets/pbr/metal_gold_polished.azmaterial",
-            "materials/presets/pbr/metal_iron.azmaterial",
-            "materials/presets/pbr/metal_iron_matte.azmaterial",
-            "materials/presets/pbr/metal_iron_polished.azmaterial",
-            "materials/presets/pbr/metal_mercury.azmaterial",
-            "materials/presets/pbr/metal_nickel.azmaterial",
-            "materials/presets/pbr/metal_nickel_matte.azmaterial",
-            "materials/presets/pbr/metal_nickel_polished.azmaterial",
-            "materials/presets/pbr/metal_palladium.azmaterial",
-            "materials/presets/pbr/metal_palladium_matte.azmaterial",
-            "materials/presets/pbr/metal_palladium_polished.azmaterial",
-            "materials/presets/pbr/metal_platinum.azmaterial",
-            "materials/presets/pbr/metal_platinum_matte.azmaterial",
-            "materials/presets/pbr/metal_platinum_polished.azmaterial",
-            "materials/presets/pbr/metal_silver.azmaterial",
-            "materials/presets/pbr/metal_silver_matte.azmaterial",
-            "materials/presets/pbr/metal_silver_polished.azmaterial",
-            "materials/presets/pbr/metal_titanium.azmaterial",
-            "materials/presets/pbr/metal_titanium_matte.azmaterial",
-            "materials/presets/pbr/metal_titanium_polished.azmaterial",
+            "materials/presets/macbeth/19_white_9-5_0-05d.azmaterial",
         };
         m_materialBrowser.SetDefaultPinnedAssets(materialAllowlist);
 
@@ -124,6 +87,11 @@ namespace AtomSampleViewer
 
     void HighInstanceTestComponent::Activate()
     {
+        BuildDiskLightParameters();
+
+        m_directionalLightFeatureProcessor = m_scene->GetFeatureProcessor<Render::DirectionalLightFeatureProcessorInterface>();
+        m_diskLightFeatureProcessor = m_scene->GetFeatureProcessor<Render::DiskLightFeatureProcessorInterface>();
+
         AZ::TickBus::Handler::BusConnect();
 
         m_imguiSidebar.Activate();
@@ -136,9 +104,15 @@ namespace AtomSampleViewer
         m_modelBrowser.ResetPinnedAssetsToDefault();
 
         SetLatticeDimensions(
-            ATOMSAMPLEVIEWER_TRAIT_HIGH_INSTANCE_COUNT_TEST_COMPONENT_LATTICE_SIZE_X, 
-            ATOMSAMPLEVIEWER_TRAIT_HIGH_INSTANCE_COUNT_TEST_COMPONENT_LATTICE_SIZE_Y, 
-            ATOMSAMPLEVIEWER_TRAIT_HIGH_INSTANCE_COUNT_TEST_COMPONENT_LATTICE_SIZE_Z);
+            m_testParameters.m_latticeSize[0], 
+            m_testParameters.m_latticeSize[1], 
+            m_testParameters.m_latticeSize[2]);
+        SetLatticeSpacing(
+            m_testParameters.m_latticeSpacing[0],
+            m_testParameters.m_latticeSpacing[1],
+            m_testParameters.m_latticeSpacing[2]);
+        SetLatticeEntityScale(m_testParameters.m_entityScale);
+
         Base::Activate();
 
         AzFramework::NativeWindowHandle windowHandle = nullptr;
@@ -158,10 +132,13 @@ namespace AtomSampleViewer
 
             SaveCameraConfiguration();
             ResetNoClipController();
+
+            SetIBLExposure(m_testParameters.m_iblExposure);
     }
 
     void HighInstanceTestComponent::Deactivate()
     {
+        DestroyLights();
         RestoreCameraConfiguration();
         AzFramework::NativeWindowHandle windowHandle = nullptr;
         AzFramework::WindowSystemRequestBus::BroadcastResult(
@@ -184,6 +161,7 @@ namespace AtomSampleViewer
     void HighInstanceTestComponent::PrepareCreateLatticeInstances(uint32_t instanceCount)
     {
         m_modelInstanceData.reserve(instanceCount);
+        DestroyLights();
     }
 
     void HighInstanceTestComponent::CreateLatticeInstance(const AZ::Transform& transform)
@@ -232,6 +210,16 @@ namespace AtomSampleViewer
         // pause script and tick until assets are ready
         ScriptRunnerRequestBus::Broadcast(&ScriptRunnerRequests::PauseScriptWithTimeout, 120.0f);
         AZ::TickBus::Handler::BusDisconnect();
+
+        if (m_testParameters.m_numShadowCastingSpotLights > 0 && m_diskLightsEnabled)
+        {
+            CreateSpotLights();
+        }
+
+        if (m_testParameters.m_activateDirectionalLight && m_directionalLightEnabled)
+        {
+            CreateDirectionalLight();
+        }
     }
 
     void HighInstanceTestComponent::OnAllAssetsReadyActivate()
@@ -271,6 +259,18 @@ namespace AtomSampleViewer
         m_modelInstanceData.clear();
     }
 
+    void HighInstanceTestComponent::DestroyLights()
+    {
+        m_directionalLightFeatureProcessor->ReleaseLight(m_directionalLightHandle);
+        m_directionalLightHandle = {};
+        for (int index = 0; index < m_diskLights.size(); ++index)
+        {
+            DiskLightHandle& handle = m_diskLights[index].m_handle;
+            m_diskLightFeatureProcessor->ReleaseLight(handle);
+            handle = {};
+        }
+    }
+
     void HighInstanceTestComponent::DestroyHandles()
     {
         for (ModelInstanceData& instanceData : m_modelInstanceData)
@@ -329,6 +329,8 @@ namespace AtomSampleViewer
         }
 
         bool currentUseSimpleModels = m_useSimpleModels;
+        bool diskLightsEnabled = m_diskLightsEnabled;
+        bool directionalLightEnabled = m_directionalLightEnabled;
         if (m_imguiSidebar.Begin())
         {
             ImGui::Checkbox("Update Transforms Every Frame", &m_updateTransformEnabled);
@@ -345,9 +347,41 @@ namespace AtomSampleViewer
 
             ImGui::Checkbox("Use simple models", &m_useSimpleModels);
 
+            ImGui::Spacing();
+            ImGui::Separator();
+            ImGui::Spacing();
+
+            ImGui::Checkbox("Display SpotLight Debug", &m_drawDiskLightDebug);
+
+            ImGui::Spacing();
+            ImGui::Separator();
+            ImGui::Spacing();
+
+            if (m_testParameters.m_numShadowCastingSpotLights > 0)
+            {
+                ImGui::Checkbox("Enable SpotLights", &m_diskLightsEnabled);
+            }
+            if (m_testParameters.m_activateDirectionalLight)
+            {
+                ImGui::Checkbox("Enable Directional Light", &m_directionalLightEnabled);
+            }
+
             m_imguiSidebar.End();
         }
 
+        if(diskLightsEnabled != m_diskLightsEnabled || directionalLightEnabled != m_directionalLightEnabled)
+        {
+            DestroyLights();
+            if (m_testParameters.m_numShadowCastingSpotLights > 0 && m_diskLightsEnabled)
+            {
+                CreateSpotLights();
+            }
+            if(m_testParameters.m_activateDirectionalLight && m_directionalLightEnabled)
+            {
+                CreateDirectionalLight();
+            }
+        }
+
         if (currentUseSimpleModels != m_useSimpleModels)
         {
             m_modelBrowser.SetPinnedAssets(m_useSimpleModels?m_simpleModelList:m_expandedModelList);
@@ -356,17 +390,22 @@ namespace AtomSampleViewer
                 instanceData.m_modelAssetId = GetRandomModelId();
             }
             DestroyHandles();
+            DestroyLights();
             FinalizeLatticeInstances();
         }
+
+        DrawDiskLightDebugObjects();
     }
 
     void HighInstanceTestComponent::ResetNoClipController()
     {
         using namespace AZ;
         using namespace AZ::Debug;
+        AZ::Vector3 camPos = AZ::Vector3::CreateFromFloat3(m_testParameters.m_cameraPosition);
         Camera::CameraRequestBus::Event(GetCameraEntityId(), &Camera::CameraRequestBus::Events::SetFarClipDistance, 2000.0f);
-        NoClipControllerRequestBus::Event(GetCameraEntityId(), &NoClipControllerRequestBus::Events::SetHeading, AZ::DegToRad(-44.722542));
-        NoClipControllerRequestBus::Event(GetCameraEntityId(), &NoClipControllerRequestBus::Events::SetPitch, AZ::DegToRad(24.987326));
+        NoClipControllerRequestBus::Event(GetCameraEntityId(), &NoClipControllerRequestBus::Events::SetPosition, camPos);
+        NoClipControllerRequestBus::Event(GetCameraEntityId(), &NoClipControllerRequestBus::Events::SetHeading, AZ::DegToRad(m_testParameters.m_cameraHeadingDeg));
+        NoClipControllerRequestBus::Event(GetCameraEntityId(), &NoClipControllerRequestBus::Events::SetPitch, AZ::DegToRad(m_testParameters.m_cameraPitchDeg));
     }
 
     void HighInstanceTestComponent::SaveCameraConfiguration()
@@ -378,4 +417,129 @@ namespace AtomSampleViewer
     {
         Camera::CameraRequestBus::Event(GetCameraEntityId(), &Camera::CameraRequestBus::Events::SetFarClipDistance, m_originalFarClipDistance);
     }
+
+    void HighInstanceTestComponent::CreateSpotLights()
+    {
+        for (int index = 0; index < m_testParameters.m_numShadowCastingSpotLights; ++index)
+        {
+            CreateSpotLight(index);
+        }
+   }
+
+    void HighInstanceTestComponent::CreateSpotLight(int index)
+    {
+        Render::DiskLightFeatureProcessorInterface* const featureProcessor = m_diskLightFeatureProcessor;
+        const DiskLightHandle handle = featureProcessor->AcquireLight();
+
+        AZ::Render::PhotometricColor<AZ::Render::PhotometricUnit::Candela> lightColor(m_diskLights[index].m_color * m_testParameters.m_shadowSpotlightIntensity);
+        featureProcessor->SetRgbIntensity(handle, lightColor);
+        featureProcessor->SetAttenuationRadius(handle, m_testParameters.m_shadowSpotlightMaxDistance);
+        featureProcessor->SetConeAngles(
+            handle, 
+            DegToRad(m_testParameters.m_shadowSpotlightInnerAngleDeg), 
+            DegToRad(m_testParameters.m_shadowSpotlightOuterAngleDeg));
+        featureProcessor->SetShadowsEnabled(handle, true);
+        featureProcessor->SetShadowmapMaxResolution(handle, m_testParameters.m_shadowmapSize);
+        featureProcessor->SetShadowFilterMethod(handle, m_testParameters.m_shadowFilterMethod);
+        featureProcessor->SetFilteringSampleCount(handle, 1);
+
+        const Vector3 aabbOffset = m_diskLights[index].m_relativePosition.GetNormalized() * (0.5f * m_testParameters.m_shadowSpotlightMaxDistance);
+        const Vector3 position = m_worldAabb.GetCenter() + aabbOffset;
+
+        featureProcessor->SetPosition(handle, position);
+        featureProcessor->SetDirection(handle, (-aabbOffset).GetNormalized());
+
+        m_diskLights[index].m_handle = handle;
+    }
+
+    const AZ::Color& HighInstanceTestComponent::GetNextLightColor()
+    {
+        static uint16_t colorIndex = 0;
+        static const AZStd::vector<AZ::Color> colors =
+        {
+            AZ::Colors::Red,
+            AZ::Colors::Green,
+            AZ::Colors::Blue,
+            AZ::Colors::Cyan,
+            AZ::Colors::Fuchsia,
+            AZ::Colors::Yellow,
+            AZ::Colors::SpringGreen
+        };
+
+        const AZ::Color& result = colors[colorIndex];
+        colorIndex = (colorIndex + 1) % colors.size();
+        return result;
+    }
+
+    AZ::Vector3 HighInstanceTestComponent::GetRandomDirection()
+    {
+        return AZ::Vector3(
+            m_random.GetRandomFloat() - 0.5f,
+            m_random.GetRandomFloat() - 0.5f,
+            m_random.GetRandomFloat() - 0.5f).GetNormalized();
+    }
+
+    void HighInstanceTestComponent::BuildDiskLightParameters()
+    {
+        m_random.SetSeed(0);
+        m_diskLights.clear();
+        m_diskLights.reserve(m_testParameters.m_numShadowCastingSpotLights);
+        for (int index = 0; index < m_testParameters.m_numShadowCastingSpotLights; ++index)
+        {
+            m_diskLights.emplace_back(
+                GetNextLightColor(),
+                GetRandomDirection(),
+                m_testParameters.m_shadowmapSize);
+        }
+    }
+
+    void HighInstanceTestComponent::CreateDirectionalLight()
+    {
+        Render::DirectionalLightFeatureProcessorInterface* featureProcessor = m_directionalLightFeatureProcessor;
+        const DirectionalLightHandle handle = featureProcessor->AcquireLight();
+
+        const auto lightTransform = Transform::CreateLookAt(
+            -m_worldAabb.GetMax(),
+            Vector3::CreateZero());
+        featureProcessor->SetDirection(
+            handle,
+            lightTransform.GetBasis(1));
+
+        featureProcessor->SetRgbIntensity(handle, AZ::Render::PhotometricColor<AZ::Render::PhotometricUnit::Lux>(AZ::Color::CreateOne() * m_testParameters.m_directionalLightIntensity));
+        featureProcessor->SetCascadeCount(handle, m_testParameters.m_numDirectionalLightShadowCascades);
+        featureProcessor->SetShadowmapSize(handle, m_testParameters.m_shadowmapSize);
+        featureProcessor->SetViewFrustumCorrectionEnabled(handle, false);
+        featureProcessor->SetShadowFilterMethod(handle, m_testParameters.m_shadowFilterMethod);
+        featureProcessor->SetFilteringSampleCount(handle, 1);
+        featureProcessor->SetGroundHeight(handle, 0.f);
+
+        m_directionalLightHandle = handle;
+    }
+
+
+
+    void HighInstanceTestComponent::DrawDiskLightDebugObjects()
+    {
+        if (auto auxGeom = AZ::RPI::AuxGeomFeatureProcessorInterface::GetDrawQueueForScene(m_scene); 
+            m_drawDiskLightDebug && auxGeom)
+        {
+            for (int i = 0; i < m_diskLights.size(); ++i)
+            {
+                const auto& light = m_diskLights[i];
+                if (light.m_handle.IsValid())
+                {
+                    const Render::DiskLightData& lightData = m_diskLightFeatureProcessor->GetDiskData(light.m_handle);
+                    const float lightDistance = sqrt(1.0f/lightData.m_invAttenuationRadiusSquared);
+                    AZ::Vector3 position = AZ::Vector3::CreateFromFloat3(lightData.m_position.data());
+                    AZ::Vector3 direction = AZ::Vector3::CreateFromFloat3(lightData.m_direction.data()).GetNormalized();
+                    position += direction * lightDistance;
+                    direction *= -1.0f;
+                    float coneSlantLength = lightDistance / lightData.m_cosOuterConeAngle;
+                    float farEndCapRadius = sqrt(coneSlantLength * coneSlantLength - lightDistance * lightDistance);
+                    auxGeom->DrawCone(position, direction, farEndCapRadius, lightDistance, light.m_color, AZ::RPI::AuxGeomDraw::DrawStyle::Line);
+                }
+            }
+        }
+    }
+
 } // namespace AtomSampleViewer

+ 179 - 0
Gem/Code/Source/Performance/HighInstanceExampleComponent.h

@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#pragma once
+
+#include <EntityLatticeTestComponent.h>
+#include <Utils/ImGuiSidebar.h>
+#include <Utils/ImGuiAssetBrowser.h>
+#include <AzCore/Component/TickBus.h>
+#include <AzCore/Math/Random.h>
+#include <AzCore/Math/Vector3.h>
+#include <AzCore/Math/Color.h>
+#include <AzCore/std/containers/vector.h>
+
+#include <Atom/Feature/CoreLights/DirectionalLightFeatureProcessorInterface.h>
+#include <Atom/Feature/CoreLights/ShadowConstants.h>
+#include <Atom/Feature/CoreLights/DiskLightFeatureProcessorInterface.h>
+
+namespace AtomSampleViewer
+{
+    //! This class is used as base of a set of simple cpu performance stress test for Atom.
+    //! This test loads a X*Y*Z lattice of entities with randomized meshes and materials and creates N shadow casting spotlights plus 0-1 Directional lights
+   struct HighInstanceTestParameters
+   {
+       int m_latticeSize[3] = {22, 22, 22};
+       float m_latticeSpacing[3] = {5.0f, 5.0f, 5.0f};
+       float m_entityScale = 1.0f;
+
+       AZ::Render::ShadowmapSize m_shadowmapSize = AZ::Render::ShadowmapSize::Size256;
+       AZ::Render::ShadowFilterMethod m_shadowFilterMethod = AZ::Render::ShadowFilterMethod::None;
+       int m_numShadowCastingSpotLights = 0;
+       float m_shadowSpotlightInnerAngleDeg = 10.0f;
+       float m_shadowSpotlightOuterAngleDeg = 30.0f;
+       float m_shadowSpotlightMaxDistance = 200.0f;
+       float m_shadowSpotlightIntensity = 500.f; // Value in Candela
+
+       bool m_activateDirectionalLight = false;
+       uint16_t m_numDirectionalLightShadowCascades = 4;
+       float m_directionalLightIntensity = 5.0f; // Value in Lux
+
+       float m_cameraPosition[3] = {0.0f, 0.0f, 0.0f};
+       float m_cameraHeadingDeg = -44.7f;
+       float m_cameraPitchDeg = 25.0f;
+       float m_iblExposure = 0.0f;
+   };
+    class HighInstanceTestComponent
+        : public EntityLatticeTestComponent
+        , public AZ::TickBus::Handler
+    {
+        using Base = EntityLatticeTestComponent;
+
+    public:
+        AZ_RTTI(HighInstanceTestComponent, "{DAA2B63B-7CC0-4696-A44F-49E53C6390B9}", EntityLatticeTestComponent);
+
+        static void Reflect(AZ::ReflectContext* context);
+
+        HighInstanceTestComponent();
+        
+        //! AZ::Component overrides...
+        void Activate() override;
+        void Deactivate() override;
+
+    private:
+        AZ_DISABLE_COPY_MOVE(HighInstanceTestComponent);
+
+        // CommonSampleComponentBase overrides...
+        void OnAllAssetsReadyActivate() override;
+
+        //! EntityLatticeTestComponent overrides...
+        void PrepareCreateLatticeInstances(uint32_t instanceCount) override;
+        void CreateLatticeInstance(const AZ::Transform& transform) override;
+        void FinalizeLatticeInstances() override;
+        void DestroyLatticeInstances() override;
+        void DestroyLights();
+
+        void DestroyHandles();
+
+        AZ::Data::AssetId GetRandomModelId() const;
+        AZ::Data::AssetId GetRandomMaterialId() const;
+
+        void OnTick(float deltaTime, AZ::ScriptTimePoint scriptTime) override;
+
+        void ResetNoClipController();
+        void SaveCameraConfiguration();
+        void RestoreCameraConfiguration();
+
+        const AZ::Color& GetNextLightColor();
+        AZ::Vector3 GetRandomDirection();
+        void BuildDiskLightParameters();
+        void CreateSpotLights();
+        void CreateSpotLight(int index);
+        void DrawDiskLightDebugObjects();
+
+        void CreateDirectionalLight();
+
+    protected:
+        HighInstanceTestParameters m_testParameters;
+
+    private:
+        struct ModelInstanceData
+        {
+            AZ::Transform m_transform;
+            AZ::Data::AssetId m_modelAssetId;
+            AZ::Data::AssetId m_materialAssetId;
+            AZ::Render::MeshFeatureProcessorInterface::MeshHandle m_meshHandle;
+        };
+
+        ImGuiSidebar m_imguiSidebar;
+        ImGuiAssetBrowser m_materialBrowser;
+        ImGuiAssetBrowser m_modelBrowser;
+        
+        AZStd::vector<ModelInstanceData> m_modelInstanceData;
+
+        struct Compare
+        {
+            bool operator()(const AZ::Data::Asset<AZ::RPI::MaterialAsset>& lhs, const AZ::Data::Asset<AZ::RPI::MaterialAsset>& rhs) const
+            {
+                if (lhs.GetId().m_guid == rhs.GetId().m_guid)
+                {
+                    return lhs.GetId().m_subId > rhs.GetId().m_subId;
+                }
+                return lhs.GetId().m_guid > rhs.GetId().m_guid;
+            }
+        };
+
+        using MaterialAssetSet = AZStd::set<AZ::Data::Asset<AZ::RPI::MaterialAsset>, Compare>;
+        MaterialAssetSet m_cachedMaterials;
+        uint32_t m_pinnedMaterialCount = 0;
+        uint32_t m_preActivateVSyncInterval = 0;
+        AZ::SimpleLcgRandom m_random;
+
+        AZStd::vector<AZStd::string> m_expandedModelList; // has models that are more expensive on the gpu
+        AZStd::vector<AZStd::string> m_simpleModelList; // Aims to keep the test cpu bottlenecked by using trivial geometry such as a cube
+        size_t m_lastPinnedModelCount = 0;
+
+        float m_originalFarClipDistance;
+        bool m_updateTransformEnabled = false;
+        bool m_useSimpleModels = true;
+
+        // light settings
+        using DirectionalLightHandle = AZ::Render::DirectionalLightFeatureProcessorInterface::LightHandle;
+        using DiskLightHandle = AZ::Render::DiskLightFeatureProcessorInterface::LightHandle;
+
+        class DiskLight
+        {
+        public:
+            DiskLight() = delete;
+            explicit DiskLight(
+                const AZ::Color& color,
+                const AZ::Vector3& relativePosition,
+                AZ::Render::ShadowmapSize shadowmapSize)
+                : m_color{ color }
+                , m_relativePosition{ relativePosition }
+                , m_shadowmapSize{ shadowmapSize }
+            {}
+            ~DiskLight() = default;
+
+            const AZ::Color m_color;
+            const AZ::Vector3 m_relativePosition;
+            const AZ::Render::ShadowmapSize m_shadowmapSize;
+            DiskLightHandle m_handle;
+        };
+
+        static constexpr float CutoffIntensity = 0.1f;
+
+        AZ::Render::DirectionalLightFeatureProcessorInterface* m_directionalLightFeatureProcessor = nullptr;
+        AZ::Render::DiskLightFeatureProcessorInterface* m_diskLightFeatureProcessor = nullptr;
+        DirectionalLightHandle m_directionalLightHandle;
+        AZStd::vector<DiskLight> m_diskLights;
+        bool m_drawDiskLightDebug = false;
+        bool m_diskLightsEnabled = true; // combined with test parameters to determine final state.
+        bool m_directionalLightEnabled = true; // combined with test parameters to determine final state.
+    };
+} // namespace AtomSampleViewer

+ 0 - 11
Gem/Code/Source/Platform/Android/HighInstanceTestComponent_Traits_Platform.h

@@ -1,11 +0,0 @@
-/*
- * Copyright (c) Contributors to the Open 3D Engine Project.
- * For complete copyright and license terms please see the LICENSE at the root of this distribution.
- *
- * SPDX-License-Identifier: Apache-2.0 OR MIT
- *
- */
-
-#define ATOMSAMPLEVIEWER_TRAIT_HIGH_INSTANCE_COUNT_TEST_COMPONENT_LATTICE_SIZE_X       12
-#define ATOMSAMPLEVIEWER_TRAIT_HIGH_INSTANCE_COUNT_TEST_COMPONENT_LATTICE_SIZE_Y       12
-#define ATOMSAMPLEVIEWER_TRAIT_HIGH_INSTANCE_COUNT_TEST_COMPONENT_LATTICE_SIZE_Z       12

+ 0 - 1
Gem/Code/Source/Platform/Android/atomsampleviewer_android_files.cmake

@@ -13,7 +13,6 @@ set(FILES
     SceneReloadSoakTestComponent_Traits_Platform.h
     SSRExampleComponent_Traits_Platform.h
     TriangleConstantBufferExampleComponent_Traits_Platform.h
-    HighInstanceTestComponent_Traits_Platform.h
     SampleComponentManager_Android.cpp
     StreamingImageExampleComponent_Android.cpp
     Utils_Android.cpp

+ 1 - 1
Gem/Code/Source/Platform/Linux/EntityLatticeTestComponent_Traits_Platform.h

@@ -9,4 +9,4 @@
 #define ENTITY_LATTICE_TEST_COMPONENT_WIDTH                     5
 #define ENTITY_LATTICE_TEST_COMPONENT_HEIGHT                    5
 #define ENTITY_LATTICE_TEST_COMPONENT_DEPTH                     5
-#define ENTITY_LATTEST_TEST_COMPONENT_MAX                       25
+#define ENTITY_LATTEST_TEST_COMPONENT_MAX                       100

+ 0 - 11
Gem/Code/Source/Platform/Linux/HighInstanceTestComponent_Traits_Platform.h

@@ -1,11 +0,0 @@
-/*
- * Copyright (c) Contributors to the Open 3D Engine Project.
- * For complete copyright and license terms please see the LICENSE at the root of this distribution.
- *
- * SPDX-License-Identifier: Apache-2.0 OR MIT
- *
- */
-
-#define ATOMSAMPLEVIEWER_TRAIT_HIGH_INSTANCE_COUNT_TEST_COMPONENT_LATTICE_SIZE_X       22
-#define ATOMSAMPLEVIEWER_TRAIT_HIGH_INSTANCE_COUNT_TEST_COMPONENT_LATTICE_SIZE_Y       22
-#define ATOMSAMPLEVIEWER_TRAIT_HIGH_INSTANCE_COUNT_TEST_COMPONENT_LATTICE_SIZE_Z       22

+ 0 - 1
Gem/Code/Source/Platform/Linux/atomsampleviewer_linux_files.cmake

@@ -13,7 +13,6 @@ set(FILES
     SceneReloadSoakTestComponent_Traits_Platform.h
     SSRExampleComponent_Traits_Platform.h
     TriangleConstantBufferExampleComponent_Traits_Platform.h
-    HighInstanceTestComponent_Traits_Platform.h
     SampleComponentManager_Linux.cpp
     StreamingImageExampleComponent_Linux.cpp
     Utils_Linux.cpp

+ 1 - 1
Gem/Code/Source/Platform/Mac/EntityLatticeTestComponent_Traits_Platform.h

@@ -9,4 +9,4 @@
 #define ENTITY_LATTICE_TEST_COMPONENT_WIDTH                     5
 #define ENTITY_LATTICE_TEST_COMPONENT_HEIGHT                    5
 #define ENTITY_LATTICE_TEST_COMPONENT_DEPTH                     5
-#define ENTITY_LATTEST_TEST_COMPONENT_MAX                       25
+#define ENTITY_LATTEST_TEST_COMPONENT_MAX                       100

+ 0 - 11
Gem/Code/Source/Platform/Mac/HighInstanceTestComponent_Traits_Platform.h

@@ -1,11 +0,0 @@
-/*
- * Copyright (c) Contributors to the Open 3D Engine Project.
- * For complete copyright and license terms please see the LICENSE at the root of this distribution.
- *
- * SPDX-License-Identifier: Apache-2.0 OR MIT
- *
- */
-
-#define ATOMSAMPLEVIEWER_TRAIT_HIGH_INSTANCE_COUNT_TEST_COMPONENT_LATTICE_SIZE_X       22
-#define ATOMSAMPLEVIEWER_TRAIT_HIGH_INSTANCE_COUNT_TEST_COMPONENT_LATTICE_SIZE_Y       22
-#define ATOMSAMPLEVIEWER_TRAIT_HIGH_INSTANCE_COUNT_TEST_COMPONENT_LATTICE_SIZE_Z       22

+ 0 - 1
Gem/Code/Source/Platform/Mac/atomsampleviewer_mac_files.cmake

@@ -14,7 +14,6 @@ set(FILES
     SceneReloadSoakTestComponent_Traits_Platform.h
     SSRExampleComponent_Traits_Platform.h
     TriangleConstantBufferExampleComponent_Traits_Platform.h
-    HighInstanceTestComponent_Traits_Platform.h
     SampleComponentManager_Mac.cpp
     StreamingImageExampleComponent_Mac.cpp
     Utils_Mac.cpp

+ 1 - 1
Gem/Code/Source/Platform/Windows/EntityLatticeTestComponent_Traits_Platform.h

@@ -9,4 +9,4 @@
 #define ENTITY_LATTICE_TEST_COMPONENT_WIDTH                     5
 #define ENTITY_LATTICE_TEST_COMPONENT_HEIGHT                    5
 #define ENTITY_LATTICE_TEST_COMPONENT_DEPTH                     5
-#define ENTITY_LATTEST_TEST_COMPONENT_MAX                       25
+#define ENTITY_LATTEST_TEST_COMPONENT_MAX                       100

+ 0 - 11
Gem/Code/Source/Platform/Windows/HighInstanceTestComponent_Traits_Platform.h

@@ -1,11 +0,0 @@
-/*
- * Copyright (c) Contributors to the Open 3D Engine Project.
- * For complete copyright and license terms please see the LICENSE at the root of this distribution.
- *
- * SPDX-License-Identifier: Apache-2.0 OR MIT
- *
- */
-
-#define ATOMSAMPLEVIEWER_TRAIT_HIGH_INSTANCE_COUNT_TEST_COMPONENT_LATTICE_SIZE_X       22
-#define ATOMSAMPLEVIEWER_TRAIT_HIGH_INSTANCE_COUNT_TEST_COMPONENT_LATTICE_SIZE_Y       22
-#define ATOMSAMPLEVIEWER_TRAIT_HIGH_INSTANCE_COUNT_TEST_COMPONENT_LATTICE_SIZE_Z       22

+ 0 - 1
Gem/Code/Source/Platform/Windows/atomsampleviewer_windows_files.cmake

@@ -12,7 +12,6 @@ set(FILES
     MultiThreadComponent_Traits_Platform.h
     SceneReloadSoakTestComponent_Traits_Platform.h
     SSRExampleComponent_Traits_Platform.h
-    HighInstanceTestComponent_Traits_Platform.h
     SampleComponentManager_Windows.cpp
     StreamingImageExampleComponent_Windows.cpp
     Utils_Windows.cpp

+ 0 - 11
Gem/Code/Source/Platform/iOS/HighInstanceTestComponent_Traits_Platform.h

@@ -1,11 +0,0 @@
-/*
- * Copyright (c) Contributors to the Open 3D Engine Project.
- * For complete copyright and license terms please see the LICENSE at the root of this distribution.
- *
- * SPDX-License-Identifier: Apache-2.0 OR MIT
- *
- */
-
-#define ATOMSAMPLEVIEWER_TRAIT_HIGH_INSTANCE_COUNT_TEST_COMPONENT_LATTICE_SIZE_X       12
-#define ATOMSAMPLEVIEWER_TRAIT_HIGH_INSTANCE_COUNT_TEST_COMPONENT_LATTICE_SIZE_Y       12
-#define ATOMSAMPLEVIEWER_TRAIT_HIGH_INSTANCE_COUNT_TEST_COMPONENT_LATTICE_SIZE_Z       12

+ 0 - 1
Gem/Code/Source/Platform/iOS/atomsampleviewer_ios_files.cmake

@@ -14,7 +14,6 @@ set(FILES
     SceneReloadSoakTestComponent_Traits_Platform.h
     SSRExampleComponent_Traits_Platform.h
     TriangleConstantBufferExampleComponent_Traits_Platform.h
-    HighInstanceTestComponent_Traits_Platform.h
     SampleComponentManager_iOS.cpp
     StreamingImageExampleComponent_iOS.cpp
     Utils_iOS.cpp

+ 436 - 0
Gem/Code/Source/RenderTargetTextureExampleComponent.cpp

@@ -0,0 +1,436 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#include <RenderTargetTextureExampleComponent.h>
+
+#include <Atom/Component/DebugCamera/NoClipControllerComponent.h>
+
+#include <Atom/RHI/Device.h>
+#include <Atom/RHI/Factory.h>
+
+#include <Atom/RPI.Public/DynamicDraw/DynamicDrawInterface.h>
+#include <Atom/RPI.Public/Image/AttachmentImagePool.h>
+#include <Atom/RPI.Public/Image/ImageSystemInterface.h>
+#include <Atom/RPI.Public/RPIUtils.h>
+#include <Atom/RPI.Public/View.h>
+
+#include <Atom/RPI.Reflect/Asset/AssetUtils.h>
+#include <Atom/RPI.Reflect/Model/ModelAsset.h>
+#include <Atom/RPI.Reflect/Material/MaterialAsset.h>
+#include <Atom/RPI.Reflect/Pass/PassDescriptor.h>
+#include <Atom/RPI.Reflect/Pass/RasterPassData.h>
+
+#include <AzCore/Asset/AssetManagerBus.h>
+#include <AzCore/Component/Entity.h>
+#include <AzCore/Math/MatrixUtils.h>
+#include <AzCore/std/smart_ptr/make_shared.h>
+
+#include <AzFramework/Components/TransformComponent.h>
+#include <AzFramework/Input/Devices/Mouse/InputDeviceMouse.h>
+
+#include <SampleComponentManager.h>
+#include <SampleComponentConfig.h>
+#include <EntityUtilityFunctions.h>
+
+#include <Automation/ScriptableImGui.h>
+#include <Automation/ScriptRunnerBus.h>
+
+#include <RHI/BasicRHIComponent.h>
+
+namespace AtomSampleViewer
+{
+    using namespace AZ;
+
+    namespace
+    {
+        static constexpr const char TextureFilePath[] = "textures/default/checker_uv_basecolor.png.streamingimage";
+    }
+
+    void RenderTargetTextureExampleComponent::Reflect(ReflectContext* context)
+    {
+        if (SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context))
+        {
+            serializeContext->Class<RenderTargetTextureExampleComponent, Component>()
+                ->Version(0)
+                ;
+        }
+    }
+
+    RenderTargetTextureExampleComponent::RenderTargetTextureExampleComponent()
+        : m_imguiSidebar("@user@/RenderTargetTextureExampleComponent/sidebar.xml")
+    {
+    }
+
+    void RenderTargetTextureExampleComponent::Activate()
+    {
+        m_ibl.PreloadAssets();
+
+        // Don't continue the script until assets are ready and scene is setup
+        ScriptRunnerRequestBus::Broadcast(&ScriptRunnerRequests::PauseScriptWithTimeout, 120.0f);
+
+        // preload assets
+        AZStd::vector<AssetCollectionAsyncLoader::AssetToLoadInfo> assetList = {
+            {DefaultPbrMaterialPath, azrtti_typeid<RPI::MaterialAsset>()},
+            {BunnyModelFilePath, azrtti_typeid<RPI::ModelAsset>()},
+            {TextureFilePath, azrtti_typeid<RPI::StreamingImageAsset>()}
+        };
+
+        PreloadAssets(assetList);
+    }
+
+    void RenderTargetTextureExampleComponent::AddRenderTargetPass()
+    {
+        m_renderTargetPassDrawListTag = AZ::Name("rt_1");
+        Name renderPassTemplateName = Name{ "RenderTargetPassTemplate" };
+        RHI::ClearValue clearValue = RHI::ClearValue::CreateVector4Float(1, 0, 0, 1);
+        AZStd::shared_ptr<RPI::PassTemplate> rtPassTemplate = RPI::PassSystemInterface::Get()->GetPassTemplate(renderPassTemplateName);
+
+        // Create the template if it doesn't exist
+        if (rtPassTemplate == nullptr)
+        {
+            // first add a pass template from code (an alternative way then using .pass asset for a new template)        
+            rtPassTemplate = AZStd::make_shared<RPI::PassTemplate>();
+            rtPassTemplate->m_name = Name{ "RenderTargetPassTemplate" };
+            rtPassTemplate->m_passClass = "RasterPass";
+
+            // only need one slot for render target output
+            RPI::PassSlot slot;
+            slot.m_name = Name("ColorOutput");
+            slot.m_slotType = RPI::PassSlotType::Output;
+            slot.m_scopeAttachmentUsage = RHI::ScopeAttachmentUsage::RenderTarget;
+            //slot.m_loadStoreAction.m_loadAction = RHI::AttachmentLoadAction::DontCare;
+            slot.m_loadStoreAction.m_loadAction = RHI::AttachmentLoadAction::Clear;
+            slot.m_loadStoreAction.m_clearValue = clearValue;
+            rtPassTemplate->AddSlot(slot);
+
+            // connect the slot to attachment
+            RPI::PassConnection connection;
+            connection.m_localSlot = Name("ColorOutput");
+            connection.m_attachmentRef.m_pass = Name("This");
+            connection.m_attachmentRef.m_attachment = Name("RenderTarget");
+            rtPassTemplate->AddOutputConnection(connection);
+
+            RPI::PassSystemInterface::Get()->AddPassTemplate(Name{ "RenderTargetPassTemplate" }, rtPassTemplate);
+        }
+
+        // Create pass
+        RPI::PassRequest createPassRequest;
+        createPassRequest.m_templateName = Name("RenderTargetPassTemplate");
+        createPassRequest.m_passName = Name("RenderTargetPass");
+
+        // Create AttacmentImage which is used for pass render target 
+        const uint32_t imageWidth = 512;
+        const uint32_t imageHeight = 512;
+        Data::Instance<RPI::AttachmentImagePool> pool = RPI::ImageSystemInterface::Get()->GetSystemAttachmentPool();
+        RPI::CreateAttachmentImageRequest createRequest;
+        createRequest.m_imagePool = pool.get();
+        createRequest.m_imageDescriptor = RHI::ImageDescriptor::Create2D(AZ::RHI::ImageBindFlags::Color|AZ::RHI::ImageBindFlags::ShaderRead, imageWidth, imageHeight, RHI::Format::R8G8B8A8_UNORM);
+        createRequest.m_imageName = Name("$RT1");
+        createRequest.m_isUniqueName = true;
+        createRequest.m_optimizedClearValue = &clearValue;
+
+        AZStd::shared_ptr<AZ::RPI::RasterPassData> passData = AZStd::make_shared<AZ::RPI::RasterPassData>();
+        passData->m_drawListTag = m_renderTargetPassDrawListTag;
+        passData->m_pipelineViewTag = AZ::Name("MainCamera");
+        passData->m_overrideScissor = RHI::Scissor(0, 0, imageWidth, imageHeight);
+        passData->m_overrideViewport = RHI::Viewport(0, imageWidth, 0, imageHeight);
+        createPassRequest.m_passData = passData;
+
+        m_renderTarget = RPI::AttachmentImage::Create(createRequest);
+
+        // Add image from asset
+        RPI::PassImageAttachmentDesc imageAttachment;
+        imageAttachment.m_name = "RenderTarget";
+        imageAttachment.m_lifetime = RHI::AttachmentLifetimeType::Imported;
+        imageAttachment.m_assetRef.m_assetId = m_renderTarget->GetAssetId();
+        createPassRequest.m_imageAttachmentOverrides.push_back(imageAttachment);
+
+        // Create the pass
+        m_renderTargetPass = RPI::PassSystemInterface::Get()->CreatePassFromRequest(&createPassRequest);
+
+        // add the pass to render pipeline
+        RPI::RenderPipelinePtr renderPipeline = m_scene->GetDefaultRenderPipeline();
+        RPI::Ptr<RPI::ParentPass> rootPass = renderPipeline->GetRootPass();
+        // Insert to the beginning so it will be done before all the other rendering
+        rootPass->InsertChild(m_renderTargetPass, RPI::ParentPass::ChildPassIndex(0));
+
+        // Add a preview pass to preview the render target
+        RPI::PassDescriptor descriptor(Name("RenderTargetPreview"));
+        m_previewPass = RPI::ImageAttachmentPreviewPass::Create(descriptor);
+        rootPass->AddChild(m_previewPass);
+
+        // we need process queued changes to build the pass properly 
+        // which Scene::RebuildPipelineStatesLookup() requires 
+        AZ::RPI::PassSystemInterface::Get()->ProcessQueuedChanges();
+        m_scene->RebuildPipelineStatesLookup();
+    }
+
+    void RenderTargetTextureExampleComponent::RemoveRenderTargetPass()
+    {
+        m_previewPass->ClearPreviewAttachment();
+        m_previewPass->QueueForRemoval();
+        m_previewPass = nullptr;
+
+        m_renderTargetPass->QueueForRemoval();
+        m_renderTargetPass = nullptr;
+        m_renderTarget = nullptr;
+    }
+
+    void RenderTargetTextureExampleComponent::CreateDynamicDraw()
+    {
+        const char* shaderFilepath = "Shaders/SimpleTextured.azshader";
+        AZ::Data::Instance<AZ::RPI::Shader> shader = AZ::RPI::LoadCriticalShader(shaderFilepath);
+
+        RHI::DrawListTagRegistry* drawListTagRegistry = RHI::RHISystemInterface::Get()->GetDrawListTagRegistry();
+        RHI::DrawListTag newTag = drawListTagRegistry->FindTag(m_renderTargetPassDrawListTag);
+
+        
+        AZ::RPI::ShaderOptionList shaderOptions;
+        shaderOptions.push_back(AZ::RPI::ShaderOption(AZ::Name("o_useColorChannels"), AZ::Name("true")));
+        shaderOptions.push_back(AZ::RPI::ShaderOption(AZ::Name("o_clamp"), AZ::Name("true")));
+
+        m_dynamicDraw = AZ::RPI::DynamicDrawInterface::Get()->CreateDynamicDrawContext();
+        m_dynamicDraw->InitDrawListTag(newTag);
+        m_dynamicDraw->InitShaderWithVariant(shader, &shaderOptions);
+        m_dynamicDraw->InitVertexFormat(
+            { {"POSITION", AZ::RHI::Format::R32G32B32_FLOAT},
+            {"COLOR", AZ::RHI::Format::B8G8R8A8_UNORM},
+            {"TEXCOORD0", AZ::RHI::Format::R32G32_FLOAT} });
+
+        m_dynamicDraw->AddDrawStateOptions(RPI::DynamicDrawContext::DrawStateOptions::BlendMode);
+        m_dynamicDraw->SetOutputScope(m_scene);
+        m_dynamicDraw->EndInit();
+                
+        RHI::TargetBlendState blendState;
+        blendState.m_enable = false;
+        m_dynamicDraw->SetTarget0BlendState(blendState);
+
+        // load texture used for the dynamic draw
+        m_texture = AZ::RPI::LoadStreamingTexture(TextureFilePath);
+    }
+
+    void RenderTargetTextureExampleComponent::OnAllAssetsReadyActivate()
+    {
+        // create render target pass
+        AddRenderTargetPass();
+
+        CreateDynamicDraw();
+
+        // load mesh and material
+        auto meshFeatureProcessor = GetMeshFeatureProcessor();
+        // material
+        auto materialAsset = RPI::AssetUtils::LoadAssetByProductPath<RPI::MaterialAsset>(DefaultPbrMaterialPath,
+            RPI::AssetUtils::TraceLevel::Assert);
+        m_material = AZ::RPI::Material::FindOrCreate(materialAsset);
+        // bunny mesh
+        auto bunnyAsset = RPI::AssetUtils::LoadAssetByProductPath<RPI::ModelAsset>(BunnyModelFilePath,
+            RPI::AssetUtils::TraceLevel::Assert);
+        m_meshHandle = meshFeatureProcessor->AcquireMesh(Render::MeshHandleDescriptor{ bunnyAsset }, m_material);
+        meshFeatureProcessor->SetTransform(m_meshHandle, Transform::CreateTranslation(Vector3(0.f, 0.f, 0.21f)));
+
+        // Set camera to use no clip controller and adjust its fov and transform
+        AZ::Debug::CameraControllerRequestBus::Event(GetCameraEntityId(), &AZ::Debug::CameraControllerRequestBus::Events::Enable,
+            azrtti_typeid<AZ::Debug::NoClipControllerComponent>());
+        AZ::Debug::NoClipControllerRequestBus::Event(GetCameraEntityId(), &AZ::Debug::NoClipControllerRequestBus::Events::SetFov, AZ::DegToRad(90));
+        AZ::Debug::NoClipControllerRequestBus::Event(GetCameraEntityId(), &AZ::Debug::NoClipControllerRequestBus::Events::SetPosition, Vector3(1.244541f, -0.660081f, 1.902831f));
+        AZ::Debug::NoClipControllerRequestBus::Event(GetCameraEntityId(), &AZ::Debug::NoClipControllerRequestBus::Events::SetHeading, AZ::DegToRad(61.274673f));
+        AZ::Debug::NoClipControllerRequestBus::Event(GetCameraEntityId(), &AZ::Debug::NoClipControllerRequestBus::Events::SetPitch, AZ::DegToRad(-36.605690f));
+
+        // Setup IBL
+        m_ibl.Init(m_scene);
+
+        // set render target texture to material
+        auto propertyId = m_material->FindPropertyIndex(AZ::Name{ "baseColor.textureMap" });
+        auto image = RPI::AttachmentImage::FindByUniqueName(Name("$RT1"));
+        if (propertyId.IsValid())
+        {
+            m_baseColorTexture = m_material->GetPropertyValue<Data::Instance<RPI::Image>>(propertyId);
+            m_material->SetPropertyValue(propertyId, (Data::Instance<RPI::Image>)image);
+        }
+        else
+        {
+            AZ_Error("ASV", false, "Failed to file property 'baseColor.textureMap' in the material");
+        }
+
+        AZ::TickBus::Handler::BusConnect();
+        m_imguiSidebar.Activate();
+        ScriptRunnerRequestBus::Broadcast(&ScriptRunnerRequests::ResumeScript);
+
+        UpdateRenderTargetPreview();
+    }
+
+    void RenderTargetTextureExampleComponent::Deactivate()
+    {
+        AZ::TickBus::Handler::BusDisconnect();
+
+        m_imguiSidebar.Deactivate();
+
+        // release model and mesh
+        GetMeshFeatureProcessor()->ReleaseMesh(m_meshHandle);
+        m_material = nullptr;
+        m_baseColorTexture = nullptr;
+        m_modelAsset = {};
+
+        m_ibl.Reset();
+
+        AZ::Debug::CameraControllerRequestBus::Event(GetCameraEntityId(), &AZ::Debug::CameraControllerRequestBus::Events::Disable);
+
+        // Release dynamic draw context
+        m_dynamicDraw = nullptr;
+
+        RemoveRenderTargetPass(); 
+    }
+
+    void RenderTargetTextureExampleComponent::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time)
+    {
+        // Note, the Compile function need to be called to apply material property change in the next frame after material was created which called copmile()
+        // Compile() only can be called once per frame
+        if (m_material->NeedsCompile())
+        {
+            m_material->Compile();
+        }
+
+        bool drawToRenderTarget = false;
+        if (m_imguiSidebar.Begin())
+        {
+            if (ScriptableImGui::Button("Next Frame"))
+            {
+                drawToRenderTarget = true;
+                m_currentFrame = (m_currentFrame+1)%4;
+            }
+            
+            ImGui::Separator();
+            
+            if (ScriptableImGui::Checkbox("Show Preview", &m_showRenderTargetPreview))
+            {
+                UpdateRenderTargetPreview();
+            }
+            
+            ImGui::Separator();
+            ScriptableImGui::Checkbox("Update Per Second", &m_updatePerSecond);
+
+            if (m_updatePerSecond)
+            {
+                auto currentTime = time.GetSeconds();
+                if (currentTime > m_lastUpdateTime + 1)
+                {                
+                    drawToRenderTarget = true;
+                    m_lastUpdateTime = currentTime;
+                    m_currentFrame = (m_currentFrame+1)%4;
+                }
+            }
+            else if (m_lastUpdateTime == 0)
+            {
+                drawToRenderTarget = true;
+                m_lastUpdateTime = time.GetSeconds();
+            }
+
+            ImGui::Separator();
+            ImGui::Text("Current frame: %d", m_currentFrame+1);
+
+            m_imguiSidebar.End();
+        }
+
+        // have to disable the pass if there is no drawing. otherwise the render target would be cleared.
+        m_renderTargetPass->SetEnabled(drawToRenderTarget);
+
+        if (drawToRenderTarget)
+        {
+            // Draw something to the render target pass
+            DrawToRenderTargetPass();
+        }
+    }
+
+    void RenderTargetTextureExampleComponent::UpdateRenderTargetPreview()
+    {
+        if (m_showRenderTargetPreview)
+        {
+            // Add attachment preview after pass queued changes processed
+            // m_renderTargetPass only has one attachment
+                m_previewPass->PreviewImageAttachmentForPass(m_renderTargetPass.get(), m_renderTargetPass->GetAttachmentBindings()[0].m_attachment.get());
+        }
+        else
+        {
+            m_previewPass->ClearPreviewAttachment();
+        }
+    }
+   
+    void RenderTargetTextureExampleComponent::DrawToRenderTargetPass()
+    {
+        const int numVerts = 4;
+        const int numFrames = 4;
+        struct Vertex
+        {
+            float position[3];
+            uint32_t color;
+            float uv[2];
+        };
+
+        uint32_t colors[numFrames] =
+        {
+            0xff0000ff,
+            0xffff00ff,
+            0xff00ffff,
+            0xffffffff
+        };
+
+        float uvoffset[numFrames][2] = 
+        {
+            {0, 0.5f},
+            {0.5f, 0.5f},
+            {0, 0},
+            {0.5f, 0},
+        };
+
+        Vertex vertices[numVerts];
+
+        // Create a vertex offset from the position to draw from based on the icon size
+        // Vertex positions are in screen space coordinates
+        auto createVertex = [&](float x, float y, float u, float v) -> Vertex
+        {
+            Vertex vertex;
+            vertex.position[0] = x;
+            vertex.position[1] = y;
+            vertex.position[2] = 0.5f;
+            vertex.color = colors[m_currentFrame];
+            vertex.uv[0] = u + uvoffset[m_currentFrame][0];
+            vertex.uv[1] = v + uvoffset[m_currentFrame][1];
+            return vertex;
+        };
+
+        vertices[0] = createVertex(0.f, 0.f, 0.f, 0.f);
+        vertices[1] = createVertex(0.f, 1.f, 0.f, 0.5f);
+        vertices[2] = createVertex(1.f, 1.f, 0.5f, 0.5f);
+        vertices[3] = createVertex(1.f, 0.f, 0.5f, 0.f);
+        
+        using Indice = AZ::u16;
+        AZStd::array<Indice, 6> indices = {0, 1, 2, 0, 2, 3};
+
+        // setup draw srg
+        auto drawSrg = m_dynamicDraw->NewDrawSrg();
+        
+        AZ::RHI::ShaderInputNameIndex imageInputIndex = "m_texture";
+        AZ::RHI::ShaderInputNameIndex viewProjInputIndex = "m_worldToProj";
+
+        // Set projection matrix
+        const float viewX = 0;
+        const float viewY = 0;
+        const float viewWidth = 1;
+        const float viewHeight = 1;
+        const float zf = 0;
+        const float zn = 1;
+        AZ::Matrix4x4 modelViewProjMat;
+        AZ::MakeOrthographicMatrixRH(modelViewProjMat, viewX, viewX + viewWidth, viewY + viewHeight, viewY, zn, zf);
+        drawSrg->SetConstant(viewProjInputIndex, modelViewProjMat);
+        drawSrg->SetImage(imageInputIndex, m_texture);
+
+        drawSrg->Compile();
+
+        m_dynamicDraw->DrawIndexed(vertices, numVerts, &indices, aznumeric_cast<uint32_t>(indices.size()), RHI::IndexFormat::Uint16, drawSrg);
+    }
+} // namespace AtomSampleViewer

+ 101 - 0
Gem/Code/Source/RenderTargetTextureExampleComponent.h

@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#pragma once
+
+#include <CommonSampleComponentBase.h>
+
+#include <AzCore/Component/EntityBus.h>
+#include <AzCore/Component/TickBus.h>
+
+#include <Utils/Utils.h>
+#include <Utils/ImGuiSidebar.h>
+
+#include <Atom/Feature/ImGui/ImGuiUtils.h>
+#include <Atom/RPI.Public/DynamicDraw/DynamicDrawContext.h>
+#include <Atom/RPI.Public/Image/AttachmentImage.h>
+#include <Atom/RPI.Public/Pass/Specific/ImageAttachmentPreviewPass.h>
+
+
+namespace AtomSampleViewer
+{
+    // This example shows how to use a render target as a texture for a mesh's material.
+    // It does following things:
+    // 1. creates a raster pass at runtime with one render target 
+    // 2. the render target is used as a texture input for a standard pbr material
+    // 3. A mesh with this material is rendered to the scene with IBL lighting. 
+    class RenderTargetTextureExampleComponent final
+        : public CommonSampleComponentBase
+        , public AZ::TickBus::Handler
+    {
+    public:
+        AZ_COMPONENT(RenderTargetTextureExampleComponent, "{43069FB5-EE01-4799-8870-3CFC422D09DF}", CommonSampleComponentBase);
+
+        static void Reflect(AZ::ReflectContext* context);
+
+        RenderTargetTextureExampleComponent();
+        ~RenderTargetTextureExampleComponent() override = default;
+
+        // AZ::Component overrides...
+        void Activate() override;
+        void Deactivate() override;
+
+    private:
+        // AZ::TickBus::Handler overrides...
+        void OnTick(float deltaTime, AZ::ScriptTimePoint time) override;
+
+        // CommonSampleComponentBase overrides...
+        void OnAllAssetsReadyActivate() override;
+
+        // create the pass render to a render target and add it to render pipeline
+        void AddRenderTargetPass();
+
+        void CreateDynamicDraw();
+
+        // Remove the render target pass
+        void RemoveRenderTargetPass();
+
+        void DrawToRenderTargetPass();
+
+        // show or hide render target preview
+        void UpdateRenderTargetPreview();
+
+        // Rendering content
+        // Mesh
+        AZ::Render::MeshFeatureProcessorInterface::MeshHandle m_meshHandle;
+        AZ::Data::Asset<AZ::RPI::ModelAsset> m_modelAsset;
+
+        // materiala and texture
+        AZ::Data::Instance<AZ::RPI::Material> m_material; 
+        AZ::Data::Instance<AZ::RPI::Image> m_baseColorTexture;
+
+        Utils::DefaultIBL m_ibl;
+
+        // render target
+        AZ::RHI::Ptr<AZ::RPI::Pass> m_renderTargetPass;
+        AZ::Data::Instance<AZ::RPI::AttachmentImage> m_renderTarget;
+        AZ::Name m_renderTargetPassDrawListTag;
+        
+        // to preview the render target
+        AZ::RPI::Ptr<AZ::RPI::ImageAttachmentPreviewPass> m_previewPass;
+
+        // For render something to render target pass
+        AZ::RHI::Ptr<AZ::RPI::DynamicDrawContext> m_dynamicDraw;
+        AZ::Data::Instance<AZ::RPI::Image> m_texture;
+        uint32_t m_currentFrame = 0;
+
+        // for ImGui ui
+        bool m_updatePerSecond = false;
+        double m_lastUpdateTime = 0;
+        bool m_showRenderTargetPreview = true;
+
+        // UI
+        ImGuiSidebar m_imguiSidebar;
+
+    };
+} // namespace AtomSampleViewer

+ 26 - 9
Gem/Code/Source/SampleComponentManager.cpp

@@ -65,6 +65,9 @@
 #include <RHI/RayTracingExampleComponent.h>
 #include <RHI/MatrixAlignmentTestExampleComponent.h>
 
+#include <Performance/100KDrawable_SingleView_ExampleComponent.h>
+#include <Performance/100KDraw_10KDrawable_MultiView_ExampleComponent.h>
+
 #include <AreaLightExampleComponent.h>
 #include <AssetLoadTestComponent.h>
 #include <AuxGeomExampleComponent.h>
@@ -86,6 +89,7 @@
 #include <MultiRenderPipelineExampleComponent.h>
 #include <MultiSceneExampleComponent.h>
 #include <ParallaxMappingExampleComponent.h>
+#include <RenderTargetTextureExampleComponent.h>
 #include <SceneReloadSoakTestComponent.h>
 #include <ShadowExampleComponent.h>
 #include <ShadowedSponzaExampleComponent.h>
@@ -99,7 +103,6 @@
 #include <DiffuseGIExampleComponent.h>
 #include <SSRExampleComponent.h>
 #include <ShaderReloadTestComponent.h>
-#include <HighInstanceExampleComponent.h>
 
 #include <Atom/Bootstrap/DefaultWindowBus.h>
 
@@ -208,6 +211,18 @@ namespace AtomSampleViewer
         return NewSample<T>(SamplePipelineType::RPI, "Features", name, isSupportedFunction);
     }
 
+    template <typename T>
+    static SampleEntry NewPerfSample(const AZStd::string& name)
+    {
+        return NewSample<T>(SamplePipelineType::RPI, "Performance", name);
+    }
+
+    template <typename T>
+    static SampleEntry NewPerfSample(const AZStd::string& name, AZStd::function<bool()> isSupportedFunction)
+    {
+        return NewSample<T>(SamplePipelineType::RPI, "Performance", name, isSupportedFunction);
+    }
+
     void SampleComponentManager::Reflect(AZ::ReflectContext* context)
     {
         if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
@@ -265,13 +280,13 @@ namespace AtomSampleViewer
             NewRPISample<DecalExampleComponent>("Decals"),
             NewRPISample<DynamicDrawExampleComponent>("DynamicDraw"),
             NewRPISample<DynamicMaterialTestComponent>("DynamicMaterialTest"),
-            NewRPISample<HighInstanceTestComponent>("HighInstanceTest"),
             NewRPISample<MaterialHotReloadTestComponent>("MaterialHotReloadTest"),
             NewRPISample<MeshExampleComponent>("Mesh"),
             NewRPISample<MSAA_RPI_ExampleComponent>("MSAA"),
             NewRPISample<MultiRenderPipelineExampleComponent>("MultiRenderPipeline"),
             NewRPISample<MultiSceneExampleComponent>("MultiScene"),
             NewRPISample<MultiViewSingleSceneAuxGeomExampleComponent>("MultiViewSingleSceneAuxGeom"),
+            NewRPISample<RenderTargetTextureExampleComponent>("RenderTargetTexture"),
             NewRPISample<RootConstantsExampleComponent>("RootConstants"),
             NewRPISample<SceneReloadSoakTestComponent>("SceneReloadSoakTest"),
             NewRPISample<StreamingImageExampleComponent>("StreamingImage"),
@@ -290,6 +305,8 @@ namespace AtomSampleViewer
             NewFeaturesSample<SSRExampleComponent>("SSR"),
             NewFeaturesSample<TonemappingExampleComponent>("Tonemapping"),
             NewFeaturesSample<TransparencyExampleComponent>("Transparency"),
+            NewPerfSample<_100KDrawableExampleComponent>("100KDrawable_SingleView"),
+            NewPerfSample<_100KDraw10KDrawableExampleComponent>("100KDraw_10KDrawable_MultiView"),
         };
     }
 
@@ -304,7 +321,7 @@ namespace AtomSampleViewer
 
     SampleComponentManager::SampleComponentManager()
         : m_imguiFrameCaptureSaver("@user@/frame_capture.xml")
-        , m_imGuiFrameTimer(FrameTimeLogSize, FrameTimeLogSize)
+        , m_imGuiFrameTimer(FrameTimeLogSize, FrameTimeLogSize, 250.0f)
     {
         m_exampleEntity = aznew AZ::Entity();
 
@@ -505,7 +522,7 @@ namespace AtomSampleViewer
 
     void SampleComponentManager::OnTick(float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time)
     {
-        m_imGuiFrameTimer.PushValue(deltaTime);
+        m_imGuiFrameTimer.PushValue(deltaTime * 1000.0f);
 
         bool screenshotRequest = false;
 
@@ -859,7 +876,7 @@ namespace AtomSampleViewer
                     Utils::ToggleFullScreenOfDefaultWindow();
                 }
 
-                if (ImGui::MenuItem("Framerate Histogram"))
+                if (ImGui::MenuItem("Frame Time Histogram"))
                 {
                     m_showFramerateHistogram = !m_showFramerateHistogram;
                 }
@@ -1137,12 +1154,12 @@ namespace AtomSampleViewer
 
     void SampleComponentManager::ShowFramerateHistogram(float deltaTime)
     {
-        if (ImGui::Begin("Framerate Histogram", &m_showFramerateHistogram, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings))
+        if (ImGui::Begin("Frame Time Histogram", &m_showFramerateHistogram, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings))
         {
             ImGuiHistogramQueue::WidgetSettings settings;
-            settings.m_reportInverse = true;
-            settings.m_units = "fps";
-            m_imGuiFrameTimer.Tick(deltaTime, settings);
+            settings.m_reportInverse = false;
+            settings.m_units = "ms";
+            m_imGuiFrameTimer.Tick(deltaTime * 1000.0f, settings);
         }
         ImGui::End();
     }

+ 1 - 1
Gem/Code/Source/SampleComponentManager.h

@@ -196,7 +196,7 @@ namespace AtomSampleViewer
 
         int32_t m_selectedSampleIndex = -1;
 
-        static constexpr uint32_t FrameTimeLogSize = 10;
+        static constexpr uint32_t FrameTimeLogSize = 30;
         ImGuiHistogramQueue m_imGuiFrameTimer;
 
         bool m_showImGuiMetrics = false;

+ 112 - 105
Gem/Code/Source/Utils/ImGuiHistogramQueue.cpp

@@ -1,105 +1,112 @@
-/*
- * Copyright (c) Contributors to the Open 3D Engine Project.
- * For complete copyright and license terms please see the LICENSE at the root of this distribution.
- *
- * SPDX-License-Identifier: Apache-2.0 OR MIT
- *
- */
-
-#include <Utils/ImGuiHistogramQueue.h>
-#include <AzCore/std/string/string.h>
-#include <imgui/imgui.h>
-
-namespace AtomSampleViewer
-{
-
-    ImGuiHistogramQueue::ImGuiHistogramQueue(
-        AZStd::size_t maxSamples,
-        AZStd::size_t runningAverageSamples,
-        float numericDisplayUpdateDelay)
-        : m_maxSamples(maxSamples)
-        , m_runningAverageSamples(runningAverageSamples)
-        , m_numericDisplayDelay(numericDisplayUpdateDelay)
-    {
-        AZ_Assert(m_maxSamples >= m_runningAverageSamples, "maxSamples must be larger");
-
-        m_valueLog.reserve(m_maxSamples);
-        m_averageLog.reserve(m_maxSamples);
-    }
-
-    float ImGuiHistogramQueue::CalculateAverage(AZStd::size_t maxSampleCount)
-    {
-        size_t sampleCount = AZStd::min<size_t>(maxSampleCount, m_valueLog.size());
-
-        float average = 0.0f;
-        for (size_t i = 0; i < sampleCount; ++i)
-        {
-            average += m_valueLog.at(i);
-        }
-        average /= sampleCount;
-
-        return average;
-    }
-
-    void ImGuiHistogramQueue::PushValue(float value)
-    {
-        m_samplesSinceLastDisplayUpdate++;
-
-        // Update the log of all values
-        if (m_valueLog.size() == m_maxSamples)
-        {
-            m_valueLog.pop_back();
-        }
-        m_valueLog.insert(m_valueLog.begin(), value);
-
-        // Calculate running average for line graph
-        if (m_averageLog.size() == m_maxSamples)
-        {
-            m_averageLog.pop_back();
-        }
-        m_averageLog.insert(m_averageLog.begin(), CalculateAverage(m_runningAverageSamples));
-
-        // Calculate average for numeric display
-        if (m_timeSinceLastDisplayUpdate >= m_numericDisplayDelay || m_samplesSinceLastDisplayUpdate >= m_maxSamples)
-        {
-            m_displayedAverage = CalculateAverage(m_samplesSinceLastDisplayUpdate);
-
-            m_timeSinceLastDisplayUpdate = 0.0f;
-            m_samplesSinceLastDisplayUpdate = 0;
-        }
-    }
-
-    void ImGuiHistogramQueue::Tick(float deltaTime, WidgetSettings settings)
-    {
-        if (m_averageLog.empty() || m_valueLog.empty())
-        {
-            return;
-        }
-
-        m_timeSinceLastDisplayUpdate += deltaTime;
-
-        ImVec2 pos = ImGui::GetCursorPos();
-
-        AZStd::string valueString;
-        if (settings.m_reportInverse)
-        {
-            valueString  = AZStd::string::format("%4.2f %s", 1.0 / m_displayedAverage, settings.m_units);
-        }
-        else
-        {
-            valueString = AZStd::string::format("%4.2f %s", m_displayedAverage, settings.m_units);
-        }
-
-        // Draw moving average of values first
-        ImGui::PushStyleColor(ImGuiCol_PlotLines, ImVec4(0.6, 0.8, 0.9, 1.0));
-        ImGui::PlotLines("##Average", &m_averageLog[0], int32_t(m_averageLog.size()), 0, nullptr, 0.0f, m_displayedAverage * 2.0f, ImVec2(300, 50));
-        ImGui::PopStyleColor();
-
-        // Draw individual value bars on top of it (with no background).
-        ImGui::SetCursorPos(pos);
-        ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0, 0, 0, 0));
-        ImGui::PlotHistogram("##Value", &m_valueLog[0], int32_t(m_valueLog.size()), 0, valueString.c_str(), 0.0f, m_displayedAverage * 2.0f, ImVec2(300, 50));
-        ImGui::PopStyleColor();
-    }
-
-} // namespace AtomSampleViewer
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#include <Utils/ImGuiHistogramQueue.h>
+#include <AzCore/std/string/string.h>
+#include <imgui/imgui.h>
+
+namespace AtomSampleViewer
+{
+
+    ImGuiHistogramQueue::ImGuiHistogramQueue(
+        AZStd::size_t maxSamples,
+        AZStd::size_t runningAverageSamples,
+        float numericDisplayUpdateDelay)
+        : m_maxSamples(maxSamples)
+        , m_runningAverageSamples(runningAverageSamples)
+        , m_numericDisplayDelay(numericDisplayUpdateDelay)
+    {
+        AZ_Assert(m_maxSamples >= m_runningAverageSamples, "maxSamples must be larger");
+
+        m_valueLog.reserve(m_maxSamples);
+        m_averageLog.reserve(m_maxSamples);
+    }
+
+    float ImGuiHistogramQueue::UpdateDisplayedValues(AZStd::size_t maxSampleCount, float& minValue, float& maxValue)
+    {
+        size_t sampleCount = AZStd::min<size_t>(maxSampleCount, m_valueLog.size());
+        float average = 0.f;
+        if (sampleCount > 0)
+        {
+            average = m_valueLog.at(0);
+            minValue = maxValue = average;
+            for (size_t i = 1; i < sampleCount; ++i)
+            {
+                float curValue = m_valueLog.at(i);
+                average += curValue;
+                minValue = minValue > curValue ? curValue : minValue;
+                maxValue = maxValue < curValue ? curValue : maxValue;
+            }
+            average /= sampleCount;
+        }
+        return average;
+    }
+
+    void ImGuiHistogramQueue::PushValue(float value)
+    {
+        m_samplesSinceLastDisplayUpdate++;
+
+        // Update the log of all values
+        if (m_valueLog.size() == m_maxSamples)
+        {
+            m_valueLog.pop_back();
+        }
+        m_valueLog.insert(m_valueLog.begin(), value);
+
+        // Calculate running average for line graph
+        if (m_averageLog.size() == m_maxSamples)
+        {
+            m_averageLog.pop_back();
+        }
+        [[maybe_unused]] float minValue, maxValue; // unused required call parameters
+        m_averageLog.insert(m_averageLog.begin(), UpdateDisplayedValues(m_runningAverageSamples, minValue, maxValue));
+
+        // Calculate average for numeric display
+        if (m_timeSinceLastDisplayUpdate >= m_numericDisplayDelay || m_samplesSinceLastDisplayUpdate >= m_maxSamples)
+        {
+            m_displayedAverage = UpdateDisplayedValues(m_samplesSinceLastDisplayUpdate, m_displayedMinimum, m_displayedMaximum);
+
+            m_timeSinceLastDisplayUpdate = 0.0f;
+            m_samplesSinceLastDisplayUpdate = 0;
+        }
+    }
+
+    void ImGuiHistogramQueue::Tick(float deltaTime, WidgetSettings settings)
+    {
+        if (m_averageLog.empty() || m_valueLog.empty())
+        {
+            return;
+        }
+
+        m_timeSinceLastDisplayUpdate += deltaTime;
+
+        ImVec2 pos = ImGui::GetCursorPos();
+
+        AZStd::string valueString;
+        if (settings.m_reportInverse)
+        {
+            valueString  = AZStd::string::format("%4.2f %s", 1.0 / m_displayedAverage, settings.m_units);
+        }
+        else
+        {
+            valueString = AZStd::string::format("avg:%4.2f %s | min:%4.2f %s | max:%4.2f %s ", m_displayedAverage, settings.m_units, m_displayedMinimum, settings.m_units, m_displayedMaximum, settings.m_units);
+        }
+
+        // Draw moving average of values first
+        ImGui::PushStyleColor(ImGuiCol_PlotLines, ImVec4(0.6, 0.8, 0.9, 1.0));
+        ImGui::PlotLines("##Average", &m_averageLog[0], int32_t(m_averageLog.size()), 0, nullptr, 0.0f, m_displayedAverage * 2.0f, ImVec2(400, 50));
+        ImGui::PopStyleColor();
+
+        // Draw individual value bars on top of it (with no background).
+        ImGui::SetCursorPos(pos);
+        ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0, 0, 0, 0));
+        ImGui::PlotHistogram("##Value", &m_valueLog[0], int32_t(m_valueLog.size()), 0, valueString.c_str(), 0.0f, m_displayedAverage * 2.0f, ImVec2(400, 50));
+        ImGui::PopStyleColor();
+    }
+
+} // namespace AtomSampleViewer

+ 59 - 55
Gem/Code/Source/Utils/ImGuiHistogramQueue.h

@@ -1,55 +1,59 @@
-/*
- * Copyright (c) Contributors to the Open 3D Engine Project.
- * For complete copyright and license terms please see the LICENSE at the root of this distribution.
- *
- * SPDX-License-Identifier: Apache-2.0 OR MIT
- *
- */
-
-#pragma once
-
-#include <AzCore/std/containers/vector.h>
-
-namespace AtomSampleViewer
-{
-    //! Tracks time values over multiple frames, computes the average, and draws a historgram.
-    class ImGuiHistogramQueue 
-    {
-    public:
-        //! @param maxSamples the max number of samples that can be recorded in the queue and displayed in the histogram
-        //! @param runningAverageSamples the number of samples to use for calculating running average hash-marks that are overlaid on the histogram
-        //! @param numericDisplayUpdateDelay the number of seconds to delay between updates of the numeric display
-        ImGuiHistogramQueue(
-            AZStd::size_t maxSamples,
-            AZStd::size_t runningAverageSamples,
-            float numericDisplayUpdateDelay = 0.25f);
-
-        struct WidgetSettings
-        {
-            bool m_reportInverse = false; //!< Use 1/average instead of average for displaying the numeric value
-            const char* m_units = "";
-        };
-
-        void PushValue(float value);
-        void Tick(float deltaTime, WidgetSettings settings);
-
-        float GetDisplayedAverage() const { return m_displayedAverage; }
-
-    private:
-
-        float CalculateAverage(AZStd::size_t maxSampleCount);
-
-        AZStd::vector<float> m_valueLog;
-        AZStd::vector<float> m_averageLog;
-
-        const AZStd::size_t m_maxSamples;
-        const AZStd::size_t m_runningAverageSamples;
-        const float m_numericDisplayDelay;
-
-        float m_timeSinceLastDisplayUpdate = 0.0f;
-        int m_samplesSinceLastDisplayUpdate = 0;
-
-        float m_displayedAverage = 0.0f;
-    };
-
-} // namespace AtomSampleViewer
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#pragma once
+
+#include <AzCore/std/containers/vector.h>
+
+namespace AtomSampleViewer
+{
+    //! Tracks time values over multiple frames, computes the average, and draws a historgram.
+    class ImGuiHistogramQueue 
+    {
+    public:
+        //! @param maxSamples the max number of samples that can be recorded in the queue and displayed in the histogram
+        //! @param runningAverageSamples the number of samples to use for calculating running average hash-marks that are overlaid on the histogram
+        //! @param numericDisplayUpdateDelay the number of seconds to delay between updates of the numeric display
+        ImGuiHistogramQueue(
+            AZStd::size_t maxSamples,
+            AZStd::size_t runningAverageSamples,
+            float numericDisplayUpdateDelay = 0.25f);
+
+        struct WidgetSettings
+        {
+            bool m_reportInverse = false; //!< Use 1/average instead of average for displaying the numeric value
+            const char* m_units = "";
+        };
+
+        void PushValue(float value);
+        void Tick(float deltaTime, WidgetSettings settings);
+
+        float GetDisplayedAverage() const { return m_displayedAverage; }
+        float GetDisplayedMinimum() const { return m_displayedMinimum; }
+        float GetDisplayedMaximum() const { return m_displayedMaximum; }
+
+    private:
+
+        float UpdateDisplayedValues(AZStd::size_t maxSampleCount, float& minValue, float& maxValue);
+
+        AZStd::vector<float> m_valueLog;
+        AZStd::vector<float> m_averageLog;
+
+        const AZStd::size_t m_maxSamples;
+        const AZStd::size_t m_runningAverageSamples;
+        const float m_numericDisplayDelay;
+
+        float m_timeSinceLastDisplayUpdate = 0.0f;
+        int m_samplesSinceLastDisplayUpdate = 0;
+
+        float m_displayedAverage = 0.0f;
+        float m_displayedMinimum = 0.0f;
+        float m_displayedMaximum = 0.0f;
+    };
+
+} // namespace AtomSampleViewer

+ 8 - 2
Gem/Code/atomsampleviewergem_private_files.cmake

@@ -82,6 +82,12 @@ set(FILES
     Source/RHI/RayTracingExampleComponent.h
     Source/RHI/MatrixAlignmentTestExampleComponent.cpp
     Source/RHI/MatrixAlignmentTestExampleComponent.h
+    Source/Performance/HighInstanceExampleComponent.cpp
+    Source/Performance/HighInstanceExampleComponent.h
+    Source/Performance/100KDrawable_SingleView_ExampleComponent.cpp
+    Source/Performance/100KDrawable_SingleView_ExampleComponent.h
+    Source/Performance/100KDraw_10KDrawable_MultiView_ExampleComponent.cpp
+    Source/Performance/100KDraw_10KDrawable_MultiView_ExampleComponent.h
     Source/AreaLightExampleComponent.cpp
     Source/AreaLightExampleComponent.h
     Source/AssetLoadTestComponent.cpp
@@ -120,8 +126,6 @@ set(FILES
     Source/EntityUtilityFunctions.h
     Source/ExposureExampleComponent.cpp
     Source/ExposureExampleComponent.h
-    Source/HighInstanceExampleComponent.cpp
-    Source/HighInstanceExampleComponent.h
     Source/LightCullingExampleComponent.cpp
     Source/LightCullingExampleComponent.h
     Source/MaterialHotReloadTestComponent.cpp
@@ -145,6 +149,8 @@ set(FILES
     Source/ProceduralSkinnedMesh.h
     Source/ProceduralSkinnedMeshUtils.cpp
     Source/ProceduralSkinnedMeshUtils.h
+    Source/RenderTargetTextureExampleComponent.cpp
+    Source/RenderTargetTextureExampleComponent.h
     Source/RootConstantsExampleComponent.h
     Source/RootConstantsExampleComponent.cpp
     Source/SceneReloadSoakTestComponent.cpp

+ 16 - 34
Materials/Decal/airship_nose_number_decal.material

@@ -1,39 +1,21 @@
 {
-    "description": "",
     "materialType": "Materials\\Types\\StandardPBR.materialtype",
-    "parentMaterial": "",
     "materialTypeVersion": 3,
-    "properties": {
-        "baseColor": {
-            "textureMap": "Materials/Decal/airship_nose_number_decal.tif"
-        },
-        "general": {
-            "applySpecularAA": false
-        },
-        "metallic": {
-            "useTexture": false
-        },
-        "normal": {
-            "textureMap": "Materials/Decal/airship_nose_number_decal_nrm.tif"
-        },
-        "opacity": {
-            "alphaSource": "Split",
-            "doubleSided": true,
-            "factor": 0.6899999976158142,
-            "mode": "Cutout",
-            "textureMap": "Materials/Decal/airship_nose_number_decal.tif"
-        },
-        "roughness": {
-            "useTexture": false
-        },
-        "specularF0": {
-            "useTexture": false
-        },
-        "uv": {
-            "center": [
-                0.0,
-                1.0
-            ]
-        }
+    "propertyValues": {
+        "baseColor.textureMap": "Materials/Decal/airship_nose_number_decal.tif",
+        "general.applySpecularAA": false,
+        "metallic.useTexture": false,
+        "normal.textureMap": "Materials/Decal/airship_nose_number_decal_nrm.tif",
+        "opacity.alphaSource": "Split",
+        "opacity.doubleSided": true,
+        "opacity.factor": 0.6899999976158142,
+        "opacity.mode": "Cutout",
+        "opacity.textureMap": "Materials/Decal/airship_nose_number_decal.tif",
+        "roughness.useTexture": false,
+        "specularF0.useTexture": false,
+        "uv.center": [
+            0.0,
+            1.0
+        ]
     }
 }

+ 16 - 34
Materials/Decal/airship_symbol_decal.material

@@ -1,39 +1,21 @@
 {
-    "description": "",
     "materialType": "Materials\\Types\\StandardPBR.materialtype",
-    "parentMaterial": "",
     "materialTypeVersion": 3,
-    "properties": {
-        "baseColor": {
-            "textureMap": "Materials/Decal/airship_symbol_decal.tif"
-        },
-        "general": {
-            "applySpecularAA": false
-        },
-        "metallic": {
-            "useTexture": false
-        },
-        "normal": {
-            "textureMap": "Materials/Decal/airship_symbol_decal_nrm.tif"
-        },
-        "opacity": {
-            "alphaSource": "Split",
-            "doubleSided": true,
-            "factor": 0.6899999976158142,
-            "mode": "Cutout",
-            "textureMap": "Materials/Decal/airship_symbol_decal.tif"
-        },
-        "roughness": {
-            "useTexture": false
-        },
-        "specularF0": {
-            "useTexture": false
-        },
-        "uv": {
-            "center": [
-                0.0,
-                1.0
-            ]
-        }
+    "propertyValues": {
+        "baseColor.textureMap": "Materials/Decal/airship_symbol_decal.tif",
+        "general.applySpecularAA": false,
+        "metallic.useTexture": false,
+        "normal.textureMap": "Materials/Decal/airship_symbol_decal_nrm.tif",
+        "opacity.alphaSource": "Split",
+        "opacity.doubleSided": true,
+        "opacity.factor": 0.6899999976158142,
+        "opacity.mode": "Cutout",
+        "opacity.textureMap": "Materials/Decal/airship_symbol_decal.tif",
+        "roughness.useTexture": false,
+        "specularF0.useTexture": false,
+        "uv.center": [
+            0.0,
+            1.0
+        ]
     }
 }

+ 16 - 34
Materials/Decal/airship_tail_01_decal.material

@@ -1,39 +1,21 @@
 {
-    "description": "",
     "materialType": "Materials\\Types\\StandardPBR.materialtype",
-    "parentMaterial": "",
     "materialTypeVersion": 3,
-    "properties": {
-        "baseColor": {
-            "textureMap": "Materials/Decal/airship_tail_01_decal.tif"
-        },
-        "general": {
-            "applySpecularAA": false
-        },
-        "metallic": {
-            "useTexture": false
-        },
-        "normal": {
-            "textureMap": "Materials/Decal/airship_tail_01_decal_nrm.tif"
-        },
-        "opacity": {
-            "alphaSource": "Split",
-            "doubleSided": true,
-            "factor": 0.6899999976158142,
-            "mode": "Cutout",
-            "textureMap": "Materials/Decal/airship_tail_01_decal_nrm.tif"
-        },
-        "roughness": {
-            "useTexture": false
-        },
-        "specularF0": {
-            "useTexture": false
-        },
-        "uv": {
-            "center": [
-                0.0,
-                1.0
-            ]
-        }
+    "propertyValues": {
+        "baseColor.textureMap": "Materials/Decal/airship_tail_01_decal.tif",
+        "general.applySpecularAA": false,
+        "metallic.useTexture": false,
+        "normal.textureMap": "Materials/Decal/airship_tail_01_decal_nrm.tif",
+        "opacity.alphaSource": "Split",
+        "opacity.doubleSided": true,
+        "opacity.factor": 0.6899999976158142,
+        "opacity.mode": "Cutout",
+        "opacity.textureMap": "Materials/Decal/airship_tail_01_decal_nrm.tif",
+        "roughness.useTexture": false,
+        "specularF0.useTexture": false,
+        "uv.center": [
+            0.0,
+            1.0
+        ]
     }
 }

+ 16 - 34
Materials/Decal/airship_tail_02_decal.material

@@ -1,39 +1,21 @@
 {
-    "description": "",
     "materialType": "Materials\\Types\\StandardPBR.materialtype",
-    "parentMaterial": "",
     "materialTypeVersion": 3,
-    "properties": {
-        "baseColor": {
-            "textureMap": "Materials/Decal/airship_tail_02_decal.tif"
-        },
-        "general": {
-            "applySpecularAA": false
-        },
-        "metallic": {
-            "useTexture": false
-        },
-        "normal": {
-            "textureMap": "Materials/Decal/airship_tail_02_decal_nrm.tif"
-        },
-        "opacity": {
-            "alphaSource": "Split",
-            "doubleSided": true,
-            "factor": 0.6899999976158142,
-            "mode": "Cutout",
-            "textureMap": "Materials/Decal/airship_tail_02_decal.tif"
-        },
-        "roughness": {
-            "useTexture": false
-        },
-        "specularF0": {
-            "useTexture": false
-        },
-        "uv": {
-            "center": [
-                0.0,
-                1.0
-            ]
-        }
+    "propertyValues": {
+        "baseColor.textureMap": "Materials/Decal/airship_tail_02_decal.tif",
+        "general.applySpecularAA": false,
+        "metallic.useTexture": false,
+        "normal.textureMap": "Materials/Decal/airship_tail_02_decal_nrm.tif",
+        "opacity.alphaSource": "Split",
+        "opacity.doubleSided": true,
+        "opacity.factor": 0.6899999976158142,
+        "opacity.mode": "Cutout",
+        "opacity.textureMap": "Materials/Decal/airship_tail_02_decal.tif",
+        "roughness.useTexture": false,
+        "specularF0.useTexture": false,
+        "uv.center": [
+            0.0,
+            1.0
+        ]
     }
 }

+ 16 - 34
Materials/Decal/am_mud_decal.material

@@ -1,39 +1,21 @@
 {
-    "description": "",
     "materialType": "Materials\\Types\\StandardPBR.materialtype",
-    "parentMaterial": "",
     "materialTypeVersion": 3,
-    "properties": {
-        "baseColor": {
-            "textureMap": "Materials/Decal/am_mud_decal.tif"
-        },
-        "general": {
-            "applySpecularAA": false
-        },
-        "metallic": {
-            "useTexture": false
-        },
-        "normal": {
-            "textureMap": "Materials/Decal/am_mud_decal_nrm.tif"
-        },  
-        "opacity": {
-            "alphaSource": "Split",
-            "doubleSided": true,
-            "factor": 0.6899999976158142,
-            "mode": "Cutout",
-            "textureMap": "Materials/Decal/am_mud_decal.tif"
-        },
-        "roughness": {
-            "useTexture": false
-        },
-        "specularF0": {
-            "useTexture": false
-        },
-        "uv": {
-            "center": [
-                0.0,
-                1.0
-            ]
-        }
+    "propertyValues": {
+        "baseColor.textureMap": "Materials/Decal/am_mud_decal.tif",
+        "general.applySpecularAA": false,
+        "metallic.useTexture": false,
+        "normal.textureMap": "Materials/Decal/am_mud_decal_nrm.tif",
+        "opacity.alphaSource": "Split",
+        "opacity.doubleSided": true,
+        "opacity.factor": 0.6899999976158142,
+        "opacity.mode": "Cutout",
+        "opacity.textureMap": "Materials/Decal/am_mud_decal.tif",
+        "roughness.useTexture": false,
+        "specularF0.useTexture": false,
+        "uv.center": [
+            0.0,
+            1.0
+        ]
     }
 }

+ 16 - 34
Materials/Decal/am_road_dust_decal.material

@@ -1,39 +1,21 @@
 {
-    "description": "",
     "materialType": "Materials\\Types\\StandardPBR.materialtype",
-    "parentMaterial": "",
     "materialTypeVersion": 3,
-    "properties": {
-        "baseColor": {
-            "textureMap": "Materials/Decal/am_road_dust_decal.tif"
-        },
-        "general": {
-            "applySpecularAA": false
-        },
-        "metallic": {
-            "useTexture": false
-        },
-        "normal": {
-            "textureMap": "Materials/Decal/am_road_dust_decal_nrm.tif"
-        },
-        "opacity": {
-            "alphaSource": "Split",
-            "doubleSided": true,
-            "factor": 0.6899999976158142,
-            "mode": "Cutout",
-            "textureMap": "Materials/Decal/am_road_dust_decal.tif"
-        },
-        "roughness": {
-            "useTexture": false
-        },
-        "specularF0": {
-            "useTexture": false
-        },
-        "uv": {
-            "center": [
-                0.0,
-                1.0
-            ]
-        }
+    "propertyValues": {
+        "baseColor.textureMap": "Materials/Decal/am_road_dust_decal.tif",
+        "general.applySpecularAA": false,
+        "metallic.useTexture": false,
+        "normal.textureMap": "Materials/Decal/am_road_dust_decal_nrm.tif",
+        "opacity.alphaSource": "Split",
+        "opacity.doubleSided": true,
+        "opacity.factor": 0.6899999976158142,
+        "opacity.mode": "Cutout",
+        "opacity.textureMap": "Materials/Decal/am_road_dust_decal.tif",
+        "roughness.useTexture": false,
+        "specularF0.useTexture": false,
+        "uv.center": [
+            0.0,
+            1.0
+        ]
     }
 }

+ 16 - 34
Materials/Decal/brushstoke_01_decal.material

@@ -1,39 +1,21 @@
 {
-    "description": "",
     "materialType": "Materials\\Types\\StandardPBR.materialtype",
-    "parentMaterial": "",
     "materialTypeVersion": 3,
-    "properties": {
-        "baseColor": {
-            "textureMap": "Materials/Decal/brushstoke_01_decal.tif"
-        },
-        "general": {
-            "applySpecularAA": false
-        },
-        "metallic": {
-            "useTexture": false
-        },
-        "normal": {
-            "textureMap": "Materials/Decal/brushstoke_01_decal_nrm.tif"
-        },  
-        "opacity": {
-            "alphaSource": "Split",
-            "doubleSided": true,
-            "factor": 0.6899999976158142,
-            "mode": "Cutout",
-            "textureMap": "Materials/Decal/brushstoke_01_decal.tif"
-        },
-        "roughness": {
-            "useTexture": false
-        },
-        "specularF0": {
-            "useTexture": false
-        },
-        "uv": {
-            "center": [
-                0.0,
-                1.0
-            ]
-        }
+    "propertyValues": {
+        "baseColor.textureMap": "Materials/Decal/brushstoke_01_decal.tif",
+        "general.applySpecularAA": false,
+        "metallic.useTexture": false,
+        "normal.textureMap": "Materials/Decal/brushstoke_01_decal_nrm.tif",
+        "opacity.alphaSource": "Split",
+        "opacity.doubleSided": true,
+        "opacity.factor": 0.6899999976158142,
+        "opacity.mode": "Cutout",
+        "opacity.textureMap": "Materials/Decal/brushstoke_01_decal.tif",
+        "roughness.useTexture": false,
+        "specularF0.useTexture": false,
+        "uv.center": [
+            0.0,
+            1.0
+        ]
     }
 }

+ 15 - 31
Materials/Decal/scorch_01_decal.material

@@ -1,36 +1,20 @@
 {
-    "description": "",
     "materialType": "Materials/Types/StandardPBR.materialtype",
-    "parentMaterial": "",
     "materialTypeVersion": 3,
-    "properties": {
-        "baseColor": {
-            "textureMap": "Materials/Decal/scorch_01_decal.tif"
-        },
-        "metallic": {
-            "useTexture": false
-        },
-        "normal": {
-            "textureMap": "Materials/Decal/scorch_01_decal_nrm.tif"
-        }, 
-        "opacity": {
-            "alphaSource": "Split",
-            "doubleSided": true,
-            "factor": 0.6899999976158142,
-            "mode": "Cutout",
-            "textureMap": "Materials/Decal/scorch_01_decal.tif"
-        },
-        "roughness": {
-            "useTexture": false
-        },
-        "specularF0": {
-            "useTexture": false
-        },
-        "uv": {
-            "center": [
-                0.0,
-                1.0
-            ]
-        }
+    "propertyValues": {
+        "baseColor.textureMap": "Materials/Decal/scorch_01_decal.tif",
+        "metallic.useTexture": false,
+        "normal.textureMap": "Materials/Decal/scorch_01_decal_nrm.tif",
+        "opacity.alphaSource": "Split",
+        "opacity.doubleSided": true,
+        "opacity.factor": 0.6899999976158142,
+        "opacity.mode": "Cutout",
+        "opacity.textureMap": "Materials/Decal/scorch_01_decal.tif",
+        "roughness.useTexture": false,
+        "specularF0.useTexture": false,
+        "uv.center": [
+            0.0,
+            1.0
+        ]
     }
 }

+ 2 - 3
Materials/DefaultPBR.material

@@ -1,6 +1,5 @@
 {
-    "description": "",
     "materialType": "Materials/Types/StandardPBR.materialtype",
-    "parentMaterial": "Materials/Presets/PBR/default_grid.material",
-    "materialTypeVersion": 3
+    "materialTypeVersion": 3,
+    "parentMaterial": "Materials/Presets/PBR/default_grid.material"
 }

+ 3 - 6
Materials/DefaultPBRTransparent.material

@@ -1,11 +1,8 @@
 {
-    "description": "",
     "materialType": "Materials/Types/StandardPBR.materialtype",
-    "parentMaterial": "Materials/Presets/PBR/default_grid.material",
     "materialTypeVersion": 3,
-    "properties": {
-        "opacity": {
-            "mode": "Blended"
-        }
+    "parentMaterial": "Materials/Presets/PBR/default_grid.material",
+    "propertyValues": {
+        "opacity.mode": "Blended"
     }
 }

+ 14 - 19
Materials/DiffuseGIExample/blue.material

@@ -1,24 +1,19 @@
 {
-    "description": "",
     "materialType": "Materials\\Types\\StandardPBR.materialtype",
     "materialTypeVersion": 3,
-    "properties": {
-        "baseColor": {
-            "color": [
-                0.0,
-                0.0,
-                1.0,
-                1.0
-            ],
-            "useTexture": false
-        },
-        "irradiance": {
-            "color": [
-                0.0,
-                0.0,
-                1.0,
-                1.0
-            ]
-        }
+    "propertyValues": {
+        "baseColor.color": [
+            0.0,
+            0.0,
+            1.0,
+            1.0
+        ],
+        "baseColor.useTexture": false,
+        "irradiance.color": [
+            0.0,
+            0.0,
+            1.0,
+            1.0
+        ]
     }
 }

+ 14 - 19
Materials/DiffuseGIExample/green.material

@@ -1,24 +1,19 @@
 {
-    "description": "",
     "materialType": "Materials\\Types\\StandardPBR.materialtype",
     "materialTypeVersion": 3,
-    "properties": {
-        "baseColor": {
-            "color": [
-                0.0,
-                1.0,
-                0.0,
-                1.0
-            ],
-            "useTexture": false
-        },
-        "irradiance": {
-            "color": [
-                0.0,
-                1.0,
-                0.0,
-                1.0
-            ]
-        }
+    "propertyValues": {
+        "baseColor.color": [
+            0.0,
+            1.0,
+            0.0,
+            1.0
+        ],
+        "baseColor.useTexture": false,
+        "irradiance.color": [
+            0.0,
+            1.0,
+            0.0,
+            1.0
+        ]
     }
 }

+ 14 - 19
Materials/DiffuseGIExample/red.material

@@ -1,24 +1,19 @@
 {
-    "description": "",
     "materialType": "Materials\\Types\\StandardPBR.materialtype",
     "materialTypeVersion": 3,
-    "properties": {
-        "baseColor": {
-            "color": [
-                1.0,
-                0.0,
-                0.0,
-                1.0
-            ],
-            "useTexture": false
-        },
-        "irradiance": {
-            "color": [
-                1.0,
-                0.0,
-                0.0,
-                1.0
-            ]
-        }
+    "propertyValues": {
+        "baseColor.color": [
+            1.0,
+            0.0,
+            0.0,
+            1.0
+        ],
+        "baseColor.useTexture": false,
+        "irradiance.color": [
+            1.0,
+            0.0,
+            0.0,
+            1.0
+        ]
     }
 }

+ 14 - 19
Materials/DiffuseGIExample/white.material

@@ -1,24 +1,19 @@
 {
-    "description": "",
     "materialType": "Materials\\Types\\StandardPBR.materialtype",
     "materialTypeVersion": 3,
-    "properties": {
-        "baseColor": {
-            "color": [
-                1.0,
-                1.0,
-                1.0,
-                1.0
-            ],
-            "useTexture": false
-        },
-        "irradiance": {
-            "color": [
-                1.0,
-                1.0,
-                1.0,
-                1.0
-            ]
-        }
+    "propertyValues": {
+        "baseColor.color": [
+            1.0,
+            1.0,
+            1.0,
+            1.0
+        ],
+        "baseColor.useTexture": false,
+        "irradiance.color": [
+            1.0,
+            1.0,
+            1.0,
+            1.0
+        ]
     }
 }

+ 14 - 19
Materials/DiffuseGIExample/yellow.material

@@ -1,24 +1,19 @@
 {
-    "description": "",
     "materialType": "Materials\\Types\\StandardPBR.materialtype",
     "materialTypeVersion": 3,
-    "properties": {
-        "baseColor": {
-            "color": [
-                1.0,
-                1.0,
-                0.0,
-                1.0
-            ],
-            "useTexture": false
-        },
-        "irradiance": {
-            "color": [
-                1.0,
-                1.0,
-                0.0,
-                1.0
-            ]
-        }
+    "propertyValues": {
+        "baseColor.color": [
+            1.0,
+            1.0,
+            0.0,
+            1.0
+        ],
+        "baseColor.useTexture": false,
+        "irradiance.color": [
+            1.0,
+            1.0,
+            0.0,
+            1.0
+        ]
     }
 }

+ 9 - 13
Materials/DynamicMaterialTest/EmissiveWithCppFunctors.material

@@ -1,18 +1,14 @@
 {
-    "description": "",
     "materialType": "Materials/DynamicMaterialTest/EmissiveWithCppFunctors.materialtype",
-    "parentMaterial": "",
     "materialTypeVersion": 3,
-    "properties": {
-        "emissive": {
-            "color": [
-                0.0313725508749485,
-                0.4941176474094391,
-                1.0,
-                1.0
-            ],
-            "intensity": 3.0,
-            "textureMap": "Textures/Default/default_basecolor.tif"
-        }
+    "propertyValues": {
+        "emissive.color": [
+            0.0313725508749485,
+            0.4941176474094391,
+            1.0,
+            1.0
+        ],
+        "emissive.intensity": 3.0,
+        "emissive.textureMap": "Textures/Default/default_basecolor.tif"
     }
 }

+ 9 - 13
Materials/DynamicMaterialTest/EmissiveWithLuaFunctors.material

@@ -1,18 +1,14 @@
 {
-    "description": "",
     "materialType": "Materials/DynamicMaterialTest/EmissiveWithLuaFunctors.materialtype",
-    "parentMaterial": "",
     "materialTypeVersion": 3,
-    "properties": {
-        "emissive": {
-            "color": [
-                0.0313725508749485,
-                0.4941176474094391,
-                1.0,
-                1.0
-            ],
-            "intensity": 3.0,
-            "textureMap": "Textures/Default/default_basecolor.tif"
-        }
+    "propertyValues": {
+        "emissive.color": [
+            0.0313725508749485,
+            0.4941176474094391,
+            1.0,
+            1.0
+        ],
+        "emissive.intensity": 3.0,
+        "emissive.textureMap": "Textures/Default/default_basecolor.tif"
     }
 }

+ 17 - 25
Materials/HotReloadTest/TestData/VariantSelection_FullyBaked.material

@@ -1,30 +1,22 @@
 {
-    "description": "",
     "materialType": "Materials/Types/StandardPBR.materialtype",
-    "parentMaterial": "",
     "materialTypeVersion": 3,
-    "properties": {
-        "baseColor": {
-            "color": [
-                0.0,
-                0.0,
-                0.0,
-                1.0
-            ]
-        },
-        "emissive": {
-            "color": [
-                1.0,
-                0.5789272785186768,
-                0.19980163872241975,
-                1.0
-            ],
-            "enable": true,
-            "intensity": 3.0,
-            "textureMap": "Materials/HotReloadTest/TestData/VariantSelection_FullyBaked.png"
-        },
-        "opacity": {
-            "doubleSided": true
-        }
+    "propertyValues": {
+        "baseColor.color": [
+            0.0,
+            0.0,
+            0.0,
+            1.0
+        ],
+        "emissive.color": [
+            1.0,
+            0.5789272785186768,
+            0.19980163872241974,
+            1.0
+        ],
+        "emissive.enable": true,
+        "emissive.intensity": 3.0,
+        "emissive.textureMap": "Materials/HotReloadTest/TestData/VariantSelection_FullyBaked.png",
+        "opacity.doubleSided": true
     }
 }

+ 16 - 24
Materials/HotReloadTest/TestData/VariantSelection_Root.material

@@ -1,29 +1,21 @@
 {
-    "description": "",
     "materialType": "Materials/Types/StandardPBR.materialtype",
-    "parentMaterial": "",
     "materialTypeVersion": 3,
-    "properties": {
-        "baseColor": {
-            "color": [
-                0.0,
-                0.0,
-                0.0,
-                1.0
-            ]
-        },
-        "emissive": {
-            "color": [
-                0.19607843458652497,
-                0.3607843220233917,
-                1.0,
-                1.0
-            ],
-            "enable": true,
-            "textureMap": "Materials/HotReloadTest/TestData/VariantSelection_Root.png"
-        },
-        "opacity": {
-            "doubleSided": true
-        }
+    "propertyValues": {
+        "baseColor.color": [
+            0.0,
+            0.0,
+            0.0,
+            1.0
+        ],
+        "emissive.color": [
+            0.19607843458652496,
+            0.3607843220233917,
+            1.0,
+            1.0
+        ],
+        "emissive.enable": true,
+        "emissive.textureMap": "Materials/HotReloadTest/TestData/VariantSelection_Root.png",
+        "opacity.doubleSided": true
     }
 }

+ 9 - 13
Materials/MinimalPBR/MinimalPBR_BlueMetal.material

@@ -1,18 +1,14 @@
 {
-    "description": "",
     "materialType": "TestData/Materials/Types/MinimalPBR.materialtype",
-    "parentMaterial": "",
     "materialTypeVersion": 3,
-    "properties": {
-        "settings": {
-            "color": [
-                0.04896620288491249,
-                0.13278400897979737,
-                0.9096513390541077,
-                1.0
-            ],
-            "metallic": 1.0,
-            "roughness": 0.13131310045719148
-        }
+    "propertyValues": {
+        "settings.color": [
+            0.04896620288491249,
+            0.13278400897979736,
+            0.9096513390541077,
+            1.0
+        ],
+        "settings.metallic": 1.0,
+        "settings.roughness": 0.13131310045719147
     }
 }

+ 0 - 2
Materials/MinimalPBR/MinimalPBR_Default.material

@@ -1,6 +1,4 @@
 {
-    "description": "",
     "materialType": "TestData/Materials/Types/MinimalPBR.materialtype",
-    "parentMaterial": "",
     "materialTypeVersion": 3
 }

+ 8 - 12
Materials/MinimalPBR/MinimalPBR_RedDielectric.material

@@ -1,17 +1,13 @@
 {
-    "description": "",
     "materialType": "TestData/Materials/Types/MinimalPBR.materialtype",
-    "parentMaterial": "",
     "materialTypeVersion": 3,
-    "properties": {
-        "settings": {
-            "color": [
-                1.0,
-                0.0,
-                0.0,
-                1.0
-            ],
-            "roughness": 0.2727273106575012
-        }
+    "propertyValues": {
+        "settings.color": [
+            1.0,
+            0.0,
+            0.0,
+            1.0
+        ],
+        "settings.roughness": 0.2727273106575012
     }
 }

+ 15 - 26
Materials/SSRExample/Cube.material

@@ -1,30 +1,19 @@
 {
-    "description": "",
     "materialType": "Materials\\Types\\StandardPBR.materialtype",
     "materialTypeVersion": 3,
-    "properties": {
-        "baseColor": {
-            "color": [
-                1.0,
-                0.0,
-                0.0,
-                1.0
-            ],
-            "useTexture": false
-        },
-        "specularF0": {
-            "factor": 0.0,
-            "useTexture": false
-        },
-        "metallic": {
-            "factor": 0.0,
-            "useTexture": false
-        },        
-        "normal": {
-            "textureMap": "Textures/Default/default_normal.tif"
-        },
-        "roughness": {
-            "textureMap": "Textures/Default/default_roughness.tif"
-        }
+    "propertyValues": {
+        "baseColor.color": [
+            1.0,
+            0.0,
+            0.0,
+            1.0
+        ],
+        "baseColor.useTexture": false,
+        "metallic.factor": 0.0,
+        "metallic.useTexture": false,
+        "normal.textureMap": "Textures/Default/default_normal.tif",
+        "roughness.textureMap": "Textures/Default/default_roughness.tif",
+        "specularF0.factor": 0.0,
+        "specularF0.useTexture": false
     }
-}
+}

+ 13 - 25
Materials/SSRExample/GroundPlaneAluminum.material

@@ -1,30 +1,18 @@
 {
-    "description": "",
     "materialType": "Materials\\Types\\StandardPBR.materialtype",
-    "parentMaterial": "",
     "materialTypeVersion": 3,
-    "properties": {
-        "baseColor": {
-            "color": [
-                0.9130998849868774,
-                0.921583890914917,
-                0.921583890914917,
-                1.0
-            ],
-            "factor": 0.75
-        },
-        "metallic": {
-            "factor": 1.0
-        },
-        "roughness": {
-            "factor": 0.20000000298023225
-        },
-        "normal": {
-            "textureMap": "Textures/Default/default_normal.tif"
-        },
-        "specularF0": {
-            "enableMultiScatterCompensation": true,
-            "factor": 1.0
-        }
+    "propertyValues": {
+        "baseColor.color": [
+            0.9130998849868774,
+            0.921583890914917,
+            0.921583890914917,
+            1.0
+        ],
+        "baseColor.factor": 0.75,
+        "metallic.factor": 1.0,
+        "normal.textureMap": "Textures/Default/default_normal.tif",
+        "roughness.factor": 0.20000000298023224,
+        "specularF0.enableMultiScatterCompensation": true,
+        "specularF0.factor": 1.0
     }
 }

+ 13 - 27
Materials/SSRExample/GroundPlaneChrome.material

@@ -1,32 +1,18 @@
 {
-    "description": "",
     "materialType": "Materials\\Types\\StandardPBR.materialtype",
-    "parentMaterial": "",
     "materialTypeVersion": 3,
-    "properties": {
-        "baseColor": {
-            "color": [
-                0.5529412031173706,
-                0.5568627715110779,
-                0.5568627715110779,
-                1.0
-            ]
-        },
-        "general": {
-            "applySpecularAA": true
-        },
-        "metallic": {
-            "factor": 1.0
-        },
-        "roughness": {
-            "factor": 0.10000000149011612
-        },
-	"normal": {
-            "textureMap": "Textures/Default/default_normal.tif"
-        },
-        "specularF0": {
-            "enableMultiScatterCompensation": true,
-            "factor": 1.0
-        }
+    "propertyValues": {
+        "baseColor.color": [
+            0.5529412031173706,
+            0.5568627715110779,
+            0.5568627715110779,
+            1.0
+        ],
+        "general.applySpecularAA": true,
+        "metallic.factor": 1.0,
+        "normal.textureMap": "Textures/Default/default_normal.tif",
+        "roughness.factor": 0.10000000149011612,
+        "specularF0.enableMultiScatterCompensation": true,
+        "specularF0.factor": 1.0
     }
 }

+ 12 - 24
Materials/SSRExample/GroundPlaneMirror.material

@@ -1,29 +1,17 @@
 {
-    "description": "",
     "materialType": "Materials\\Types\\StandardPBR.materialtype",
-    "parentMaterial": "",
     "materialTypeVersion": 3,
-    "properties": {
-        "baseColor": {
-            "color": [
-                1.0,
-                1.0,
-                1.0,
-                1.0
-            ]
-        },
-        "general": {
-            "applySpecularAA": true
-        },
-        "metallic": {
-            "factor": 1.0
-        },
-        "roughness": {
-            "factor": 0.0
-        },
-        "specularF0": {
-            "enableMultiScatterCompensation": true,
-            "factor": 1.0
-        }
+    "propertyValues": {
+        "baseColor.color": [
+            1.0,
+            1.0,
+            1.0,
+            1.0
+        ],
+        "general.applySpecularAA": true,
+        "metallic.factor": 1.0,
+        "roughness.factor": 0.0,
+        "specularF0.enableMultiScatterCompensation": true,
+        "specularF0.factor": 1.0
     }
 }

+ 5 - 15
Materials/SSRExample/GroundPlaneWood.material

@@ -1,20 +1,10 @@
 {
-    "description": "",
     "materialType": "Materials\\Types\\StandardPBR.materialtype",
-    "parentMaterial": "",
     "materialTypeVersion": 3,
-    "properties": {
-        "baseColor": {
-            "textureMap": "Materials/SSRExample/wood_planks_512_diff.tif"
-        },
-        "metallic": {
-            "factor": 0.0
-        },
-        "roughness": {
-            "factor": 0.5
-        },
-	"normal": {
-            "textureMap": "Materials/SSRExample/wood_planks_512_ddna.tif"
-        }
+    "propertyValues": {
+        "baseColor.textureMap": "Materials/SSRExample/wood_planks_512_diff.tif",
+        "metallic.factor": 0.0,
+        "normal.textureMap": "Materials/SSRExample/wood_planks_512_ddna.tif",
+        "roughness.factor": 0.5
     }
 }

+ 20 - 31
Materials/SSRExample/ShaderBall.material

@@ -1,36 +1,25 @@
 {
-    "description": "",
     "materialType": "Materials\\Types\\StandardPBR.materialtype",
     "materialTypeVersion": 3,
-    "properties": {
-        "baseColor": {
-            "color": [
-                0.0,
-                0.0,
-                1.0,
-                1.0
-            ],
-            "useTexture": false
-        },
-        "specularF0": {
-            "factor": 0.0,
-            "useTexture": false
-        },
-        "metallic": {
-            "factor": 0.0,
-            "useTexture": false
-        },
-        "roughness": {
-            "factor": 1.0,
-            "useTexture": false
-        },
-        "irradiance": {
-            "color": [
-                0.0,
-                0.0,
-                1.0,
-                1.0
-            ]
-        }
+    "propertyValues": {
+        "baseColor.color": [
+            0.0,
+            0.0,
+            1.0,
+            1.0
+        ],
+        "baseColor.useTexture": false,
+        "irradiance.color": [
+            0.0,
+            0.0,
+            1.0,
+            1.0
+        ],
+        "metallic.factor": 0.0,
+        "metallic.useTexture": false,
+        "roughness.factor": 1.0,
+        "roughness.useTexture": false,
+        "specularF0.factor": 0.0,
+        "specularF0.useTexture": false
     }
 }

+ 4 - 7
Materials/TransparentDoubleSide.material

@@ -1,12 +1,9 @@
 {
-    "description": "",
     "materialType": "Materials/Types/StandardPBR.materialtype",
-    "parentMaterial": "Materials/Presets/PBR/default_grid.material",
     "materialTypeVersion": 3,
-    "properties": {
-        "opacity": {
-            "mode": "Blended",
-            "doubleSided": true
-        }
+    "parentMaterial": "Materials/Presets/PBR/default_grid.material",
+    "propertyValues": {
+        "opacity.doubleSided": true,
+        "opacity.mode": "Blended"
     }
 }

+ 24 - 0
Materials/Types/MinimalMultilayerExample.material

@@ -0,0 +1,24 @@
+{
+    "materialType": "Materials/Types/MinimalMultilayerPBR.materialtype",
+    "materialTypeVersion": 1,
+    "propertyValues": {
+        "blend.texture": "TestData/Textures/checker8x8_512.png",
+        "layer1.baseColor.color": [
+            1.0,
+            0.7495536804199219,
+            0.3466697037220001,
+            1.0
+        ],
+        "layer1.baseColor.texture": "Textures/bricks_1k_basecolor.png",
+        "layer1.metallic": 1.0,
+        "layer1.roughness": 0.23000000417232513,
+        "layer2.baseColor.color": [
+            0.34021514654159546,
+            0.14996567368507385,
+            0.42177462577819824,
+            1.0
+        ],
+        "layer2.baseColor.texture": "TestData/Textures/cc0/Concrete019_1K_Color.jpg",
+        "layer2.roughness": 0.8399999737739563
+    }
+}

+ 61 - 0
Materials/Types/MinimalMultilayerPBR.materialtype

@@ -0,0 +1,61 @@
+{
+    "description": "This material type is for testing features realated to the 'Remixable Material Types' RFC. It is only here temporarily until we get StandardMultilayerPBR factored out using the new features. At that time, we can remove this material type.",
+    "version": 1,
+    "propertyLayout": {
+        "propertyGroups": [
+            {
+                "name": "blend",
+                "displayName": "Blend",
+                "description": "Controls how the layers blend together.",
+                "properties": [
+                    {
+                        "name": "texture",
+                        "displayName": "Blend Mask Texture",
+                        "description": "Grayscale image where black is layer 1 and white is layer 2.",
+                        "type": "Image",
+                        "defaultValue": "Textures/DefaultBlendMask_layers.png",
+                        "connection": {
+                            "type": "ShaderInput",
+                            "name": "m_blendMaskTexture"
+                        }
+                    }
+                ]
+            },
+            { 
+                "$import": { 
+                    "filename": "MinimalMultilayerPBR_LayerProperties.json", 
+                    "patch": {
+                        "name": "layer1",
+                        "displayName": "Layer 1",
+                        "shaderInputsPrefix":  "m_layer1_",
+                        "shaderOptionsPrefix":  "o_layer1_"
+                    }
+                }
+            },
+            { 
+                "$import": { 
+                    "filename": "MinimalMultilayerPBR_LayerProperties.json", 
+                    "patch": {
+                        "name": "layer2",
+                        "displayName": "Layer 2",
+                        "shaderInputsPrefix":  "m_layer2_",
+                        "shaderOptionsPrefix":  "o_layer2_"
+                    }
+                }
+            }
+        ]
+    },
+    "shaders": [
+        {
+            "file": "./MinimalMultilayerPBR_ForwardPass.shader"
+        },
+        {
+            "file": "Shaders/Shadow/Shadowmap.shader"
+        },
+        {
+            "file": "Shaders/Depth/DepthPass.shader"
+        }
+    ],
+    "functors": [
+    ]
+}

+ 163 - 0
Materials/Types/MinimalMultilayerPBR_ForwardPass.azsl

@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) Contributors to the Open 3D Engine Project.
+ * For complete copyright and license terms please see the LICENSE at the root of this distribution.
+ *
+ * SPDX-License-Identifier: Apache-2.0 OR MIT
+ *
+ */
+
+#include <viewsrg.srgi>
+#include <Atom/Features/PBR/DefaultObjectSrg.azsli>
+#include <Atom/Features/PBR/ForwardPassSrg.azsli>
+#include <Atom/Features/PBR/ForwardPassOutput.azsli>
+#include <Atom/Features/PBR/AlphaUtils.azsli>
+#include <Atom/Features/SrgSemantics.azsli>
+#include <Atom/Features/ColorManagement/TransformColor.azsli>
+#include <Atom/Features/PBR/Lighting/StandardLighting.azsli>
+#include <Atom/Features/PBR/Decals.azsli>
+
+#include <Atom/Feature/Common/Assets/Materials/Types/MaterialInputs/BaseColorInput.azsli>
+
+ShaderResourceGroup MaterialSrg : SRG_PerMaterial
+{
+    float3 m_layer1_baseColor;
+    float  m_layer1_metallic;
+    float  m_layer1_roughness;
+    float3 m_layer2_baseColor;
+    float  m_layer2_metallic;
+    float  m_layer2_roughness;
+    
+    Texture2D m_layer1_baseColorTexture;
+    Texture2D m_layer2_baseColorTexture;
+
+    Sampler m_sampler
+    {
+       AddressU = Wrap;
+       AddressV = Wrap;
+       MinFilter = Linear;
+       MagFilter = Linear;
+       MipFilter = Linear;
+       MaxAnisotropy = 16;
+    };
+    
+    Texture2D m_blendMaskTexture;
+}
+
+option bool o_layer1_useBaseColorTexture;
+option bool o_layer2_useBaseColorTexture;
+
+struct VSInput
+{
+    float3 m_position : POSITION;
+    float3 m_normal : NORMAL;
+    float4 m_tangent : TANGENT; 
+    float3 m_bitangent : BITANGENT; 
+    float2 m_uv : UV0;
+};
+
+struct VSOutput
+{
+    precise linear centroid float4 m_position : SV_Position;
+    float3 m_normal: NORMAL;
+    float3 m_tangent : TANGENT; 
+    float3 m_bitangent : BITANGENT; 
+    float2 m_uv : UV0;
+    float3 m_worldPosition : UV1;
+    float3 m_shadowCoords[ViewSrg::MaxCascadeCount] : UV2;
+};
+
+#include <Atom/Features/Vertex/VertexHelper.azsli>
+
+VSOutput MinimalMultilayerPBR_MainPassVS(VSInput IN)
+{
+    VSOutput OUT;
+ 
+    float3 worldPosition = mul(ObjectSrg::GetWorldMatrix(), float4(IN.m_position, 1.0)).xyz;
+ 
+    OUT.m_uv = IN.m_uv;
+
+    VertexHelper(IN, OUT, worldPosition);
+
+    return OUT;
+}
+
+
+
+ForwardPassOutput MinimalMultilayerPBR_MainPassPS(VSOutput IN)
+{
+    float3 baseColor1 = GetBaseColorInput(MaterialSrg::m_layer1_baseColorTexture, MaterialSrg::m_sampler, IN.m_uv, MaterialSrg::m_layer1_baseColor, o_layer1_useBaseColorTexture);
+    float3 baseColor2 = GetBaseColorInput(MaterialSrg::m_layer2_baseColorTexture, MaterialSrg::m_sampler, IN.m_uv, MaterialSrg::m_layer2_baseColor, o_layer2_useBaseColorTexture);
+    
+    baseColor1 = BlendBaseColor(baseColor1, MaterialSrg::m_layer1_baseColor, 1.0, TextureBlendMode::Multiply, o_layer1_useBaseColorTexture);
+    baseColor2 = BlendBaseColor(baseColor2, MaterialSrg::m_layer2_baseColor, 1.0, TextureBlendMode::Multiply, o_layer2_useBaseColorTexture);
+
+    float blendValue = MaterialSrg::m_blendMaskTexture.Sample(MaterialSrg::m_sampler, IN.m_uv).r;
+    float3 baseColor = lerp(baseColor1, baseColor2, blendValue);
+    float roughness = lerp(MaterialSrg::m_layer1_roughness, MaterialSrg::m_layer2_roughness, blendValue);
+    float metallic = lerp(MaterialSrg::m_layer1_metallic, MaterialSrg::m_layer2_metallic, blendValue);
+
+    // ------- Surface -------
+
+    Surface surface;
+    
+    // Position, Normal, Roughness
+    surface.position = IN.m_worldPosition.xyz;
+    surface.normal = normalize(IN.m_normal);
+    surface.vertexNormal = normalize(IN.m_normal);
+    surface.roughnessLinear = roughness;
+    surface.CalculateRoughnessA();
+
+    // Albedo, SpecularF0
+    const float specularF0Factor = 0.5f;
+    surface.SetAlbedoAndSpecularF0(baseColor, specularF0Factor, metallic);
+
+    // Clear Coat, Transmission
+    surface.clearCoat.InitializeToZero();
+
+    // ------- LightingData -------
+
+    LightingData lightingData;
+
+    // Light iterator
+    lightingData.tileIterator.Init(IN.m_position, PassSrg::m_lightListRemapped, PassSrg::m_tileLightData);
+    lightingData.Init(surface.position, surface.normal, surface.roughnessLinear);
+
+    // Shadow, Occlusion
+    lightingData.shadowCoords = IN.m_shadowCoords;
+
+    // Diffuse and Specular response
+    lightingData.specularResponse = FresnelSchlickWithRoughness(lightingData.NdotV, surface.specularF0, surface.roughnessLinear);
+    lightingData.diffuseResponse = 1.0f - lightingData.specularResponse;
+
+    const float alpha = 1.0f;
+
+    // ------- Lighting Calculation -------
+
+    // Apply Decals
+    ApplyDecals(lightingData.tileIterator, surface);
+
+    // Apply Direct Lighting
+    ApplyDirectLighting(surface, lightingData);
+
+    // Apply Image Based Lighting (IBL)
+    ApplyIBL(surface, lightingData);
+
+    // Finalize Lighting
+    lightingData.FinalizeLighting();
+
+    PbrLightingOutput lightingOutput = GetPbrLightingOutput(surface, lightingData, alpha);
+
+    // ------- Output -------
+
+    ForwardPassOutput OUT;
+
+    OUT.m_diffuseColor = lightingOutput.m_diffuseColor;
+    OUT.m_diffuseColor.w = -1; // Subsurface scattering is disabled
+    OUT.m_specularColor = lightingOutput.m_specularColor;
+    OUT.m_specularF0 = lightingOutput.m_specularF0;
+    OUT.m_albedo = lightingOutput.m_albedo;
+    OUT.m_normal = lightingOutput.m_normal;
+
+    return OUT;
+}
+

+ 46 - 0
Materials/Types/MinimalMultilayerPBR_ForwardPass.shader

@@ -0,0 +1,46 @@
+{
+    "Source" : "./MinimalMultilayerPBR_ForwardPass.azsl",
+
+    "DepthStencilState" :
+    {
+        "Depth" :
+        {
+            "Enable" : true,
+            "CompareFunc" : "GreaterEqual"
+        },
+        "Stencil" :
+        {
+            "Enable" : true,
+            "ReadMask" : "0x00",
+            "WriteMask" : "0xFF",
+            "FrontFace" :
+            {
+                "Func" : "Always",
+                "DepthFailOp" : "Keep",
+                "FailOp" : "Keep",
+                "PassOp" : "Replace"
+            }
+        }
+    },
+
+    "CompilerHints" : { 
+        "DisableOptimizations" : false
+    },
+
+    "ProgramSettings":
+    {
+      "EntryPoints":
+      [
+        {
+          "name": "MinimalMultilayerPBR_MainPassVS",
+          "type": "Vertex"
+        },
+        {
+          "name": "MinimalMultilayerPBR_MainPassPS",
+          "type": "Fragment"
+        }
+      ]
+    },
+
+    "DrawList" : "forward"
+}

+ 75 - 0
Materials/Types/MinimalMultilayerPBR_LayerProperties.json

@@ -0,0 +1,75 @@
+{
+    "description": "Settings that affect one layer of the multilayer material.",
+    "properties": [
+        {
+            "name": "metallic",
+            "displayName": "Metallic",
+            "description": "Controls how metallic the surface appears.",
+            "type": "Float",
+            "defaultValue": 0.0,
+            "min": 0.0,
+            "max": 1.0,
+            "connection": {
+                "type": "ShaderInput",
+                "name": "metallic"
+            }
+        },
+        {
+            "name": "roughness",
+            "displayName": "Roughness",
+            "type": "Float",
+            "defaultValue": 1.0,
+            "min": 0.0,
+            "max": 1.0,
+            "connection": {
+                "type": "ShaderInput",
+                "name": "roughness"
+            }
+        }
+    ],
+    "propertyGroups": [
+        {
+            "name": "baseColor",
+            "displayName": "Base Color",
+            "description": "Settings that control the diffuse color for non-metals or specular color for metals.",
+            "properties": [
+                {
+                    "name": "color",
+                    "displayName": "Color",
+                    "type": "Color",
+                    "defaultValue": [ 1.0, 1.0, 1.0 ],
+                    "connection": {
+                        "type": "ShaderInput",
+                        "name": "baseColor"
+                    }
+                },
+                {
+                    "name": "texture",
+                    "displayName": "Color Texture",
+                    "type": "Image",
+                    "connection": {
+                        "type": "ShaderInput",
+                        "name": "baseColorTexture"
+                    }
+                },
+                {
+                    "name": "useTexture",
+                    "displayName": "Use Color Texture",
+                    "type": "Bool",
+                    "defaultValue": true
+                }
+            ],
+            "functors": 
+            [
+                {
+                    "type": "UseTexture",
+                    "args": {
+                        "textureProperty": "texture",
+                        "useTextureProperty": "useTexture",
+                        "shaderOption": "useBaseColorTexture"
+                    }
+                }
+            ]
+        }
+    ]
+}

+ 5 - 2
Scripts/DynamicMaterialTest.bv.lua

@@ -31,18 +31,21 @@ function TakeScreenshotSeries(filenamePrefix)
     SelectImageComparisonToleranceLevel("Level H")
 
     -- There could be variation in how long prior activities took so reset the clock for each series of screenshots
-    SetImguiValue('Reset Clock', true) 
-    IdleFrames(1) -- Give time for the sample to make any material changes before starting screenshots.
+    SetImguiValue('Reset Clock', true)     
+    IdleFrames(1) -- Consume ImGui changes, to ensure the clock is reset before pausing
 
     -- Note we pause while taking the screenshot so that IO delays won't impact the timing of the sample
 
     SetImguiValue("Pause", true)
+    IdleFrames(1) -- Give extra time to make sure any material changes are applied, especially in case an asset hot-load causes the material to reinitialize itself.
     CaptureScreenshot(g_screenshotOutputFolder .. filenamePrefix .. '_A.png')
     SetImguiValue("Pause", false)
 
+    -- Let the animation run for 1 second
     IdleSeconds(1.0)
 
     SetImguiValue("Pause", true)
+    IdleFrames(1) -- Give extra time to make sure any material changes are applied, especially in case an asset hot-load causes the material to reinitialize itself.
     CaptureScreenshot(g_screenshotOutputFolder .. filenamePrefix .. '_B.png')
     SetImguiValue("Pause", false)
 end

+ 2 - 2
Scripts/ExpectedScreenshots/Checkerboard/frame1.png

@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:53cee500af3d55c058bafd05a0cb18c135164a0c185761749ea7c8a89cce9efe
-size 164913
+oid sha256:00166bde1678829d372a61346d2e2ad953db0d2606282625488a484dd0996d41
+size 191278

+ 2 - 2
Scripts/ExpectedScreenshots/DynamicMaterialTest/01_defaultsetup_A.png

@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:6727406511486214c74672bd6a455c96637e78218ad80b23e19bf4fe11ba230d
-size 1335670
+oid sha256:54291f140b119bb9bd7234ea598d90a0b57b1b147f2fb419f0df14ff9a61ff5d
+size 1478106

+ 2 - 2
Scripts/ExpectedScreenshots/DynamicMaterialTest/01_defaultsetup_B.png

@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:412a5881377f26f36b30888429a1d409d16fe0fee2f6730b2a04e773928c3171
-size 1335520
+oid sha256:460203b053f8a1c977cdea6b420ee5a7e6cfd7400c61d4a156119ebf452966a7
+size 1480957

+ 2 - 2
Scripts/ExpectedScreenshots/DynamicMaterialTest/02_manyentities_A.png

@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:84786db354866995eb72e752b354ac134340b0a5e4e92ee4645a03526556eaaa
-size 1506707
+oid sha256:695b7a8dbee92c5739829174a23b22bcd1b3409a2d7670e86304d1132ec6894f
+size 1642868

+ 2 - 2
Scripts/ExpectedScreenshots/DynamicMaterialTest/02_manyentities_B.png

@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:a8872cfd90c897e7a7e5b067bd91e2960d684eb702b5de16f01f5ce3446c550c
-size 1506231
+oid sha256:91802fb4d052718f07207fddab6b83e70eaa1525e7d687f23e279fc6e285f2a4
+size 1644801

+ 3 - 0
Scripts/ExpectedScreenshots/MinimalPBR/minimalmultilayerexample.png

@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:5d2c3542cc2e6774d2783d7aadb9855293a726370410d6dcb620ca13aea9fbd9
+size 1171349

+ 2 - 2
Scripts/ExpectedScreenshots/PassTree/albedo.png

@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:a928d95b7d91e79a178e37da8faed8d63a0a9ff5dd1e8eca23a52f2d733b716a
-size 227383
+oid sha256:1172abab6b87e6097f579a6a0dd0ee8967cf8d0c1afe6f0766bedbc65fdc7740
+size 241139

+ 2 - 2
Scripts/ExpectedScreenshots/PassTree/brdf.png

@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:b4fa72c6a29efd95ce9c7167a0ac2f11c37d43d6eb2722425747d04bed49f22c
-size 203218
+oid sha256:0b03c1da7705375112394edf197a1ddd5dfb41621de9450d7c897a7cccf9c006
+size 251221

+ 2 - 2
Scripts/ExpectedScreenshots/PassTree/depthStencilMs.png

@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:d1c465bbb995b0785409c2056f5a3a3047a6bca038f4afd2478158eb7039f211
-size 199455
+oid sha256:37e527aae96d6b58ff97f0b0a1d1e3e27d461ba296a2ec0ead6c2ba789a48546
+size 207872

+ 2 - 2
Scripts/ExpectedScreenshots/PassTree/depthStencilResolve.png

@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:ac0614e3c9fece06d67094e25b5d62220ef0fa8e2fedca6e7da78b566cb028ae
-size 198902
+oid sha256:3e7cbcb07dc9cd8a0c10b9a8c3e55db7141ea1f07ccf2fa1efadfdadb3c279a3
+size 208072

+ 2 - 2
Scripts/ExpectedScreenshots/PassTree/linearDepth.png

@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:0e759c618aceb299fcf62fd5e910c9246cd453f0ef0ee98cad53019825d6794b
-size 175611
+oid sha256:7f1bd5b2966d57d97ca9a38914ced65d33daeb70fd09ce2758ec4fa05292f64b
+size 204945

+ 2 - 2
Scripts/ExpectedScreenshots/PassTree/specularResolved.png

@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:dc16d6db850bd461a56efeb3177b6ec1a15fba98a58d1e36243585a6d3293472
-size 239633
+oid sha256:aa486051731f114e3e06b155e96b00719080f39e6c6b7543e4f4fe80e9f53afd
+size 234151

+ 3 - 0
Scripts/ExpectedScreenshots/RenderTargetTexture/screenshot_1.png

@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:c333e7dab4906e37e71b0b01defb6798da2731160ebca142691bc8ea20fcb34a
+size 84087

+ 3 - 0
Scripts/ExpectedScreenshots/RenderTargetTexture/screenshot_2.png

@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:19b8fd0e5ee92732be670e6befb198a64f6d050a37ae97730410cbe737811543
+size 92580

+ 2 - 2
Scripts/ExpectedScreenshots/SceneReloadSoakTest/screenshot.png

@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:427c18d84f13e9dfef9e20726fad4bfdf3601390851551410181f8361ef928fe
-size 286701
+oid sha256:f19208b95b3efc2081881e361aa3073a3b9107d3d2275af17de6daba90fcd304
+size 323874

+ 2 - 2
Scripts/ExpectedScreenshots/ShadowedSponza/directional_filter.png

@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:7431de98450bc58a69425266f7f949a14b3c5468fe8fadb3556c3d61ac9a3fd8
-size 129439
+oid sha256:97e8e3793c497f53b19a20581bcaf29e14172042654de3b847d133e33613134b
+size 126990

+ 2 - 2
Scripts/ExpectedScreenshots/ShadowedSponza/directional_nofilter.png

@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:db7bd43477e5fef3ea86a6dc9853a35ecc86c22c885705b593fa3f9d976ad4d5
-size 123378
+oid sha256:1c4ae6a6e645083b86410d24fab05ccae96d69984b1d120e6dd3c2b7a56e1b3c
+size 123338

+ 2 - 2
Scripts/ExpectedScreenshots/ShadowedSponza/initial.png

@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:d56b3aaad036fb387d64fb154d44c0031c4685134568c94218bd9bcb1ba00dfb
-size 140910
+oid sha256:17d41e65a22245b308149b933f9a0afad66ab18757dd0131af7a09f4afa8358e
+size 145213

+ 2 - 2
Scripts/ExpectedScreenshots/ShadowedSponza/spot_filter.png

@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:5ee99410c2fa503ea8cd13148f7905b63a7e719797a3b011ea0f95c64466d627
-size 146768
+oid sha256:b2e918d9cf8ce6ce9afcaeb583788551af82318de7718fe0080a698d2f355eca
+size 146828

+ 2 - 2
Scripts/ExpectedScreenshots/ShadowedSponza/spot_nofilter.png

@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:08cb4c1eff8c36d05397516a8b204714893301fbe64babd1de4689f0f1406a22
-size 140519
+oid sha256:12c8f4c5aae165a59f7ae1ceb2f52eb7d75acfc433ed6b74d7a337c01cbfc88b
+size 140465

+ 2 - 2
Scripts/ExpectedScreenshots/StandardMultilayerPBR/002_parallaxpdo.png

@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:214b1a0c96518160348fe25a86079628e6e0c919b74fcba4dcb7d73c6fdc881a
-size 1546370
+oid sha256:669473008a95559978ff3c34676445624f5bb091df4c6f7136ed700a7d5ba98c
+size 1432817

+ 2 - 2
Scripts/ExpectedScreenshots/StandardPBR/015_subsurfacescattering_transmission.png

@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:0d81f6ca0d5cfd272fc80d3fdbe1d5bb65490b8b751e761da6c8eb67bee60532
-size 835103
+oid sha256:57df2a1870b6de8c95b0065b019005d07282e4f641bce41523afd1f01880e655
+size 784975

+ 2 - 2
Scripts/ExpectedScreenshots/StandardPBR/015_subsurfacescattering_transmission_thin.png

@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:09d2d72e1d0a125b4d92f3b0c8c89c707aefe22b72413ce58cbc3ba4081f792c
-size 590416
+oid sha256:5a9c43061cae04c2914e0e2e8c93481b89510809b199f3b1ecaae206e066b9f9
+size 621979

+ 2 - 2
Scripts/ExpectedScreenshots/msaa_rpi/screenshot_msaa4x_cylinder.png

@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:ef3cb1b55c8af667da369c8064c2093617691dca56c6f1043cfaf5c73befac25
-size 382489
+oid sha256:18d4c8ab2cb4aa4272e4cf213dda6f2d5793cf057955635f09459a6ed1148d46
+size 381231

+ 10 - 0
Scripts/MaterialScreenshotTests.bv.lua

@@ -203,6 +203,16 @@ GenerateMaterialScreenshot('Level B', 'MinimalPbr_Default')
 GenerateMaterialScreenshot('Level F', 'MinimalPbr_BlueMetal')
 GenerateMaterialScreenshot('Level D', 'MinimalPbr_RedDielectric')
 
+----------------------------------------------------------------------
+-- MinimalMultilayerPBR Materials...
+-- This test is here only temporarily for regression testing until StandardMultilayerPBR is refactored to use reused nested property groups.
+
+g_testMaterialsFolder = 'materials/types/'
+g_screenshotOutputFolder = ResolvePath('@user@/Scripts/Screenshots/MinimalPBR/')
+Print('Saving screenshots to ' .. NormalizePath(g_screenshotOutputFolder))
+
+GenerateMaterialScreenshot('Level D', 'MinimalMultilayerExample')
+
 ----------------------------------------------------------------------
 -- AutoBrick Materials...
 

+ 12 - 1
Scripts/PassTree.bv.lua

@@ -24,11 +24,22 @@ function TestAttachment(attachmentName, screenshotFileName)
 end
 
 -- Test PassTree tool with shading sample 
-OpenSample('RPI/Shading')
+OpenSample('RPI/Mesh')
 ResizeViewport(800, 600)
 
 SelectImageComparisonToleranceLevel("Level F")
 
+-- choose model, material and lighting
+SetImguiValue('Models/##Available', 'objects/shaderball_simple.azmodel')
+SetImguiValue('Enable Material Override', true)
+SetImguiValue('Materials/##Available', 'materials/defaultpbr.azmaterial')
+SetImguiValue('Lighting Preset##SampleBase/Thumbnail', true)
+
+-- set camera transform
+ArcBallCameraController_SetHeading(DegToRad(144.671860))
+ArcBallCameraController_SetPitch(DegToRad(-17.029560))
+ArcBallCameraController_SetDistance(6.590300)
+
 -- Show the tool and enable preview image attachment
 ShowTool('PassTree', true)
 SetImguiValue('Show Pass Attachments', true)

+ 39 - 0
Scripts/RenderTargetTexture.bv.lua

@@ -0,0 +1,39 @@
+----------------------------------------------------------------------------------------------------
+--
+-- Copyright (c) Contributors to the Open 3D Engine Project.
+-- For complete copyright and license terms please see the LICENSE at the root of this distribution.
+--
+-- SPDX-License-Identifier: Apache-2.0 OR MIT
+--
+--
+--
+----------------------------------------------------------------------------------------------------
+
+g_screenshotOutputFolder = ResolvePath('@user@/Scripts/Screenshots/RenderTargetTexture/')
+Print('Saving screenshots to ' .. NormalizePath(g_screenshotOutputFolder))
+
+OpenSample('RPI/RenderTargetTexture')
+SelectImageComparisonToleranceLevel("Level F") 
+
+-- hide preview before resize since it may clean the cached image copy
+SetImguiValue('Show Preview', false)
+
+IdleFrames(1) 
+ResizeViewport(800, 500)
+
+-- manully hide ImGui since CaptureScreenshotWithPreview won't hide it automatically
+SetShowImGui(false)
+
+-- enable preview after resize
+SetImguiValue('Show Preview', true)
+SetImguiValue('Next Frame', true)
+IdleFrames(1) 
+CaptureScreenshotWithPreview(g_screenshotOutputFolder .. '/screenshot_1.png')
+
+SetImguiValue('Next Frame', true)
+IdleFrames(2) 
+CaptureScreenshotWithPreview(g_screenshotOutputFolder .. '/screenshot_2.png')
+
+SetShowImGui(false)
+
+OpenSample(nil)

+ 2 - 1
Scripts/_AutomatedPeriodicBenchmarkSuite_.bv.lua

@@ -14,7 +14,8 @@ FRAME_COUNT = 100
 SAMPLES_TO_RUN = {
     {prefix = 'RPI', name = 'CullingAndLod', width = 1400, height = 800},
     {prefix = 'RPI', name = 'SponzaBenchmark', width = 1400, height = 800},
-    {prefix = 'RPI', name = 'HighInstanceTest', width = 800, height = 600}
+    {prefix = 'Performance', name = '100KDrawable_SingleView', width = 800, height = 600},
+    {prefix = 'Performance', name = '100KDraw_10KDrawable_MultiView', width = 800, height = 600}
 }
 
 Print('Capturing data for ' .. tostring(#SAMPLES_TO_RUN) .. ' benchmarks')

Some files were not shown because too many files changed in this diff