diff --git a/Source/Editor/Surface/Archetypes/Textures.cs b/Source/Editor/Surface/Archetypes/Textures.cs index a3974c740..b1a39bcb6 100644 --- a/Source/Editor/Surface/Archetypes/Textures.cs +++ b/Source/Editor/Surface/Archetypes/Textures.cs @@ -358,6 +358,19 @@ namespace FlaxEditor.Surface.Archetypes NodeElementArchetype.Factory.Input(1, "Location", true, null, 2), } }, + new NodeArchetype + { + TypeID = 14, + Title = "Sample Global SDF", + Description = "Samples the Global SDF to get the distance to the closest surface (in world-space). Requires models SDF to be generated and checking `Enable Global SDF` in Graphics Settings.", + Flags = NodeFlags.MaterialGraph, + Size = new Vector2(200, 20), + Elements = new[] + { + NodeElementArchetype.Factory.Output(0, "Distance", typeof(float), 0), + NodeElementArchetype.Factory.Input(0, "World Position", true, typeof(Vector3), 1), + } + }, }; } } diff --git a/Source/Engine/Graphics/Materials/DecalMaterialShader.cpp b/Source/Engine/Graphics/Materials/DecalMaterialShader.cpp index f0ac5300b..a8fefdbca 100644 --- a/Source/Engine/Graphics/Materials/DecalMaterialShader.cpp +++ b/Source/Engine/Graphics/Materials/DecalMaterialShader.cpp @@ -48,7 +48,7 @@ void DecalMaterialShader::Bind(BindParameters& params) bindMeta.Context = context; bindMeta.Constants = cb; bindMeta.Input = nullptr; - bindMeta.Buffers = nullptr; + bindMeta.Buffers = params.RenderContext.Buffers; bindMeta.CanSampleDepth = true; bindMeta.CanSampleGBuffer = false; MaterialParams::Bind(params.ParamsLink, bindMeta); diff --git a/Source/Engine/Graphics/Materials/DeferredMaterialShader.cpp b/Source/Engine/Graphics/Materials/DeferredMaterialShader.cpp index 29ef818e0..50780743b 100644 --- a/Source/Engine/Graphics/Materials/DeferredMaterialShader.cpp +++ b/Source/Engine/Graphics/Materials/DeferredMaterialShader.cpp @@ -74,7 +74,7 @@ void DeferredMaterialShader::Bind(BindParameters& params) bindMeta.Context = context; bindMeta.Constants = cb; bindMeta.Input = nullptr; - bindMeta.Buffers = nullptr; + bindMeta.Buffers = params.RenderContext.Buffers; bindMeta.CanSampleDepth = false; bindMeta.CanSampleGBuffer = false; MaterialParams::Bind(params.ParamsLink, bindMeta); diff --git a/Source/Engine/Graphics/Materials/DeformableMaterialShader.cpp b/Source/Engine/Graphics/Materials/DeformableMaterialShader.cpp index 61d6fb42a..f491ee700 100644 --- a/Source/Engine/Graphics/Materials/DeformableMaterialShader.cpp +++ b/Source/Engine/Graphics/Materials/DeformableMaterialShader.cpp @@ -62,7 +62,7 @@ void DeformableMaterialShader::Bind(BindParameters& params) bindMeta.Context = context; bindMeta.Constants = cb; bindMeta.Input = nullptr; - bindMeta.Buffers = nullptr; + bindMeta.Buffers = params.RenderContext.Buffers; bindMeta.CanSampleDepth = false; bindMeta.CanSampleGBuffer = false; MaterialParams::Bind(params.ParamsLink, bindMeta); diff --git a/Source/Engine/Graphics/Materials/MaterialParams.cpp b/Source/Engine/Graphics/Materials/MaterialParams.cpp index 7386343b5..e7dfe88e0 100644 --- a/Source/Engine/Graphics/Materials/MaterialParams.cpp +++ b/Source/Engine/Graphics/Materials/MaterialParams.cpp @@ -11,6 +11,8 @@ #include "Engine/Graphics/RenderBuffers.h" #include "Engine/Graphics/GPUDevice.h" #include "Engine/Graphics/GPULimits.h" +#include "Engine/Graphics/RenderTask.h" +#include "Engine/Renderer/GlobalSignDistanceFieldPass.h" #include "Engine/Streaming/Streaming.h" bool MaterialInfo8::operator==(const MaterialInfo8& other) const @@ -157,6 +159,9 @@ const Char* ToString(MaterialParameterType value) case MaterialParameterType::TextureGroupSampler: result = TEXT("TextureGroupSampler"); break; + case MaterialParameterType::GlobalSDF: + result = TEXT("GlobalSDF"); + break; default: result = TEXT(""); break; @@ -198,7 +203,6 @@ Variant MaterialParameter::GetValue() const case MaterialParameterType::GPUTexture: return _asGPUTexture.Get(); default: - CRASH; return Variant::Zero; } } @@ -303,6 +307,8 @@ void MaterialParameter::SetValue(const Variant& value) invalidType = true; } break; + case MaterialParameterType::GlobalSDF: + break; default: invalidType = true; } @@ -475,6 +481,16 @@ void MaterialParameter::Bind(BindMeta& meta) const case MaterialParameterType::TextureGroupSampler: meta.Context->BindSampler(_registerIndex, Streaming::GetTextureGroupSampler(_asInteger)); break; + case MaterialParameterType::GlobalSDF: + { + GlobalSignDistanceFieldPass::BindingData bindingData; + if (GlobalSignDistanceFieldPass::Instance()->Get(meta.Buffers, bindingData)) + Platform::MemoryClear(&bindingData, sizeof(bindingData)); + for (int32 i = 0; i < 4; i++) + meta.Context->BindSR(_registerIndex + i, bindingData.Cascades[i] ? bindingData.Cascades[i]->ViewVolume() : nullptr); + *((GlobalSignDistanceFieldPass::GlobalSDFData*)(meta.Constants.Get() + _offset)) = bindingData.GlobalSDF; + break; + } default: break; } diff --git a/Source/Engine/Graphics/Materials/MaterialParams.h b/Source/Engine/Graphics/Materials/MaterialParams.h index 664da2b19..a367114c2 100644 --- a/Source/Engine/Graphics/Materials/MaterialParams.h +++ b/Source/Engine/Graphics/Materials/MaterialParams.h @@ -128,6 +128,11 @@ enum class MaterialParameterType : byte /// The texture sampler derived from texture group settings. /// TextureGroupSampler = 19, + + /// + /// The Global SDF (textures and constants). + /// + GlobalSDF = 20, }; const Char* ToString(MaterialParameterType value); diff --git a/Source/Engine/Graphics/Materials/TerrainMaterialShader.cpp b/Source/Engine/Graphics/Materials/TerrainMaterialShader.cpp index 808278c04..b93298d7a 100644 --- a/Source/Engine/Graphics/Materials/TerrainMaterialShader.cpp +++ b/Source/Engine/Graphics/Materials/TerrainMaterialShader.cpp @@ -67,7 +67,7 @@ void TerrainMaterialShader::Bind(BindParameters& params) bindMeta.Context = context; bindMeta.Constants = cb; bindMeta.Input = nullptr; - bindMeta.Buffers = nullptr; + bindMeta.Buffers = params.RenderContext.Buffers; bindMeta.CanSampleDepth = false; bindMeta.CanSampleGBuffer = false; MaterialParams::Bind(params.ParamsLink, bindMeta); diff --git a/Source/Engine/Renderer/GlobalSignDistanceFieldPass.cpp b/Source/Engine/Renderer/GlobalSignDistanceFieldPass.cpp index 2fe47bc48..e5b39d685 100644 --- a/Source/Engine/Renderer/GlobalSignDistanceFieldPass.cpp +++ b/Source/Engine/Renderer/GlobalSignDistanceFieldPass.cpp @@ -215,7 +215,7 @@ void GlobalSignDistanceFieldPass::Dispose() bool GlobalSignDistanceFieldPass::Get(const RenderBuffers* buffers, BindingData& result) { - auto* sdfData = buffers->FindCustomBuffer(TEXT("GlobalSignDistanceField")); + auto* sdfData = buffers ? buffers->FindCustomBuffer(TEXT("GlobalSignDistanceField")) : nullptr; if (sdfData && sdfData->LastFrameUsed == Engine::FrameCount) { result = sdfData->Result; diff --git a/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.Textures.cpp b/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.Textures.cpp index bb940b610..a5e03f124 100644 --- a/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.Textures.cpp +++ b/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.Textures.cpp @@ -420,6 +420,16 @@ void MaterialGenerator::ProcessGroupTextures(Box* box, Node* node, Value& value) value = writeLocal(VariantType::Vector2, String::Format(TEXT("({3} + float2({0}, {1})) * {2}"), frameX.Value, frameY.Value, framesXYInv.Value, uv.Value), node); break; } + // Sample Global SDF + case 14: + { + auto param = findOrAddGlobalSDF(); + Value worldPosition = tryGetValue(node->GetBox(1), Value(VariantType::Vector3, TEXT("input.WorldPosition.xyz"))).Cast(VariantType::Vector3); + value = writeLocal(VariantType::Float, String::Format(TEXT("SampleGlobalSDF({0}, {0}_Tex, {1})"), param.ShaderName, worldPosition.Value), node); + _includes.Add(TEXT("./Flax/GlobalSignDistanceField.hlsl")); + //float SampleGlobalSDF(const GlobalSDFData data, Texture3D tex[4], float3 worldPosition, uint minCascade = 0) + break; + } default: break; } diff --git a/Source/Engine/Visject/ShaderGraph.cpp b/Source/Engine/Visject/ShaderGraph.cpp index 7cf2f01b5..d06a00977 100644 --- a/Source/Engine/Visject/ShaderGraph.cpp +++ b/Source/Engine/Visject/ShaderGraph.cpp @@ -1298,6 +1298,27 @@ SerializedMaterialParam& ShaderGenerator::findOrAddTextureGroupSampler(int32 ind return param; } +SerializedMaterialParam& ShaderGenerator::findOrAddGlobalSDF() +{ + // Find + for (int32 i = 0; i < _parameters.Count(); i++) + { + SerializedMaterialParam& param = _parameters[i]; + if (!param.IsPublic && param.Type == MaterialParameterType::GlobalSDF) + return param; + } + + // Create + SerializedMaterialParam& param = _parameters.AddOne(); + param.Type = MaterialParameterType::GlobalSDF; + param.IsPublic = false; + param.Override = true; + param.Name = TEXT("Global SDF"); + param.ShaderName = getParamName(_parameters.Count()); + param.ID = Guid(_parameters.Count(), 0, 0, 3); // Assign temporary id + return param; +} + String ShaderGenerator::getLocalName(int32 index) { return TEXT("local") + StringUtils::ToString(index); diff --git a/Source/Engine/Visject/ShaderGraph.h b/Source/Engine/Visject/ShaderGraph.h index 1ae7cab7f..38205f743 100644 --- a/Source/Engine/Visject/ShaderGraph.h +++ b/Source/Engine/Visject/ShaderGraph.h @@ -286,6 +286,7 @@ protected: SerializedMaterialParam findOrAddCubeTexture(const Guid& id); SerializedMaterialParam findOrAddSceneTexture(MaterialSceneTextures type); SerializedMaterialParam& findOrAddTextureGroupSampler(int32 index); + SerializedMaterialParam& findOrAddGlobalSDF(); static String getLocalName(int32 index); static String getParamName(int32 index); diff --git a/Source/Engine/Visject/ShaderGraphUtilities.cpp b/Source/Engine/Visject/ShaderGraphUtilities.cpp index 0944685e9..bfe86fcef 100644 --- a/Source/Engine/Visject/ShaderGraphUtilities.cpp +++ b/Source/Engine/Visject/ShaderGraphUtilities.cpp @@ -9,19 +9,19 @@ #include "Engine/Content/Content.h" #include "Engine/Engine/GameplayGlobals.h" #include "Engine/Graphics/Config.h" +#include "Engine/Renderer/GlobalSignDistanceFieldPass.h" void ShaderGraphUtilities::GenerateShaderConstantBuffer(TextWriterUnicode& writer, Array& parameters) { int32 constantsOffset = 0; int32 paddingIndex = 0; - for (int32 i = 0; i < parameters.Count(); i++) { auto& param = parameters[i]; - const Char* format = nullptr; int32 size; int32 alignment; + bool zeroRegister = true; switch (param.Type) { case MaterialParameterType::Bool: @@ -107,11 +107,15 @@ void ShaderGraphUtilities::GenerateShaderConstantBuffer(TextWriterUnicode& write alignment = 16; format = TEXT("float4 {0};"); break; - default: ; } break; } - default: ; + case MaterialParameterType::GlobalSDF: + zeroRegister = false; + size = sizeof(GlobalSignDistanceFieldPass::GlobalSDFData); + alignment = 16; + format = TEXT("GlobalSDFData {0};"); + break; } if (format) { @@ -126,7 +130,8 @@ void ShaderGraphUtilities::GenerateShaderConstantBuffer(TextWriterUnicode& write } } - param.RegisterIndex = 0; + if (zeroRegister) + param.RegisterIndex = 0; param.Offset = constantsOffset; writer.WriteLine(format, param.ShaderName); constantsOffset += size; @@ -139,7 +144,9 @@ const Char* ShaderGraphUtilities::GenerateShaderResources(TextWriterUnicode& wri for (int32 i = 0; i < parameters.Count(); i++) { auto& param = parameters[i]; - const Char* format; + const Char* format = nullptr; + bool zeroOffset = true; + int32 registers = 1; switch (param.Type) { case MaterialParameterType::NormalMap: @@ -158,16 +165,19 @@ const Char* ShaderGraphUtilities::GenerateShaderResources(TextWriterUnicode& wri case MaterialParameterType::GPUTextureVolume: format = TEXT("Texture3D {0} : register(t{1});"); break; - default: - format = nullptr; + case MaterialParameterType::GlobalSDF: + format = TEXT("Texture3D {0}_Tex[4] : register(t{1});"); + registers = 4; + zeroOffset = false; break; } if (format) { - param.Offset = 0; + if (zeroOffset) + param.Offset = 0; param.RegisterIndex = (byte)startRegister; writer.WriteLine(format, param.ShaderName, startRegister); - startRegister++; + startRegister += registers; if (param.RegisterIndex >= GPU_MAX_SR_BINDED) { return TEXT("Too many textures used. The maximum supported amount is " MACRO_TO_STR(GPU_MAX_SR_BINDED) " (including lightmaps and utility textures for lighting)."); diff --git a/Source/Shaders/GlobalSignDistanceField.hlsl b/Source/Shaders/GlobalSignDistanceField.hlsl index 83a98ae00..2e3f5ddd0 100644 --- a/Source/Shaders/GlobalSignDistanceField.hlsl +++ b/Source/Shaders/GlobalSignDistanceField.hlsl @@ -57,17 +57,15 @@ struct GlobalSDFHit float SampleGlobalSDF(const GlobalSDFData data, Texture3D tex[4], float3 worldPosition, uint minCascade = 0) { float distance = data.CascadePosDistance[3].w * 2.0f; + UNROLL for (uint cascade = minCascade; cascade < 4; cascade++) { float4 cascadePosDistance = data.CascadePosDistance[cascade]; float cascadeMaxDistance = cascadePosDistance.w * 2; float3 posInCascade = worldPosition - cascadePosDistance.xyz; float3 cascadeUV = posInCascade / cascadeMaxDistance + 0.5f; - if (any(cascadeUV < 0) || any(cascadeUV > 1)) - continue; - // TODO: sample mip first float cascadeDistance = tex[cascade].SampleLevel(SamplerLinearClamp, cascadeUV, 0); - if (cascadeDistance < 1.0f) + if (cascadeDistance < 1.0f && !any(cascadeUV < 0) && !any(cascadeUV > 1)) { distance = cascadeDistance * cascadeMaxDistance; break;