Add **render layer mask to decals**

#967 #3080
This commit is contained in:
Wojtek Figat
2025-10-07 18:23:03 +02:00
parent 2f1f380062
commit 39803ce6b2
8 changed files with 30 additions and 2 deletions

View File

@@ -6,6 +6,7 @@
@3 @3
#include "./Flax/Common.hlsl" #include "./Flax/Common.hlsl"
#include "./Flax/Stencil.hlsl"
#include "./Flax/MaterialCommon.hlsl" #include "./Flax/MaterialCommon.hlsl"
#include "./Flax/GBufferCommon.hlsl" #include "./Flax/GBufferCommon.hlsl"
@7 @7
@@ -14,10 +15,13 @@ META_CB_BEGIN(0, Data)
float4x4 WorldMatrix; float4x4 WorldMatrix;
float4x4 InvWorld; float4x4 InvWorld;
float4x4 SvPositionToWorld; float4x4 SvPositionToWorld;
float3 Padding0;
uint RenderLayersMask;
@1META_CB_END @1META_CB_END
// Use depth buffer for per-pixel decal layering // Use depth buffer for per-pixel decal layering
Texture2D DepthBuffer : register(t0); Texture2D DepthBuffer : register(t0);
Texture2D<uint2> StencilBuffer : register(t1);
// Material shader resources // Material shader resources
@2 @2
@@ -200,6 +204,14 @@ void PS_Decal(
#endif #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; float2 screenUV = SvPosition.xy * ScreenSize.zw;
SvPosition.z = SAMPLE_RT(DepthBuffer, screenUV).r; SvPosition.z = SAMPLE_RT(DepthBuffer, screenUV).r;

View File

@@ -17,6 +17,8 @@ PACK_STRUCT(struct DecalMaterialShaderData {
Matrix WorldMatrix; Matrix WorldMatrix;
Matrix InvWorld; Matrix InvWorld;
Matrix SvPositionToWorld; Matrix SvPositionToWorld;
Float3 Padding0;
uint32 RenderLayersMask;
}); });
DrawPass DecalMaterialShader::GetDrawModes() const DrawPass DecalMaterialShader::GetDrawModes() const
@@ -50,6 +52,7 @@ void DecalMaterialShader::Bind(BindParameters& params)
GPUTexture* depthBuffer = params.RenderContext.Buffers->DepthBuffer; GPUTexture* depthBuffer = params.RenderContext.Buffers->DepthBuffer;
GPUTextureView* depthBufferView = EnumHasAnyFlags(depthBuffer->Flags(), GPUTextureFlags::ReadOnlyDepthView) ? depthBuffer->ViewReadOnlyDepth() : depthBuffer->View(); GPUTextureView* depthBufferView = EnumHasAnyFlags(depthBuffer->Flags(), GPUTextureFlags::ReadOnlyDepthView) ? depthBuffer->ViewReadOnlyDepth() : depthBuffer->View();
context->BindSR(0, depthBufferView); context->BindSR(0, depthBufferView);
context->BindSR(1, depthBuffer->ViewStencil());
// Setup material constants // Setup material constants
{ {
@@ -68,6 +71,7 @@ void DecalMaterialShader::Bind(BindParameters& params)
-1.0f, 1.0f, 0, 1); -1.0f, 1.0f, 0, 1);
const Matrix svPositionToWorld = offsetMatrix * view.IVP; const Matrix svPositionToWorld = offsetMatrix * view.IVP;
Matrix::Transpose(svPositionToWorld, materialData->SvPositionToWorld); Matrix::Transpose(svPositionToWorld, materialData->SvPositionToWorld);
materialData->RenderLayersMask = (uint32)drawCall.SortKey; // Provided by GBufferPass::DrawDecals
} }
// Bind constants // Bind constants

View File

@@ -10,7 +10,7 @@
/// <summary> /// <summary>
/// Current materials shader version. /// Current materials shader version.
/// </summary> /// </summary>
#define MATERIAL_GRAPH_VERSION 177 #define MATERIAL_GRAPH_VERSION 178
class Material; class Material;
class GPUShader; class GPUShader;

View File

