diff --git a/engine/include/XCEngine/Rendering/Execution/DrawSettings.h b/engine/include/XCEngine/Rendering/Execution/DrawSettings.h index 13366d7d..974afdf4 100644 --- a/engine/include/XCEngine/Rendering/Execution/DrawSettings.h +++ b/engine/include/XCEngine/Rendering/Execution/DrawSettings.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include #include @@ -12,10 +13,15 @@ struct DrawSettings { ScenePhase scenePhase = ScenePhase::Opaque; RendererListDesc rendererListDesc = {}; Resources::ResourceHandle overrideMaterial = {}; + Containers::String shaderPassName = {}; bool HasOverrideMaterial() const { return overrideMaterial.IsValid(); } + + bool HasShaderPassName() const { + return !shaderPassName.Empty(); + } }; } // namespace Rendering diff --git a/engine/include/XCEngine/Rendering/Pipelines/BuiltinForwardPipeline.h b/engine/include/XCEngine/Rendering/Pipelines/BuiltinForwardPipeline.h index 6c3d99cc..c0148c65 100644 --- a/engine/include/XCEngine/Rendering/Pipelines/BuiltinForwardPipeline.h +++ b/engine/include/XCEngine/Rendering/Pipelines/BuiltinForwardPipeline.h @@ -297,10 +297,12 @@ private: void DestroyPipelineResources(); static bool TryResolveSurfacePassType( const Resources::Material* material, + const BuiltinMaterialPass* preferredPass, BuiltinMaterialPass& outPass); ResolvedShaderPass ResolveSurfaceShaderPass( const RenderSceneData& sceneData, - const Resources::Material* material) const; + const Resources::Material* material, + const BuiltinMaterialPass* preferredPass) const; PassResourceLayout* GetOrCreatePassResourceLayout( const RenderContext& context, const ResolvedShaderPass& resolvedShaderPass); @@ -308,7 +310,8 @@ private: const RenderContext& context, const RenderSurface& surface, const RenderSceneData& sceneData, - const Resources::Material* material); + const Resources::Material* material, + const BuiltinMaterialPass* preferredPass); RHI::RHIPipelineState* GetOrCreateSkyboxPipelineState( const RenderContext& context, const RenderSurface& surface); @@ -364,7 +367,8 @@ private: bool DrawVisibleItem( const FrameExecutionContext& executionContext, const VisibleRenderItem& visibleItem, - const Resources::Material* material); + const Resources::Material* material, + const BuiltinMaterialPass* preferredPass); 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 8eff1090..79e9288a 100644 --- a/engine/src/Rendering/Pipelines/Internal/BuiltinForwardPipelineSurface.cpp +++ b/engine/src/Rendering/Pipelines/Internal/BuiltinForwardPipelineSurface.cpp @@ -106,6 +106,32 @@ bool UsesDynamicSurfaceDescriptorSet(const BuiltinPassSetLayoutMetadata& setLayo setLayout.usesMaterialBuffers; } +bool TryResolveRequestedSurfacePassType( + const DrawSettings& drawSettings, + BuiltinMaterialPass& outPass, + bool& outHasRequestedPass) { + outHasRequestedPass = false; + if (!drawSettings.HasShaderPassName()) { + return true; + } + + outHasRequestedPass = true; + const Containers::String normalizedPassName = + NormalizeBuiltinPassMetadataValue(drawSettings.shaderPassName); + if (normalizedPassName == Containers::String("forward") || + MatchesBuiltinPassName(normalizedPassName, BuiltinMaterialPass::ForwardLit)) { + outPass = BuiltinMaterialPass::ForwardLit; + return true; + } + + if (MatchesBuiltinPassName(normalizedPassName, BuiltinMaterialPass::Unlit)) { + outPass = BuiltinMaterialPass::Unlit; + return true; + } + + return false; +} + } // namespace RHI::InputLayoutDesc BuiltinForwardPipeline::BuildInputLayout() { @@ -172,7 +198,17 @@ RHI::InputLayoutDesc BuiltinForwardPipeline::BuildInputLayout() { bool BuiltinForwardPipeline::TryResolveSurfacePassType( const Resources::Material* material, + const BuiltinMaterialPass* preferredPass, BuiltinMaterialPass& outPass) { + if (preferredPass != nullptr) { + if (MatchesBuiltinPass(material, *preferredPass)) { + outPass = *preferredPass; + return true; + } + + return false; + } + if (MatchesBuiltinPass(material, BuiltinMaterialPass::Unlit)) { outPass = BuiltinMaterialPass::Unlit; return true; @@ -188,10 +224,14 @@ bool BuiltinForwardPipeline::TryResolveSurfacePassType( BuiltinForwardPipeline::ResolvedShaderPass BuiltinForwardPipeline::ResolveSurfaceShaderPass( const RenderSceneData& sceneData, - const Resources::Material* material) const { + const Resources::Material* material, + const BuiltinMaterialPass* preferredPass) const { ResolvedShaderPass resolved = {}; - BuiltinMaterialPass pass = BuiltinMaterialPass::ForwardLit; - if (!TryResolveSurfacePassType(material, pass)) { + BuiltinMaterialPass pass = + preferredPass != nullptr + ? *preferredPass + : BuiltinMaterialPass::ForwardLit; + if (!TryResolveSurfacePassType(material, preferredPass, pass)) { return resolved; } @@ -227,9 +267,14 @@ RHI::RHIPipelineState* BuiltinForwardPipeline::GetOrCreatePipelineState( const RenderContext& context, const RenderSurface& surface, const RenderSceneData& sceneData, - const Resources::Material* material) { + const Resources::Material* material, + const BuiltinMaterialPass* preferredPass) { const Resources::ShaderKeywordSet keywordSet = ResolvePassKeywordSet(sceneData, material); - const ResolvedShaderPass resolvedShaderPass = ResolveSurfaceShaderPass(sceneData, material); + const ResolvedShaderPass resolvedShaderPass = + ResolveSurfaceShaderPass( + sceneData, + material, + preferredPass); if (resolvedShaderPass.shader == nullptr || resolvedShaderPass.pass == nullptr) { Debug::Logger::Get().Error( Debug::LogCategory::Rendering, @@ -402,7 +447,8 @@ bool BuiltinForwardPipeline::ExecuteForwardTransparentPass( bool BuiltinForwardPipeline::DrawVisibleItem( const FrameExecutionContext& executionContext, const VisibleRenderItem& visibleItem, - const Resources::Material* material) { + const Resources::Material* material, + const BuiltinMaterialPass* preferredPass) { const RenderContext& context = executionContext.renderContext; const RenderSceneData& sceneData = executionContext.sceneData; @@ -435,7 +481,11 @@ bool BuiltinForwardPipeline::DrawVisibleItem( shadowReceiverConstants.shadowSampling = sceneData.lighting.mainDirectionalShadow.sampling; } - const ResolvedShaderPass resolvedShaderPass = ResolveSurfaceShaderPass(sceneData, material); + const ResolvedShaderPass resolvedShaderPass = + ResolveSurfaceShaderPass( + sceneData, + material, + preferredPass); if (resolvedShaderPass.shader == nullptr || resolvedShaderPass.pass == nullptr) { return false; } @@ -578,6 +628,25 @@ bool BuiltinForwardPipeline::DrawVisibleItems( RHI::RHICommandList* commandList = context.commandList; RHI::RHIPipelineState* currentPipelineState = nullptr; bool drawFailed = false; + BuiltinMaterialPass requestedPass = BuiltinMaterialPass::ForwardLit; + bool hasRequestedPass = false; + if (!TryResolveRequestedSurfacePassType( + drawSettings, + requestedPass, + hasRequestedPass)) { + Debug::Logger::Get().Error( + Debug::LogCategory::Rendering, + (Containers::String( + "BuiltinForwardPipeline only supports explicit shaderPassName values of ForwardLit or Unlit for scene draws, received: ") + + drawSettings.shaderPassName) + .CStr()); + return false; + } + + const BuiltinMaterialPass* preferredPass = + hasRequestedPass + ? &requestedPass + : nullptr; auto drawVisibleItem = [&](const VisibleRenderItem& visibleItem) { if (drawFailed) { @@ -588,12 +657,24 @@ bool BuiltinForwardPipeline::DrawVisibleItems( drawSettings.HasOverrideMaterial() ? drawSettings.overrideMaterial.Get() : ResolveMaterial(visibleItem); - BuiltinMaterialPass pass = BuiltinMaterialPass::ForwardLit; - if (!TryResolveSurfacePassType(material, pass)) { + BuiltinMaterialPass pass = + preferredPass != nullptr + ? *preferredPass + : BuiltinMaterialPass::ForwardLit; + if (!TryResolveSurfacePassType( + material, + preferredPass, + pass)) { return; } - RHI::RHIPipelineState* pipelineState = GetOrCreatePipelineState(context, surface, sceneData, material); + RHI::RHIPipelineState* pipelineState = + GetOrCreatePipelineState( + context, + surface, + sceneData, + material, + preferredPass); if (pipelineState == nullptr) { drawFailed = true; return; @@ -603,7 +684,11 @@ bool BuiltinForwardPipeline::DrawVisibleItems( currentPipelineState = pipelineState; } - if (!DrawVisibleItem(executionContext, visibleItem, material)) { + if (!DrawVisibleItem( + executionContext, + visibleItem, + material, + preferredPass)) { drawFailed = true; } }; diff --git a/engine/src/Scripting/Mono/MonoScriptRuntime.cpp b/engine/src/Scripting/Mono/MonoScriptRuntime.cpp index 29473a4b..27efd445 100644 --- a/engine/src/Scripting/Mono/MonoScriptRuntime.cpp +++ b/engine/src/Scripting/Mono/MonoScriptRuntime.cpp @@ -4592,7 +4592,8 @@ InternalCall_Rendering_ScriptableRenderContext_DrawRenderersByDesc( uint64_t nativeHandle, int32_t scenePhase, ManagedRendererListDescData* rendererListDescData, - MonoString* overrideMaterialPath) { + MonoString* overrideMaterialPath, + MonoString* shaderPassName) { ManagedScriptableRenderContextState* const state = FindManagedScriptableRenderContextState(nativeHandle); if (state == nullptr || @@ -4626,6 +4627,13 @@ InternalCall_Rendering_ScriptableRenderContext_DrawRenderersByDesc( } } + const std::string shaderPassNameUtf8 = + MonoStringToUtf8(shaderPassName); + if (!shaderPassNameUtf8.empty()) { + drawSettings.shaderPassName = + Containers::String(shaderPassNameUtf8.c_str()); + } + return state->sceneRecorder->RecordSceneDrawSettings( drawSettings) ? 1 diff --git a/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/RenderObjectsRendererFeature.cs b/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/RenderObjectsRendererFeature.cs index 5481b31c..613b3eba 100644 --- a/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/RenderObjectsRendererFeature.cs +++ b/managed/XCEngine.RenderPipelines.Universal/Rendering/Universal/RenderObjectsRendererFeature.cs @@ -20,6 +20,7 @@ namespace XCEngine.Rendering.Universal public bool overrideRenderLayerMask; public uint renderLayerMask = uint.MaxValue; public string overrideMaterialPath = string.Empty; + public string shaderPassName = string.Empty; public bool overrideFilteringSettings; public FilteringSettings filteringSettings; public bool overrideSortingSettings; @@ -111,6 +112,8 @@ namespace XCEngine.Rendering.Universal DrawingSettings.CreateDefault(); drawingSettings.overrideMaterialPath = overrideMaterialPath ?? string.Empty; + drawingSettings.shaderPassName = + shaderPassName ?? string.Empty; return drawingSettings; } } diff --git a/managed/XCEngine.ScriptCore/InternalCalls.cs b/managed/XCEngine.ScriptCore/InternalCalls.cs index 4fec83de..8abe5596 100644 --- a/managed/XCEngine.ScriptCore/InternalCalls.cs +++ b/managed/XCEngine.ScriptCore/InternalCalls.cs @@ -782,7 +782,8 @@ namespace XCEngine ulong nativeHandle, int scenePhase, ref Rendering.RendererListDesc rendererListDesc, - string overrideMaterialPath); + string overrideMaterialPath, + string shaderPassName); [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 index d890ea13..e59a86e1 100644 --- a/managed/XCEngine.ScriptCore/Rendering/Core/DrawingSettings.cs +++ b/managed/XCEngine.ScriptCore/Rendering/Core/DrawingSettings.cs @@ -3,16 +3,22 @@ namespace XCEngine.Rendering public struct DrawingSettings { public string overrideMaterialPath; + public string shaderPassName; public bool hasOverrideMaterial => !string.IsNullOrEmpty( overrideMaterialPath); + public bool hasShaderPassName => + !string.IsNullOrEmpty( + shaderPassName); + public static DrawingSettings CreateDefault() { return new DrawingSettings { - overrideMaterialPath = string.Empty + overrideMaterialPath = string.Empty, + shaderPassName = string.Empty }; } } diff --git a/managed/XCEngine.ScriptCore/Rendering/Core/ScriptableRenderContext.cs b/managed/XCEngine.ScriptCore/Rendering/Core/ScriptableRenderContext.cs index 13fa4283..a1ee8f7b 100644 --- a/managed/XCEngine.ScriptCore/Rendering/Core/ScriptableRenderContext.cs +++ b/managed/XCEngine.ScriptCore/Rendering/Core/ScriptableRenderContext.cs @@ -107,6 +107,8 @@ namespace XCEngine.Rendering (int)scenePhase, ref rendererListDesc, drawingSettings.overrideMaterialPath ?? + string.Empty, + drawingSettings.shaderPassName ?? string.Empty); } diff --git a/project/Assets/Scripts/ProjectRenderPipelineProbe.cs b/project/Assets/Scripts/ProjectRenderPipelineProbe.cs index c4406a4c..1de12923 100644 --- a/project/Assets/Scripts/ProjectRenderPipelineProbe.cs +++ b/project/Assets/Scripts/ProjectRenderPipelineProbe.cs @@ -139,6 +139,8 @@ namespace ProjectScripts RenderPassEvent.RenderOpaques, scenePhase = SceneRenderPhase.Opaque, + shaderPassName = + "Unlit", overrideMaterialPath = "Assets/New Material.mat", overrideRenderQueueRange = true,