diff --git a/Content/Editor/MaterialTemplates/Features/DeferredShading.hlsl b/Content/Editor/MaterialTemplates/Features/DeferredShading.hlsl
index 556cc99a1..64cecd4f8 100644
--- a/Content/Editor/MaterialTemplates/Features/DeferredShading.hlsl
+++ b/Content/Editor/MaterialTemplates/Features/DeferredShading.hlsl
@@ -22,6 +22,9 @@ void PS_GBuffer(
#if USE_GBUFFER_CUSTOM_DATA
,out float4 RT3 : SV_Target4
#endif
+#endif
+#if USE_DEPTH_OFFSET
+ ,out float Depth : SV_Depth
#endif
)
{
@@ -36,11 +39,16 @@ void PS_GBuffer(
MaterialInput materialInput = GetMaterialInput(input);
Material material = GetMaterialPS(materialInput);
+ // Depth offset
+#if USE_DEPTH_OFFSET
+ Depth = (materialInput.SvPosition.z * materialInput.SvPosition.w) / (materialInput.SvPosition.w + material.DepthOffset);
+#endif
+
// Masking
#if MATERIAL_MASKED
clip(material.Mask - MATERIAL_MASK_THRESHOLD);
#endif
-
+
#if USE_LIGHTMAP
float3 diffuseColor = GetDiffuseColor(material.Color, material.Metalness);
float3 specularColor = GetSpecularColor(material.Color, material.Specular, material.Metalness);
diff --git a/Content/Editor/MaterialTemplates/Features/ForwardShading.hlsl b/Content/Editor/MaterialTemplates/Features/ForwardShading.hlsl
index d395a8bd1..68278f949 100644
--- a/Content/Editor/MaterialTemplates/Features/ForwardShading.hlsl
+++ b/Content/Editor/MaterialTemplates/Features/ForwardShading.hlsl
@@ -33,9 +33,15 @@ DECLARE_LIGHTSHADOWDATA_ACCESS(DirectionalLightShadow);
// Pixel Shader function for Forward Pass
META_PS(USE_FORWARD, FEATURE_LEVEL_ES2)
-float4 PS_Forward(PixelInput input) : SV_Target0
+void PS_Forward(
+ in PixelInput input
+ ,out float4 output : SV_Target0
+#if USE_DEPTH_OFFSET
+ ,out float Depth : SV_Depth
+#endif
+ )
{
- float4 output = 0;
+ output = 0;
#if USE_DITHERED_LOD_TRANSITION
// LOD masking
@@ -45,6 +51,11 @@ float4 PS_Forward(PixelInput input) : SV_Target0
// Get material parameters
MaterialInput materialInput = GetMaterialInput(input);
Material material = GetMaterialPS(materialInput);
+
+ // Depth offset
+#if USE_DEPTH_OFFSET
+ Depth = (materialInput.SvPosition.z * materialInput.SvPosition.w) / (materialInput.SvPosition.w + material.DepthOffset);
+#endif
// Masking
#if MATERIAL_MASKED
@@ -148,6 +159,4 @@ float4 PS_Forward(PixelInput input) : SV_Target0
#endif
#endif
-
- return output;
}
diff --git a/Content/Editor/MaterialTemplates/Surface.shader b/Content/Editor/MaterialTemplates/Surface.shader
index 0e7c948a1..3e93ddbb6 100644
--- a/Content/Editor/MaterialTemplates/Surface.shader
+++ b/Content/Editor/MaterialTemplates/Surface.shader
@@ -587,14 +587,18 @@ void ClipLODTransition(PixelInput input)
// Pixel Shader function for Depth Pass
META_PS(true, FEATURE_LEVEL_ES2)
-void PS_Depth(PixelInput input)
+void PS_Depth(PixelInput input
+#if USE_DEPTH_OFFSET
+ ,out float Depth : SV_Depth
+#endif
+ )
{
#if USE_DITHERED_LOD_TRANSITION
// LOD masking
ClipLODTransition(input);
#endif
-#if MATERIAL_MASKED || MATERIAL_BLEND != MATERIAL_BLEND_OPAQUE
+#if MATERIAL_MASKED || MATERIAL_BLEND != MATERIAL_BLEND_OPAQUE || USE_DEPTH_OFFSET
// Get material parameters
MaterialInput materialInput = GetMaterialInput(input);
Material material = GetMaterialPS(materialInput);
@@ -606,6 +610,11 @@ void PS_Depth(PixelInput input)
#if MATERIAL_BLEND != MATERIAL_BLEND_OPAQUE
clip(material.Opacity - MATERIAL_OPACITY_THRESHOLD);
#endif
+
+ // Depth offset
+#if USE_DEPTH_OFFSET
+ Depth = (materialInput.SvPosition.z * materialInput.SvPosition.w) / (materialInput.SvPosition.w + material.DepthOffset);
+#endif
#endif
}
diff --git a/Source/Editor/Surface/Archetypes/Material.cs b/Source/Editor/Surface/Archetypes/Material.cs
index 1a797c67d..5182dba50 100644
--- a/Source/Editor/Surface/Archetypes/Material.cs
+++ b/Source/Editor/Surface/Archetypes/Material.cs
@@ -40,6 +40,7 @@ namespace FlaxEditor.Surface.Archetypes
TessellationMultiplier = 12,
WorldDisplacement = 13,
SubsurfaceColor = 14,
+ DepthOffset = 15,
};
///
@@ -85,6 +86,7 @@ namespace FlaxEditor.Surface.Archetypes
GetBox(MaterialNodeBoxes.TessellationMultiplier).Enabled = false;
GetBox(MaterialNodeBoxes.WorldDisplacement).Enabled = false;
GetBox(MaterialNodeBoxes.SubsurfaceColor).Enabled = false;
+ GetBox(MaterialNodeBoxes.DepthOffset).Enabled = false;
return;
}
@@ -116,6 +118,7 @@ namespace FlaxEditor.Surface.Archetypes
GetBox(MaterialNodeBoxes.TessellationMultiplier).Enabled = withTess;
GetBox(MaterialNodeBoxes.WorldDisplacement).Enabled = withTess;
GetBox(MaterialNodeBoxes.SubsurfaceColor).Enabled = info.ShadingModel == MaterialShadingModel.Subsurface || info.ShadingModel == MaterialShadingModel.Foliage;
+ GetBox(MaterialNodeBoxes.DepthOffset).Enabled = true;
break;
}
case MaterialDomain.PostProcess:
@@ -134,6 +137,7 @@ namespace FlaxEditor.Surface.Archetypes
GetBox(MaterialNodeBoxes.TessellationMultiplier).Enabled = false;
GetBox(MaterialNodeBoxes.WorldDisplacement).Enabled = false;
GetBox(MaterialNodeBoxes.SubsurfaceColor).Enabled = false;
+ GetBox(MaterialNodeBoxes.DepthOffset).Enabled = false;
break;
}
case MaterialDomain.Decal:
@@ -154,6 +158,7 @@ namespace FlaxEditor.Surface.Archetypes
GetBox(MaterialNodeBoxes.TessellationMultiplier).Enabled = false;
GetBox(MaterialNodeBoxes.WorldDisplacement).Enabled = false;
GetBox(MaterialNodeBoxes.SubsurfaceColor).Enabled = false;
+ GetBox(MaterialNodeBoxes.DepthOffset).Enabled = false;
break;
}
case MaterialDomain.GUI:
@@ -172,6 +177,7 @@ namespace FlaxEditor.Surface.Archetypes
GetBox(MaterialNodeBoxes.TessellationMultiplier).Enabled = false;
GetBox(MaterialNodeBoxes.WorldDisplacement).Enabled = false;
GetBox(MaterialNodeBoxes.SubsurfaceColor).Enabled = false;
+ GetBox(MaterialNodeBoxes.DepthOffset).Enabled = false;
break;
}
case MaterialDomain.VolumeParticle:
@@ -190,6 +196,7 @@ namespace FlaxEditor.Surface.Archetypes
GetBox(MaterialNodeBoxes.TessellationMultiplier).Enabled = false;
GetBox(MaterialNodeBoxes.WorldDisplacement).Enabled = false;
GetBox(MaterialNodeBoxes.SubsurfaceColor).Enabled = false;
+ GetBox(MaterialNodeBoxes.DepthOffset).Enabled = false;
break;
}
default: throw new ArgumentOutOfRangeException();
@@ -281,7 +288,7 @@ namespace FlaxEditor.Surface.Archetypes
Title = "Material",
Description = "Main material node",
Flags = NodeFlags.MaterialGraph | NodeFlags.NoRemove | NodeFlags.NoSpawnViaGUI | NodeFlags.NoSpawnViaPaste | NodeFlags.NoCloseButton,
- Size = new Float2(150, 300),
+ Size = new Float2(150, 320),
Elements = new[]
{
NodeElementArchetype.Factory.Input(0, "", true, typeof(void), 0),
@@ -299,6 +306,7 @@ namespace FlaxEditor.Surface.Archetypes
NodeElementArchetype.Factory.Input(12, "Tessellation Multiplier", true, typeof(float), 12),
NodeElementArchetype.Factory.Input(13, "World Displacement", true, typeof(Float3), 13),
NodeElementArchetype.Factory.Input(14, "Subsurface Color", true, typeof(Float3), 14),
+ NodeElementArchetype.Factory.Input(15, "Depth Offset", true, typeof(float), 15),
}
},
new NodeArchetype
diff --git a/Source/Engine/Content/Assets/Material.cpp b/Source/Engine/Content/Assets/Material.cpp
index 76ed34b80..fb2313ff7 100644
--- a/Source/Engine/Content/Assets/Material.cpp
+++ b/Source/Engine/Content/Assets/Material.cpp
@@ -426,6 +426,9 @@ void Material::InitCompilationOptions(ShaderCompilationOptions& options)
info.BlendMode != MaterialBlendMode::Opaque &&
EnumHasAnyFlags(info.UsageFlags, MaterialUsageFlags::UseRefraction) &&
(info.FeaturesFlags & MaterialFeaturesFlags::DisableDistortion) == MaterialFeaturesFlags::None;
+ const bool useDepthOffset =
+ (info.Domain == MaterialDomain::Surface) &&
+ EnumHasAnyFlags(info.UsageFlags, MaterialUsageFlags::UseDepthOffset);
// @formatter:off
static const char* Numbers[] =
@@ -496,6 +499,7 @@ void Material::InitCompilationOptions(ShaderCompilationOptions& options)
options.Macros.Add({ "USE_FORWARD", Numbers[useForward ? 1 : 0] });
options.Macros.Add({ "USE_DEFERRED", Numbers[isSurfaceOrTerrainOrDeformable && info.BlendMode == MaterialBlendMode::Opaque ? 1 : 0] });
options.Macros.Add({ "USE_DISTORTION", Numbers[useDistortion ? 1 : 0] });
+ options.Macros.Add({ "USE_DEPTH_OFFSET", Numbers[useDepthOffset ? 1 : 0] });
#endif
}
diff --git a/Source/Engine/Graphics/Materials/MaterialInfo.h b/Source/Engine/Graphics/Materials/MaterialInfo.h
index 86fab4548..11eb8c14f 100644
--- a/Source/Engine/Graphics/Materials/MaterialInfo.h
+++ b/Source/Engine/Graphics/Materials/MaterialInfo.h
@@ -330,6 +330,11 @@ API_ENUM(Attributes="Flags") enum class MaterialUsageFlags : uint32
/// The flag used to indicate that material uses refraction feature.
///
UseRefraction = 1 << 6,
+
+ ///
+ /// The flag used to indicate that material uses per-pixel depth offset feature.
+ ///
+ UseDepthOffset = 1 << 7,
};
DECLARE_ENUM_OPERATORS(MaterialUsageFlags);
diff --git a/Source/Engine/Graphics/Materials/MaterialShader.h b/Source/Engine/Graphics/Materials/MaterialShader.h
index 007afee67..48a9abe5e 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 159
+#define MATERIAL_GRAPH_VERSION 160
class Material;
class GPUShader;
diff --git a/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.Layer.cpp b/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.Layer.cpp
index b7af16cb2..993a61469 100644
--- a/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.Layer.cpp
+++ b/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.Layer.cpp
@@ -27,10 +27,12 @@ MaterialGenerator::MaterialGraphBoxesMapping MaterialGenerator::MaterialGraphBox
{ 12, TEXT("TessellationMultiplier"), MaterialTreeType::VertexShader, MaterialValue(VariantType::Float, TEXT("4.0f")) },
{ 13, TEXT("WorldDisplacement"), MaterialTreeType::DomainShader, MaterialValue::InitForZero(VariantType::Float3) },
{ 14, TEXT("SubsurfaceColor"), MaterialTreeType::PixelShader, MaterialValue::InitForZero(VariantType::Float3) },
+ { 15, TEXT("DepthOffset"), MaterialTreeType::PixelShader, MaterialValue::InitForZero(VariantType::Float) },
};
const MaterialGenerator::MaterialGraphBoxesMapping& MaterialGenerator::GetMaterialRootNodeBox(MaterialGraphBoxes box)
{
+ static_assert(ARRAY_COUNT(MaterialGenerator::MaterialGraphBoxesMappings) == 16, "Invalid amount of boxes added for root node. Please update the code above");
return MaterialGraphBoxesMappings[static_cast(box)];
}
diff --git a/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.Layers.cpp b/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.Layers.cpp
index 63718b329..7007bf7d9 100644
--- a/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.Layers.cpp
+++ b/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.Layers.cpp
@@ -103,6 +103,7 @@ void MaterialGenerator::ProcessGroupLayers(Box* box, Node* node, Value& value)
EAT_BOX(AmbientOcclusion);
EAT_BOX(Opacity);
EAT_BOX(Refraction);
+ EAT_BOX(DepthOffset);
EAT_BOX(Mask);
EAT_BOX(Emissive);
EAT_BOX(SubsurfaceColor);
@@ -204,6 +205,7 @@ void MaterialGenerator::ProcessGroupLayers(Box* box, Node* node, Value& value)
EAT_BOX(AmbientOcclusion);
EAT_BOX(Opacity);
EAT_BOX(Refraction);
+ EAT_BOX(DepthOffset);
EAT_BOX(Mask);
EAT_BOX(Emissive);
EAT_BOX(SubsurfaceColor);
@@ -246,12 +248,15 @@ void MaterialGenerator::ProcessGroupLayers(Box* box, Node* node, Value& value)
EAT_BOX(AmbientOcclusion);
EAT_BOX(Opacity);
EAT_BOX(Refraction);
+ EAT_BOX(DepthOffset);
EAT_BOX(Mask);
EAT_BOX(Emissive);
CHECK_MATERIAL_FEATURE(Emissive, UseEmissive);
CHECK_MATERIAL_FEATURE(Normal, UseNormal);
CHECK_MATERIAL_FEATURE(Mask, UseMask);
+ CHECK_MATERIAL_FEATURE(Refraction, UseRefraction);
+ CHECK_MATERIAL_FEATURE(DepthOffset, UseDepthOffset);
break;
}
@@ -331,6 +336,7 @@ void MaterialGenerator::ProcessGroupLayers(Box* box, Node* node, Value& value)
CHECK_MATERIAL_FEATURE(Normal, UseNormal);
CHECK_MATERIAL_FEATURE(Mask, UseMask);
CHECK_MATERIAL_FEATURE(Refraction, UseRefraction);
+ CHECK_MATERIAL_FEATURE(DepthOffset, UseDepthOffset);
break;
}
diff --git a/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.cpp b/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.cpp
index b1aab0049..20722e494 100644
--- a/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.cpp
+++ b/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.cpp
@@ -256,6 +256,7 @@ bool MaterialGenerator::Generate(WriteStream& source, MaterialInfo& materialInfo
eatMaterialGraphBox(baseLayer, MaterialGraphBoxes::Roughness);
eatMaterialGraphBox(baseLayer, MaterialGraphBoxes::Opacity);
eatMaterialGraphBox(baseLayer, MaterialGraphBoxes::Refraction);
+ eatMaterialGraphBox(baseLayer, MaterialGraphBoxes::DepthOffset);
eatMaterialGraphBox(baseLayer, MaterialGraphBoxes::SubsurfaceColor);
eatMaterialGraphBox(baseLayer, MaterialGraphBoxes::Mask);
}
diff --git a/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.h b/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.h
index 92f238508..d0823d359 100644
--- a/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.h
+++ b/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.h
@@ -6,7 +6,6 @@
#include "Engine/Graphics/Materials/MaterialInfo.h"
#include "Engine/Graphics/Materials/MaterialParams.h"
-#include "Engine/Content/AssetsContainer.h"
#include "MaterialLayer.h"
#include "Types.h"
@@ -90,6 +89,11 @@ enum class MaterialGraphBoxes
///
SubsurfaceColor = 14,
+ ///
+ /// The custom depth offset applied per-pixel.
+ ///
+ DepthOffset = 15,
+
///
/// The amount of input boxes.
///
diff --git a/Source/Engine/Tools/MaterialGenerator/MaterialLayer.cpp b/Source/Engine/Tools/MaterialGenerator/MaterialLayer.cpp
index 33b3dfed3..8de2d6edb 100644
--- a/Source/Engine/Tools/MaterialGenerator/MaterialLayer.cpp
+++ b/Source/Engine/Tools/MaterialGenerator/MaterialLayer.cpp
@@ -129,6 +129,7 @@ void MaterialLayer::UpdateFeaturesFlags()
CHECK_BOX_AS_FEATURE(PositionOffset, UsePositionOffset);
CHECK_BOX_AS_FEATURE(WorldDisplacement, UseDisplacement);
CHECK_BOX_AS_FEATURE(Refraction, UseRefraction);
+ CHECK_BOX_AS_FEATURE(DepthOffset, UseDepthOffset);
#undef CHECK_BOX_AS_FEATURE
}
@@ -179,7 +180,8 @@ MaterialLayer* MaterialLayer::Load(const Guid& id, ReadStream* graphData, const
ADD_BOX(TessellationMultiplier, Float);
ADD_BOX(WorldDisplacement, Float3);
ADD_BOX(SubsurfaceColor, Float3);
- static_assert(static_cast(MaterialGraphBoxes::MAX) == 15, "Invalid amount of boxes added for root node. Please update the code above");
+ ADD_BOX(DepthOffset, Float);
+ static_assert(static_cast(MaterialGraphBoxes::MAX) == 16, "Invalid amount of boxes added for root node. Please update the code above");
ASSERT(layer->Root->Boxes.Count() == static_cast(MaterialGraphBoxes::MAX));
#if BUILD_DEBUG
// Test for valid pointers after node upgrade
@@ -225,11 +227,12 @@ void MaterialLayer::createRootNode()
INIT_BOX(Normal, Float3);
INIT_BOX(Opacity, Float);
INIT_BOX(Refraction, Float);
+ INIT_BOX(DepthOffset, Float);
INIT_BOX(PositionOffset, Float3);
INIT_BOX(TessellationMultiplier, Float);
INIT_BOX(WorldDisplacement, Float3);
INIT_BOX(SubsurfaceColor, Float3);
- static_assert(static_cast(MaterialGraphBoxes::MAX) == 15, "Invalid amount of boxes created for root node. Please update the code above");
+ static_assert(static_cast(MaterialGraphBoxes::MAX) == 16, "Invalid amount of boxes created for root node. Please update the code above");
#undef INIT_BOX
// Mark as root
diff --git a/Source/Shaders/MaterialCommon.hlsl b/Source/Shaders/MaterialCommon.hlsl
index 1f516a4fc..01ba12e8c 100644
--- a/Source/Shaders/MaterialCommon.hlsl
+++ b/Source/Shaders/MaterialCommon.hlsl
@@ -83,9 +83,10 @@ struct Material
float Opacity;
float3 SubsurfaceColor;
float Refraction;
+ float3 WorldDisplacement;
float Mask;
float TessellationMultiplier;
- float3 WorldDisplacement;
+ float DepthOffset;
#if USE_CUSTOM_VERTEX_INTERPOLATORS
float4 CustomVSToPS[CUSTOM_VERTEX_INTERPOLATORS_COUNT];
#endif