@@ -87,6 +87,7 @@ void Decal::Draw(RenderContext& renderContext)
transform.Scale *= _size; transform.Scale *= _size;
renderContext.View.GetWorldMatrix(transform, data.World); renderContext.View.GetWorldMatrix(transform, data.World);
data.SortOrder = SortOrder; data.SortOrder = SortOrder;
data.RenderLayersMask = RenderLayersMask;
data.Material = material; data.Material = material;
renderContext.List->Decals.Add(data); renderContext.List->Decals.Add(data);
} }
@@ -102,6 +103,7 @@ void Decal::Serialize(SerializeStream& stream, const void* otherObj)
SERIALIZE(Material); SERIALIZE(Material);
SERIALIZE_MEMBER(Size, _size); SERIALIZE_MEMBER(Size, _size);
SERIALIZE(SortOrder); SERIALIZE(SortOrder);
SERIALIZE(RenderLayersMask);
SERIALIZE(DrawMinScreenSize); SERIALIZE(DrawMinScreenSize);
} }
@@ -113,6 +115,7 @@ void Decal::Deserialize(DeserializeStream& stream, ISerializeModifier* modifier)
DESERIALIZE(Material); DESERIALIZE(Material);
DESERIALIZE_MEMBER(Size, _size); DESERIALIZE_MEMBER(Size, _size);
DESERIALIZE(SortOrder); DESERIALIZE(SortOrder);
DESERIALIZE(RenderLayersMask);
DESERIALIZE(DrawMinScreenSize); DESERIALIZE(DrawMinScreenSize);
_bounds.Extents = _size * 0.5f; _bounds.Extents = _size * 0.5f;

View File

@@ -3,6 +3,7 @@
#pragma once #pragma once
#include "../Actor.h" #include "../Actor.h"
#include "Engine/Core/Types/LayersMask.h"
#include "Engine/Core/Math/Matrix.h" #include "Engine/Core/Math/Matrix.h"
#include "Engine/Core/Math/OrientedBoundingBox.h" #include "Engine/Core/Math/OrientedBoundingBox.h"
#include "Engine/Content/Assets/MaterialBase.h" #include "Engine/Content/Assets/MaterialBase.h"
@@ -33,6 +34,12 @@ public:
API_FIELD(Attributes="EditorOrder(20), EditorDisplay(\"Decal\")") API_FIELD(Attributes="EditorOrder(20), EditorDisplay(\"Decal\")")
int32 SortOrder = 0; int32 SortOrder = 0;
/// <summary>
/// The layers mask used for render composition. Can be used to include or exclude specific actor layers from the drawing on top of them.
/// </summary>
API_FIELD(Attributes = "EditorOrder(25), EditorDisplay(\"Decal\")")
LayersMask RenderLayersMask;
/// <summary> /// <summary>
/// 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. /// 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.
/// </summary> /// </summary>

View File

@@ -518,6 +518,7 @@ void GBufferPass::DrawDecals(RenderContext& renderContext, GPUTextureView* light
// Draw decal // Draw decal
drawCall.World = decal.World; drawCall.World = decal.World;
drawCall.SortKey = (uint64)decal.RenderLayersMask;
decal.Material->Bind(bindParams); decal.Material->Bind(bindParams);
// TODO: use hardware instancing // TODO: use hardware instancing
context->DrawIndexed(drawCall.Draw.IndicesCount); context->DrawIndexed(drawCall.Draw.IndicesCount);

View File

@@ -167,6 +167,7 @@ struct RenderDecalData
Matrix World; Matrix World;
MaterialBase* Material; MaterialBase* Material;
int32 SortOrder; int32 SortOrder;
uint32 RenderLayersMask;
}; };
/// <summary> /// <summary>

View File

@@ -490,7 +490,7 @@ bool MaterialGenerator::Generate(WriteStream& source, MaterialInfo& materialInfo
srv = 3; // Objects + Skinning Bones + Prev Bones srv = 3; // Objects + Skinning Bones + Prev Bones
break; break;
case MaterialDomain::Decal: case MaterialDomain::Decal:
srv = 1; // Depth buffer srv = 2; // Depth buffer + Stencil buffer
break; break;
case MaterialDomain::Terrain: case MaterialDomain::Terrain:
srv = 3; // Heightmap + 2 splatmaps srv = 3; // Heightmap + 2 splatmaps