From 39803ce6b29a0aa59ea4ba22a38e7130bc3763ac Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Tue, 7 Oct 2025 18:23:03 +0200 Subject: [PATCH] Add **render layer mask to decals** #967 #3080 --- Content/Editor/MaterialTemplates/Decal.shader | 12 ++++++++++++ .../Graphics/Materials/DecalMaterialShader.cpp | 4 ++++ Source/Engine/Graphics/Materials/MaterialShader.h | 2 +- Source/Engine/Level/Actors/Decal.cpp | 3 +++ Source/Engine/Level/Actors/Decal.h | 7 +++++++ Source/Engine/Renderer/GBufferPass.cpp | 1 + Source/Engine/Renderer/RenderList.h | 1 + .../Tools/MaterialGenerator/MaterialGenerator.cpp | 2 +- 8 files changed, 30 insertions(+), 2 deletions(-) diff --git a/Content/Editor/MaterialTemplates/Decal.shader b/Content/Editor/MaterialTemplates/Decal.shader index b933fcbb3..c958d8a4a 100644 --- a/Content/Editor/MaterialTemplates/Decal.shader +++ b/Content/Editor/MaterialTemplates/Decal.shader @@ -6,6 +6,7 @@ @3 #include "./Flax/Common.hlsl" +#include "./Flax/Stencil.hlsl" #include "./Flax/MaterialCommon.hlsl" #include "./Flax/GBufferCommon.hlsl" @7 @@ -14,10 +15,13 @@ META_CB_BEGIN(0, Data) float4x4 WorldMatrix; float4x4 InvWorld; float4x4 SvPositionToWorld; +float3 Padding0; +uint RenderLayersMask; @1META_CB_END // Use depth buffer for per-pixel decal layering Texture2D DepthBuffer : register(t0); +Texture2D StencilBuffer : register(t1); // Material shader resources @2 @@ -200,6 +204,14 @@ void PS_Decal( #endif ) { + // Stencil masking + uint stencilObjectLayer = STENCIL_BUFFER_OBJECT_LAYER(STENCIL_BUFFER_LOAD(StencilBuffer, SvPosition.xy)); + if ((RenderLayersMask & (1 << stencilObjectLayer)) == 0) + { + clip(-1); + return; + } + float2 screenUV = SvPosition.xy * ScreenSize.zw; SvPosition.z = SAMPLE_RT(DepthBuffer, screenUV).r; diff --git a/Source/Engine/Graphics/Materials/DecalMaterialShader.cpp b/Source/Engine/Graphics/Materials/DecalMaterialShader.cpp index ffc8fa241..7cf9c96d1 100644 --- a/Source/Engine/Graphics/Materials/DecalMaterialShader.cpp +++ b/Source/Engine/Graphics/Materials/DecalMaterialShader.cpp @@ -17,6 +17,8 @@ PACK_STRUCT(struct DecalMaterialShaderData { Matrix WorldMatrix; Matrix InvWorld; Matrix SvPositionToWorld; + Float3 Padding0; + uint32 RenderLayersMask; }); DrawPass DecalMaterialShader::GetDrawModes() const @@ -50,6 +52,7 @@ void DecalMaterialShader::Bind(BindParameters& params) GPUTexture* depthBuffer = params.RenderContext.Buffers->DepthBuffer; GPUTextureView* depthBufferView = EnumHasAnyFlags(depthBuffer->Flags(), GPUTextureFlags::ReadOnlyDepthView) ? depthBuffer->ViewReadOnlyDepth() : depthBuffer->View(); context->BindSR(0, depthBufferView); + context->BindSR(1, depthBuffer->ViewStencil()); // Setup material constants { @@ -68,6 +71,7 @@ void DecalMaterialShader::Bind(BindParameters& params) -1.0f, 1.0f, 0, 1); const Matrix svPositionToWorld = offsetMatrix * view.IVP; Matrix::Transpose(svPositionToWorld, materialData->SvPositionToWorld); + materialData->RenderLayersMask = (uint32)drawCall.SortKey; // Provided by GBufferPass::DrawDecals } // Bind constants diff --git a/Source/Engine/Graphics/Materials/MaterialShader.h b/Source/Engine/Graphics/Materials/MaterialShader.h index c45fd3748..5da4ee04f 100644 --- a/Source/Engine/Graphics/Materials/MaterialShader.h +++ b/Source/Engine/Graphics/Materials/MaterialShader.h @@ -10,7 +10,7 @@ /// /// Current materials shader version. /// -#define MATERIAL_GRAPH_VERSION 177 +#define MATERIAL_GRAPH_VERSION 178 class Material; class GPUShader; diff --git a/Source/Engine/Level/Actors/Decal.cpp b/Source/Engine/Level/Actors/Decal.cpp index 82661b131..78066133c 100644 --- a/Source/Engine/Level/Actors/Decal.cpp +++ b/Source/Engine/Level/Actors/Decal.cpp @@ -87,6 +87,7 @@ void Decal::Draw(RenderContext& renderContext) transform.Scale *= _size; renderContext.View.GetWorldMatrix(transform, data.World); data.SortOrder = SortOrder; + data.RenderLayersMask = RenderLayersMask; data.Material = material; renderContext.List->Decals.Add(data); } @@ -102,6 +103,7 @@ void Decal::Serialize(SerializeStream& stream, const void* otherObj) SERIALIZE(Material); SERIALIZE_MEMBER(Size, _size); SERIALIZE(SortOrder); + SERIALIZE(RenderLayersMask); SERIALIZE(DrawMinScreenSize); } @@ -113,6 +115,7 @@ void Decal::Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) DESERIALIZE(Material); DESERIALIZE_MEMBER(Size, _size); DESERIALIZE(SortOrder); + DESERIALIZE(RenderLayersMask); DESERIALIZE(DrawMinScreenSize); _bounds.Extents = _size * 0.5f; diff --git a/Source/Engine/Level/Actors/Decal.h b/Source/Engine/Level/Actors/Decal.h index 3adfdcbac..068a4447e 100644 --- a/Source/Engine/Level/Actors/Decal.h +++ b/Source/Engine/Level/Actors/Decal.h @@ -3,6 +3,7 @@ #pragma once #include "../Actor.h" +#include "Engine/Core/Types/LayersMask.h" #include "Engine/Core/Math/Matrix.h" #include "Engine/Core/Math/OrientedBoundingBox.h" #include "Engine/Content/Assets/MaterialBase.h" @@ -33,6 +34,12 @@ public: API_FIELD(Attributes="EditorOrder(20), EditorDisplay(\"Decal\")") int32 SortOrder = 0; + /// + /// The layers mask used for render composition. Can be used to include or exclude specific actor layers from the drawing on top of them. + /// + API_FIELD(Attributes = "EditorOrder(25), EditorDisplay(\"Decal\")") + LayersMask RenderLayersMask; + /// /// The minimum screen size for the decal drawing. If the decal size on the screen is smaller than this value then decal will be culled. Set it to higher value to make culling more aggressive. /// diff --git a/Source/Engine/Renderer/GBufferPass.cpp b/Source/Engine/Renderer/GBufferPass.cpp index 7c9abb413..1881aac3b 100644 --- a/Source/Engine/Renderer/GBufferPass.cpp +++ b/Source/Engine/Renderer/GBufferPass.cpp @@ -518,6 +518,7 @@ void GBufferPass::DrawDecals(RenderContext& renderContext, GPUTextureView* light // Draw decal drawCall.World = decal.World; + drawCall.SortKey = (uint64)decal.RenderLayersMask; decal.Material->Bind(bindParams); // TODO: use hardware instancing context->DrawIndexed(drawCall.Draw.IndicesCount); diff --git a/Source/Engine/Renderer/RenderList.h b/Source/Engine/Renderer/RenderList.h index fc11b26cc..7a3ac867a 100644 --- a/Source/Engine/Renderer/RenderList.h +++ b/Source/Engine/Renderer/RenderList.h @@ -167,6 +167,7 @@ struct RenderDecalData Matrix World; MaterialBase* Material; int32 SortOrder; + uint32 RenderLayersMask; }; /// diff --git a/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.cpp b/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.cpp index 46368cf73..c473f940c 100644 --- a/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.cpp +++ b/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.cpp @@ -490,7 +490,7 @@ bool MaterialGenerator::Generate(WriteStream& source, MaterialInfo& materialInfo srv = 3; // Objects + Skinning Bones + Prev Bones break; case MaterialDomain::Decal: - srv = 1; // Depth buffer + srv = 2; // Depth buffer + Stencil buffer break; case MaterialDomain::Terrain: srv = 3; // Heightmap + 2 splatmaps