diff --git a/engine/include/XCEngine/Rendering/Execution/DrawSettings.h b/engine/include/XCEngine/Rendering/Execution/DrawSettings.h index 43db05e7..13366d7d 100644 --- a/engine/include/XCEngine/Rendering/Execution/DrawSettings.h +++ b/engine/include/XCEngine/Rendering/Execution/DrawSettings.h @@ -1,7 +1,9 @@ #pragma once +#include #include #include +#include namespace XCEngine { namespace Rendering { @@ -9,6 +11,11 @@ namespace Rendering { struct DrawSettings { ScenePhase scenePhase = ScenePhase::Opaque; RendererListDesc rendererListDesc = {}; + Resources::ResourceHandle overrideMaterial = {}; + + bool HasOverrideMaterial() const { + return overrideMaterial.IsValid(); + } }; } // namespace Rendering diff --git a/engine/include/XCEngine/Rendering/Pipelines/BuiltinForwardPipeline.h b/engine/include/XCEngine/Rendering/Pipelines/BuiltinForwardPipeline.h index dc9f4508..6c3d99cc 100644 --- a/engine/include/XCEngine/Rendering/Pipelines/BuiltinForwardPipeline.h +++ b/engine/include/XCEngine/Rendering/Pipelines/BuiltinForwardPipeline.h @@ -335,7 +335,7 @@ private: const Resources::Texture* ResolveTexture(const Resources::Material* material) const; RHI::RHIResourceView* ResolveTextureView(const Resources::Texture* texture); - RHI::RHIResourceView* ResolveTextureView(const VisibleRenderItem& visibleItem); + RHI::RHIResourceView* ResolveTextureView(const Resources::Material* material); RHI::RHIResourceView* ResolveMaterialTextureView( const Resources::Material* material, const BuiltinPassResourceBindingDesc& binding); @@ -363,7 +363,8 @@ private: const DrawSettings& drawSettings); bool DrawVisibleItem( const FrameExecutionContext& executionContext, - const VisibleRenderItem& visibleItem); + const VisibleRenderItem& visibleItem, + const Resources::Material* material); bool EnsureSkyboxResources(const RenderContext& context); bool CreateSkyboxResources(const RenderContext& context); void DestroySkyboxResources(); diff --git a/engine/src/Rendering/Pipelines/Internal/BuiltinForwardPipelineSurface.cpp b/engine/src/Rendering/Pipelines/Internal/BuiltinForwardPipelineSurface.cpp index 837a5a27..8eff1090 100644 --- a/engine/src/Rendering/Pipelines/Internal/BuiltinForwardPipelineSurface.cpp +++ b/engine/src/Rendering/Pipelines/Internal/BuiltinForwardPipelineSurface.cpp @@ -307,8 +307,7 @@ RHI::RHIResourceView* BuiltinForwardPipeline::ResolveTextureView( } RHI::RHIResourceView* BuiltinForwardPipeline::ResolveTextureView( - const VisibleRenderItem& visibleItem) { - const Resources::Material* material = ResolveMaterial(visibleItem); + const Resources::Material* material) { const Resources::Texture* texture = ResolveTexture(material); RHI::RHIResourceView* textureView = ResolveTextureView(texture); return textureView != nullptr ? textureView : m_fallbackTexture2DView; @@ -402,7 +401,8 @@ bool BuiltinForwardPipeline::ExecuteForwardTransparentPass( bool BuiltinForwardPipeline::DrawVisibleItem( const FrameExecutionContext& executionContext, - const VisibleRenderItem& visibleItem) { + const VisibleRenderItem& visibleItem, + const Resources::Material* material) { const RenderContext& context = executionContext.renderContext; const RenderSceneData& sceneData = executionContext.sceneData; @@ -435,7 +435,6 @@ bool BuiltinForwardPipeline::DrawVisibleItem( shadowReceiverConstants.shadowSampling = sceneData.lighting.mainDirectionalShadow.sampling; } - const Resources::Material* material = ResolveMaterial(visibleItem); const ResolvedShaderPass resolvedShaderPass = ResolveSurfaceShaderPass(sceneData, material); if (resolvedShaderPass.shader == nullptr || resolvedShaderPass.pass == nullptr) { return false; @@ -452,7 +451,7 @@ bool BuiltinForwardPipeline::DrawVisibleItem( return false; } - RHI::RHIResourceView* baseColorTextureView = ResolveTextureView(visibleItem); + RHI::RHIResourceView* baseColorTextureView = ResolveTextureView(material); if (passLayout->baseColorTexture.IsValid() && baseColorTextureView == nullptr) { return false; } @@ -585,7 +584,10 @@ bool BuiltinForwardPipeline::DrawVisibleItems( return; } - const Resources::Material* material = ResolveMaterial(visibleItem); + const Resources::Material* material = + drawSettings.HasOverrideMaterial() + ? drawSettings.overrideMaterial.Get() + : ResolveMaterial(visibleItem); BuiltinMaterialPass pass = BuiltinMaterialPass::ForwardLit; if (!TryResolveSurfacePassType(material, pass)) { return; @@ -601,7 +603,7 @@ bool BuiltinForwardPipeline::DrawVisibleItems( currentPipelineState = pipelineState; } - if (!DrawVisibleItem(executionContext, visibleItem)) { + if (!DrawVisibleItem(executionContext, visibleItem, material)) { drawFailed = true; } }; diff --git a/engine/src/Scripting/Mono/MonoScriptRuntime.cpp b/engine/src/Scripting/Mono/MonoScriptRuntime.cpp index 7b625734..29473a4b 100644 --- a/engine/src/Scripting/Mono/MonoScriptRuntime.cpp +++ b/engine/src/Scripting/Mono/MonoScriptRuntime.cpp @@ -24,6 +24,7 @@ #include "Rendering/RenderPassGraphContract.h" #include "Rendering/RenderPipelineStageGraphContract.h" #include "Resources/BuiltinResources.h" +#include "Core/Asset/ResourceManager.h" #include "Scene/Scene.h" #include "Scripting/ScriptComponent.h" #include "Scripting/ScriptEngine.h" @@ -4590,7 +4591,8 @@ mono_bool InternalCall_Rendering_ScriptableRenderContext_DrawRenderersByDesc( uint64_t nativeHandle, int32_t scenePhase, - ManagedRendererListDescData* rendererListDescData) { + ManagedRendererListDescData* rendererListDescData, + MonoString* overrideMaterialPath) { ManagedScriptableRenderContextState* const state = FindManagedScriptableRenderContextState(nativeHandle); if (state == nullptr || @@ -4607,6 +4609,23 @@ InternalCall_Rendering_ScriptableRenderContext_DrawRenderersByDesc( drawSettings.rendererListDesc = *reinterpret_cast( rendererListDescData); + const std::string overrideMaterialPathUtf8 = + MonoStringToUtf8(overrideMaterialPath); + if (!overrideMaterialPathUtf8.empty()) { + drawSettings.overrideMaterial = + Resources::ResourceManager::Get().Load( + overrideMaterialPathUtf8.c_str()); + if (!drawSettings.overrideMaterial.IsValid()) { + Debug::Logger::Get().Error( + Debug::LogCategory::Rendering, + (Containers::String( + "ScriptableRenderContext DrawRenderers failed to load override material: ") + + Containers::String(overrideMaterialPathUtf8.c_str())) + .CStr()); + return 0; + } + } + return state->sceneRecorder->RecordSceneDrawSettings( drawSettings) ? 1 diff --git a/managed/CMakeLists.txt b/managed/CMakeLists.txt index 32b3895f..c7ccddf4 100644 --- a/managed/CMakeLists.txt +++ b/managed/CMakeLists.txt @@ -173,6 +173,7 @@ set(XCENGINE_SCRIPT_CORE_SOURCES # Rendering core ${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.ScriptCore/Rendering/Core/CameraFrameColorSource.cs ${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.ScriptCore/Rendering/Core/CameraFrameStage.cs + ${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.ScriptCore/Rendering/Core/DrawingSettings.cs ${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.ScriptCore/Rendering/Core/FinalColorExposureMode.cs ${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.ScriptCore/Rendering/Core/FinalColorOutputTransferMode.cs ${CMAKE_CURRENT_SOURCE_DIR}/XCEngine.ScriptCore/Rendering/Core/FinalColorSettings.cs diff --git a/managed/GameScripts/ScriptableRenderContextApiSurfaceProbe.cs b/managed/GameScripts/ScriptableRenderContextApiSurfaceProbe.cs index eab0c2a6..dbbd7407 100644 --- a/managed/GameScripts/ScriptableRenderContextApiSurfaceProbe.cs +++ b/managed/GameScripts/ScriptableRenderContextApiSurfaceProbe.cs @@ -13,6 +13,7 @@ namespace Gameplay public bool HasPublicContextRecordSceneInjectionPoint; public bool HasPublicContextDrawRenderersByType; public bool HasPublicContextDrawRenderersByDesc; + public bool HasPublicContextDrawRenderersByDescAndSettings; public bool HasPublicContextDrawOpaqueRenderers; public bool HasPublicContextDrawTransparentRenderers; public bool HasPublicContextRecordOpaqueScenePhase; @@ -66,6 +67,7 @@ namespace Gameplay public bool HasSceneRenderPhaseType; public bool HasSceneRenderInjectionPointType; public bool HasRendererListType; + public bool HasDrawingSettingsType; public bool HasRenderQueueRangeType; public bool HasRendererSortModeType; public bool HasFilteringSettingsType; @@ -135,6 +137,18 @@ namespace Gameplay typeof(RendererListDesc) }, null) != null; + HasPublicContextDrawRenderersByDescAndSettings = + contextType.GetMethod( + "DrawRenderers", + PublicInstanceMethodFlags, + null, + new System.Type[] + { + typeof(SceneRenderPhase), + typeof(RendererListDesc), + typeof(DrawingSettings) + }, + null) != null; HasPublicContextDrawOpaqueRenderers = contextType.GetMethod( "DrawOpaqueRenderers", @@ -353,6 +367,9 @@ namespace Gameplay HasRendererListType = contextType.Assembly.GetType( "XCEngine.Rendering.RendererListType") != null; + HasDrawingSettingsType = + contextType.Assembly.GetType( + "XCEngine.Rendering.DrawingSettings") != null; HasRenderQueueRangeType = contextType.Assembly.GetType( "XCEngine.Rendering.RenderQueueRange") != null; diff --git a/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/DrawObjectsPass.cs b/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/DrawObjectsPass.cs index 44d45090..b0dc6040 100644 --- a/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/DrawObjectsPass.cs +++ b/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/DrawObjectsPass.cs @@ -10,26 +10,56 @@ namespace XCEngine.Rendering.Universal private RendererListDesc m_rendererListDesc = RendererListDesc.CreateDefault( RendererListType.Opaque); + private DrawingSettings m_drawingSettings = + DrawingSettings.CreateDefault(); public DrawObjectsPass( RenderPassEvent passEvent, SceneRenderPhase scenePhase, RendererListDesc rendererListDesc) + : this( + passEvent, + scenePhase, + rendererListDesc, + DrawingSettings.CreateDefault()) + { + } + + public DrawObjectsPass( + RenderPassEvent passEvent, + SceneRenderPhase scenePhase, + RendererListDesc rendererListDesc, + DrawingSettings drawingSettings) { Configure( passEvent, scenePhase, - rendererListDesc); + rendererListDesc, + drawingSettings); } public void Configure( RenderPassEvent passEvent, SceneRenderPhase scenePhase, RendererListDesc rendererListDesc) + { + Configure( + passEvent, + scenePhase, + rendererListDesc, + DrawingSettings.CreateDefault()); + } + + public void Configure( + RenderPassEvent passEvent, + SceneRenderPhase scenePhase, + RendererListDesc rendererListDesc, + DrawingSettings drawingSettings) { renderPassEvent = passEvent; m_scenePhase = scenePhase; m_rendererListDesc = rendererListDesc; + m_drawingSettings = drawingSettings; } protected override bool RecordRenderGraph( @@ -41,7 +71,8 @@ namespace XCEngine.Rendering.Universal renderingData.isMainSceneStage && context.DrawRenderers( m_scenePhase, - m_rendererListDesc); + m_rendererListDesc, + m_drawingSettings); } } } diff --git a/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/RenderObjectsRendererFeature.cs b/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/RenderObjectsRendererFeature.cs index d125c628..5481b31c 100644 --- a/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/RenderObjectsRendererFeature.cs +++ b/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/RenderObjectsRendererFeature.cs @@ -19,6 +19,7 @@ namespace XCEngine.Rendering.Universal RenderQueueRange.Opaque; public bool overrideRenderLayerMask; public uint renderLayerMask = uint.MaxValue; + public string overrideMaterialPath = string.Empty; public bool overrideFilteringSettings; public FilteringSettings filteringSettings; public bool overrideSortingSettings; @@ -28,20 +29,24 @@ namespace XCEngine.Rendering.Universal { RendererListDesc rendererListDesc = BuildRendererListDesc(); + DrawingSettings drawingSettings = + BuildDrawingSettings(); if (m_pass == null) { m_pass = new DrawObjectsPass( passEvent, scenePhase, - rendererListDesc); + rendererListDesc, + drawingSettings); return; } m_pass.Configure( passEvent, scenePhase, - rendererListDesc); + rendererListDesc, + drawingSettings); } public override void AddRenderPasses( @@ -63,7 +68,8 @@ namespace XCEngine.Rendering.Universal m_pass.Configure( passEvent, scenePhase, - BuildRendererListDesc()); + BuildRendererListDesc(), + BuildDrawingSettings()); renderer.EnqueuePass(m_pass); } @@ -98,5 +104,14 @@ namespace XCEngine.Rendering.Universal return rendererListDesc; } + + private DrawingSettings BuildDrawingSettings() + { + DrawingSettings drawingSettings = + DrawingSettings.CreateDefault(); + drawingSettings.overrideMaterialPath = + overrideMaterialPath ?? string.Empty; + return drawingSettings; + } } } diff --git a/managed/XCEngine.ScriptCore/InternalCalls.cs b/managed/XCEngine.ScriptCore/InternalCalls.cs index fad81ffa..4fec83de 100644 --- a/managed/XCEngine.ScriptCore/InternalCalls.cs +++ b/managed/XCEngine.ScriptCore/InternalCalls.cs @@ -781,7 +781,8 @@ namespace XCEngine Rendering_ScriptableRenderContext_DrawRenderersByDesc( ulong nativeHandle, int scenePhase, - ref Rendering.RendererListDesc rendererListDesc); + ref Rendering.RendererListDesc rendererListDesc, + string overrideMaterialPath); [MethodImpl(MethodImplOptions.InternalCall)] internal static extern bool diff --git a/managed/XCEngine.ScriptCore/Rendering/Core/DrawingSettings.cs b/managed/XCEngine.ScriptCore/Rendering/Core/DrawingSettings.cs new file mode 100644 index 00000000..d890ea13 --- /dev/null +++ b/managed/XCEngine.ScriptCore/Rendering/Core/DrawingSettings.cs @@ -0,0 +1,19 @@ +namespace XCEngine.Rendering +{ + public struct DrawingSettings + { + public string overrideMaterialPath; + + public bool hasOverrideMaterial => + !string.IsNullOrEmpty( + overrideMaterialPath); + + public static DrawingSettings CreateDefault() + { + return new DrawingSettings + { + overrideMaterialPath = string.Empty + }; + } + } +} diff --git a/managed/XCEngine.ScriptCore/Rendering/Core/ScriptableRenderContext.cs b/managed/XCEngine.ScriptCore/Rendering/Core/ScriptableRenderContext.cs index c795b865..13fa4283 100644 --- a/managed/XCEngine.ScriptCore/Rendering/Core/ScriptableRenderContext.cs +++ b/managed/XCEngine.ScriptCore/Rendering/Core/ScriptableRenderContext.cs @@ -67,22 +67,47 @@ namespace XCEngine.Rendering public bool DrawRenderers( SceneRenderPhase scenePhase, RendererListType rendererListType) + { + return DrawRenderers( + scenePhase, + rendererListType, + DrawingSettings.CreateDefault()); + } + + public bool DrawRenderers( + SceneRenderPhase scenePhase, + RendererListType rendererListType, + DrawingSettings drawingSettings) { return DrawRenderers( scenePhase, RendererListDesc.CreateDefault( - rendererListType)); + rendererListType), + drawingSettings); } public bool DrawRenderers( SceneRenderPhase scenePhase, RendererListDesc rendererListDesc) + { + return DrawRenderers( + scenePhase, + rendererListDesc, + DrawingSettings.CreateDefault()); + } + + public bool DrawRenderers( + SceneRenderPhase scenePhase, + RendererListDesc rendererListDesc, + DrawingSettings drawingSettings) { return InternalCalls .Rendering_ScriptableRenderContext_DrawRenderersByDesc( m_nativeHandle, (int)scenePhase, - ref rendererListDesc); + ref rendererListDesc, + drawingSettings.overrideMaterialPath ?? + string.Empty); } public bool RecordOpaqueScenePhase() diff --git a/project/Assets/Scripts/ProjectRenderPipelineProbe.cs b/project/Assets/Scripts/ProjectRenderPipelineProbe.cs index a5acf9a9..c4406a4c 100644 --- a/project/Assets/Scripts/ProjectRenderPipelineProbe.cs +++ b/project/Assets/Scripts/ProjectRenderPipelineProbe.cs @@ -139,6 +139,8 @@ namespace ProjectScripts RenderPassEvent.RenderOpaques, scenePhase = SceneRenderPhase.Opaque, + overrideMaterialPath = + "Assets/New Material.mat", overrideRenderQueueRange = true, renderQueueRange = RenderQueueRange.Opaque,