diff --git a/Source/Editor/Surface/Archetypes/Textures.cs b/Source/Editor/Surface/Archetypes/Textures.cs index 00c0a806d..3398b0988 100644 --- a/Source/Editor/Surface/Archetypes/Textures.cs +++ b/Source/Editor/Surface/Archetypes/Textures.cs @@ -368,11 +368,13 @@ namespace FlaxEditor.Surface.Archetypes 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 | NodeFlags.ParticleEmitterGraph, - Size = new Float2(200, 20), + Size = new Float2(200, 40), + DefaultValues = new object[] { 0 }, Elements = new[] { NodeElementArchetype.Factory.Output(0, "Distance", typeof(float), 0), NodeElementArchetype.Factory.Input(0, "World Position", true, typeof(Float3), 1), + NodeElementArchetype.Factory.Input(1, "Start Cascade", true, typeof(int), 2, 0), } }, new NodeArchetype @@ -382,11 +384,13 @@ namespace FlaxEditor.Surface.Archetypes Description = "Samples the Global SDF to get the gradient and distance to the closest surface (in world-space). Normalize gradient to get SDF surface normal vector. Requires models SDF to be generated and checking `Enable Global SDF` in Graphics Settings.", Flags = NodeFlags.MaterialGraph | NodeFlags.ParticleEmitterGraph, Size = new Float2(260, 40), + DefaultValues = new object[] { 0 }, Elements = new[] { NodeElementArchetype.Factory.Output(0, "Gradient", typeof(Float3), 0), NodeElementArchetype.Factory.Output(1, "Distance", typeof(float), 2), NodeElementArchetype.Factory.Input(0, "World Position", true, typeof(Float3), 1), + NodeElementArchetype.Factory.Input(1, "Start Cascade", true, typeof(int), 2, 0), } }, new NodeArchetype diff --git a/Source/Engine/Particles/Graph/GPU/ParticleEmitterGraph.GPU.Textures.cpp b/Source/Engine/Particles/Graph/GPU/ParticleEmitterGraph.GPU.Textures.cpp index bd8777f64..f05b09dac 100644 --- a/Source/Engine/Particles/Graph/GPU/ParticleEmitterGraph.GPU.Textures.cpp +++ b/Source/Engine/Particles/Graph/GPU/ParticleEmitterGraph.GPU.Textures.cpp @@ -311,10 +311,27 @@ void ParticleEmitterGPUGenerator::ProcessGroupTextures(Box* box, Node* node, Val { auto param = findOrAddGlobalSDF(); Value worldPosition = tryGetValue(node->GetBox(1), Value(VariantType::Float3, TEXT("input.WorldPosition.xyz"))).Cast(VariantType::Float3); - value = writeLocal(VariantType::Float, String::Format(TEXT("SampleGlobalSDF({0}, {0}_Tex, {1})"), param.ShaderName, worldPosition.Value), node); + Value startCascade = tryGetValue(node->GetBox(2), 0, Value::Zero).Cast(VariantType::Uint); + value = writeLocal(VariantType::Float, String::Format(TEXT("SampleGlobalSDF({0}, {0}_Tex, {0}_Mip, {1}, {2})"), param.ShaderName, worldPosition.Value, startCascade.Value), node); _includes.Add(TEXT("./Flax/GlobalSignDistanceField.hlsl")); break; } + // Sample Global SDF Gradient + case 15: + { + auto gradientBox = node->GetBox(0); + auto distanceBox = node->GetBox(2); + auto param = findOrAddGlobalSDF(); + Value worldPosition = tryGetValue(node->GetBox(1), Value(VariantType::Float3, TEXT("input.WorldPosition.xyz"))).Cast(VariantType::Float3); + Value startCascade = tryGetValue(node->GetBox(2), 0, Value::Zero).Cast(VariantType::Uint); + auto distance = writeLocal(VariantType::Float, node); + auto gradient = writeLocal(VariantType::Float3, String::Format(TEXT("SampleGlobalSDFGradient({0}, {0}_Tex, {0}_Mip, {1}, {2}, {3})"), param.ShaderName, worldPosition.Value, distance.Value, startCascade.Value), node); + _includes.Add(TEXT("./Flax/GlobalSignDistanceField.hlsl")); + gradientBox->Cache = gradient; + distanceBox->Cache = distance; + value = box == gradientBox ? gradient : distance; + break; + } default: break; } diff --git a/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.Textures.cpp b/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.Textures.cpp index d7b3bbb23..539900886 100644 --- a/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.Textures.cpp +++ b/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.Textures.cpp @@ -665,7 +665,8 @@ void MaterialGenerator::ProcessGroupTextures(Box* box, Node* node, Value& value) { auto param = findOrAddGlobalSDF(); Value worldPosition = tryGetValue(node->GetBox(1), Value(VariantType::Float3, TEXT("input.WorldPosition.xyz"))).Cast(VariantType::Float3); - value = writeLocal(VariantType::Float, String::Format(TEXT("SampleGlobalSDF({0}, {0}_Tex, {0}_Mip, {1})"), param.ShaderName, worldPosition.Value), node); + Value startCascade = tryGetValue(node->GetBox(2), 0, Value::Zero).Cast(VariantType::Uint); + value = writeLocal(VariantType::Float, String::Format(TEXT("SampleGlobalSDF({0}, {0}_Tex, {0}_Mip, {1}, {2})"), param.ShaderName, worldPosition.Value, startCascade.Value), node); _includes.Add(TEXT("./Flax/GlobalSignDistanceField.hlsl")); break; } @@ -676,8 +677,9 @@ void MaterialGenerator::ProcessGroupTextures(Box* box, Node* node, Value& value) auto distanceBox = node->GetBox(2); auto param = findOrAddGlobalSDF(); Value worldPosition = tryGetValue(node->GetBox(1), Value(VariantType::Float3, TEXT("input.WorldPosition.xyz"))).Cast(VariantType::Float3); + Value startCascade = tryGetValue(node->GetBox(2), 0, Value::Zero).Cast(VariantType::Uint); auto distance = writeLocal(VariantType::Float, node); - auto gradient = writeLocal(VariantType::Float3, String::Format(TEXT("SampleGlobalSDFGradient({0}, {0}_Tex, {0}_Mip, {1}, {2})"), param.ShaderName, worldPosition.Value, distance.Value), node); + auto gradient = writeLocal(VariantType::Float3, String::Format(TEXT("SampleGlobalSDFGradient({0}, {0}_Tex, {0}_Mip, {1}, {2}, {3})"), param.ShaderName, worldPosition.Value, distance.Value, startCascade.Value), node); _includes.Add(TEXT("./Flax/GlobalSignDistanceField.hlsl")); gradientBox->Cache = gradient; distanceBox->Cache = distance; diff --git a/Source/Shaders/GlobalSignDistanceField.hlsl b/Source/Shaders/GlobalSignDistanceField.hlsl index ab5d37372..577b9ebca 100644 --- a/Source/Shaders/GlobalSignDistanceField.hlsl +++ b/Source/Shaders/GlobalSignDistanceField.hlsl @@ -126,12 +126,13 @@ float SampleGlobalSDF(const GlobalSDFData data, Texture3D tex, floa } // Samples the Global SDF and returns the distance to the closest surface (in world units) at the given world location. -float SampleGlobalSDF(const GlobalSDFData data, Texture3D tex, Texture3D mip, float3 worldPosition) +float SampleGlobalSDF(const GlobalSDFData data, Texture3D tex, Texture3D mip, float3 worldPosition, uint startCascade = 0) { float distance = data.CascadePosDistance[3].w * 2.0f; if (distance <= 0.0f) return GLOBAL_SDF_WORLD_SIZE; - for (uint cascade = 0; cascade < data.CascadesCount; cascade++) + startCascade = min(startCascade, data.CascadesCount - 1); + for (uint cascade = startCascade; cascade < data.CascadesCount; cascade++) { float3 cascadeUV, textureUV; GetGlobalSDFCascadeUV(data, cascade, worldPosition, cascadeUV, textureUV); @@ -186,13 +187,14 @@ float3 SampleGlobalSDFGradient(const GlobalSDFData data, Texture3D } // Samples the Global SDF and returns the gradient vector (derivative) at the given world location. Normalize it to get normal vector. -float3 SampleGlobalSDFGradient(const GlobalSDFData data, Texture3D tex, Texture3D mip, float3 worldPosition, out float distance) +float3 SampleGlobalSDFGradient(const GlobalSDFData data, Texture3D tex, Texture3D mip, float3 worldPosition, out float distance, uint startCascade = 0) { float3 gradient = float3(0, 0.00001f, 0); distance = GLOBAL_SDF_WORLD_SIZE; if (data.CascadePosDistance[3].w <= 0.0f) return gradient; - for (uint cascade = 0; cascade < data.CascadesCount; cascade++) + startCascade = min(startCascade, data.CascadesCount - 1); + for (uint cascade = startCascade; cascade < data.CascadesCount; cascade++) { float3 cascadeUV, textureUV; GetGlobalSDFCascadeUV(data, cascade, worldPosition, cascadeUV, textureUV);