From 9062c04ef0c7669ff21f55f7e7f15818c9a73577 Mon Sep 17 00:00:00 2001 From: ExMatics HydrogenC <33123710+HydrogenC@users.noreply.github.com> Date: Tue, 18 Jun 2024 21:25:12 +0800 Subject: [PATCH] Complete sdf reflections --- .../Features/ForwardShading.hlsl | 33 ++------ .../Features/SDFReflections.hlsl | 39 ++++++++++ .../Materials/ForwardMaterialShader.cpp | 2 + .../Materials/MaterialShaderFeatures.cpp | 75 ++++++++++++++++--- .../Materials/MaterialShaderFeatures.h | 21 ++++++ .../Renderer/GI/GlobalSurfaceAtlasPass.cpp | 11 +++ .../Renderer/GI/GlobalSurfaceAtlasPass.h | 8 ++ .../MaterialGenerator/MaterialGenerator.cpp | 2 + Source/Shaders/SSR.shader | 4 +- 9 files changed, 154 insertions(+), 41 deletions(-) create mode 100644 Content/Editor/MaterialTemplates/Features/SDFReflections.hlsl diff --git a/Content/Editor/MaterialTemplates/Features/ForwardShading.hlsl b/Content/Editor/MaterialTemplates/Features/ForwardShading.hlsl index 0df9abe9e..62e98ed1a 100644 --- a/Content/Editor/MaterialTemplates/Features/ForwardShading.hlsl +++ b/Content/Editor/MaterialTemplates/Features/ForwardShading.hlsl @@ -9,10 +9,6 @@ #define MATERIAL_REFLECTIONS_SSR 1 #if MATERIAL_REFLECTIONS == MATERIAL_REFLECTIONS_SSR #include "./Flax/SSR.hlsl" -#if USE_GLOBAL_SURFACE_ATLAS -#include "./Flax/GlobalSignDistanceField.hlsl" -#include "./Flax/GI/GlobalSurfaceAtlas.hlsl" -#endif #endif #endif #include "./Flax/Lighting.hlsl" @@ -31,15 +27,6 @@ LightData LocalLights[MAX_LOCAL_LIGHTS]; TextureCube EnvProbe : register(t__SRV__); TextureCube SkyLightTexture : register(t__SRV__); Texture2DArray DirectionalLightShadowMap : register(t__SRV__); -#if USE_GLOBAL_SURFACE_ATLAS -Texture3D GlobalSDFTex : register(t__SRV__); -Texture3D GlobalSDFMip : register(t__SRV__); -ByteAddressBuffer GlobalSurfaceAtlasChunks : register(t__SRV__); -ByteAddressBuffer RWGlobalSurfaceAtlasCulledObjects : register(t__SRV__); -Buffer GlobalSurfaceAtlasObjects : register(t__SRV__); -Texture2D GlobalSurfaceAtlasDepth : register(t__SRV__); -Texture2D GlobalSurfaceAtlasTex : register(t__SRV__); -#endif @4// Forward Shading: Utilities DECLARE_LIGHTSHADOWDATA_ACCESS(DirectionalLightShadow); @5// Forward Shading: Shaders @@ -82,7 +69,7 @@ void PS_Forward( gBuffer.Color = material.Color; gBuffer.Specular = material.Specular; gBuffer.AO = material.AO; - gBuffer.ViewPos = mul(float4(materialInput.WorldPosition, 1), ViewMatrix).xyz; + gBuffer.ViewPos = ViewPos; #if MATERIAL_SHADING_MODEL == SHADING_MODEL_SUBSURFACE gBuffer.CustomData = float4(material.SubsurfaceColor, material.Opacity); #elif MATERIAL_SHADING_MODEL == SHADING_MODEL_FOLIAGE @@ -148,21 +135,12 @@ void PS_Forward( if (hit.z < 0.9f) { // Don't use temporal effect in forward pass - float3 reflectWS = ScreenSpaceReflectionDirection(screenUV, gBuffer, gBufferData.ViewPos); + float3 reflectWS = ScreenSpaceReflectionDirection(screenUV, gBuffer, ViewPos); + float4 surfaceAtlas; - GlobalSDFTrace sdfTrace; - float maxDistance = 100000; - float selfOcclusionBias = GlobalSDF.CascadeVoxelSize[0]; - sdfTrace.Init(gBuffer.WorldPos + gBuffer.Normal * selfOcclusionBias, reflectWS, 0.0f, maxDistance); - GlobalSDFHit sdfHit = RayTraceGlobalSDF(GlobalSDF, GlobalSDFTex, GlobalSDFMip, sdfTrace); - if (sdfHit.IsHit()) - { - float3 hitPosition = sdfHit.GetHitPosition(sdfTrace); - float surfaceThreshold = GetGlobalSurfaceAtlasThreshold(GlobalSDF, sdfHit); - float4 surfaceAtlas = SampleGlobalSurfaceAtlas(GlobalSurfaceAtlas, GlobalSurfaceAtlasChunks, RWGlobalSurfaceAtlasCulledObjects, GlobalSurfaceAtlasObjects, GlobalSurfaceAtlasDepth, GlobalSurfaceAtlasTex, hitPosition, -reflectWS, surfaceThreshold); - + if(TraceSDFSoftwareReflections(gBuffer, reflectWS, surfaceAtlas)){ float3 screenColor = sceneColorTexture.SampleLevel(SamplerPointClamp, hit.xy, 0).rgb; - reflections = lerp(surfaceAtlas, float4(screenColor, 1), hit.z); + reflections = lerp(2 * surfaceAtlas, float4(screenColor, 1), hit.z); } } @@ -174,6 +152,7 @@ void PS_Forward( // Add lighting (apply ambient occlusion) output.rgb += light.rgb * gBuffer.AO; + output = #endif diff --git a/Content/Editor/MaterialTemplates/Features/SDFReflections.hlsl b/Content/Editor/MaterialTemplates/Features/SDFReflections.hlsl new file mode 100644 index 000000000..be3e6c831 --- /dev/null +++ b/Content/Editor/MaterialTemplates/Features/SDFReflections.hlsl @@ -0,0 +1,39 @@ +// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved. + +@0// SDF Reflections: Defines +#define USE_GLOBAL_SURFACE_ATLAS 1 +@1// SDF Reflections: Includes +#include "./Flax/GlobalSignDistanceField.hlsl" +#include "./Flax/GI/GlobalSurfaceAtlas.hlsl" +@2// SDF Reflections: Constants +GlobalSDFData GlobalSDF; +GlobalSurfaceAtlasData GlobalSurfaceAtlas; +@3// SDF Reflections: Resources +Texture3D GlobalSDFTex : register(t__SRV__); +Texture3D GlobalSDFMip : register(t__SRV__); +ByteAddressBuffer GlobalSurfaceAtlasChunks : register(t__SRV__); +ByteAddressBuffer RWGlobalSurfaceAtlasCulledObjects : register(t__SRV__); +Buffer GlobalSurfaceAtlasObjects : register(t__SRV__); +Texture2D GlobalSurfaceAtlasDepth : register(t__SRV__); +Texture2D GlobalSurfaceAtlasTex : register(t__SRV__); +@4// SDF Reflections: Utilities +bool TraceSDFSoftwareReflections(GBufferSample gBuffer, float3 reflectWS, out float4 surfaceAtlas) +{ + GlobalSDFTrace sdfTrace; + float maxDistance = 100000; + float selfOcclusionBias = GlobalSDF.CascadeVoxelSize[0]; + sdfTrace.Init(gBuffer.WorldPos + gBuffer.Normal * selfOcclusionBias, reflectWS, 0.0f, maxDistance); + GlobalSDFHit sdfHit = RayTraceGlobalSDF(GlobalSDF, GlobalSDFTex, GlobalSDFMip, sdfTrace); + if (sdfHit.IsHit()) + { + float3 hitPosition = sdfHit.GetHitPosition(sdfTrace); + float surfaceThreshold = GetGlobalSurfaceAtlasThreshold(GlobalSDF, sdfHit); + surfaceAtlas = SampleGlobalSurfaceAtlas(GlobalSurfaceAtlas, GlobalSurfaceAtlasChunks, RWGlobalSurfaceAtlasCulledObjects, GlobalSurfaceAtlasObjects, GlobalSurfaceAtlasDepth, GlobalSurfaceAtlasTex, hitPosition, -reflectWS, surfaceThreshold); + + return true; + } + + return false; +} + +@5// SDF Reflections: Shaders diff --git a/Source/Engine/Graphics/Materials/ForwardMaterialShader.cpp b/Source/Engine/Graphics/Materials/ForwardMaterialShader.cpp index 31c2f8166..2b4237190 100644 --- a/Source/Engine/Graphics/Materials/ForwardMaterialShader.cpp +++ b/Source/Engine/Graphics/Materials/ForwardMaterialShader.cpp @@ -53,6 +53,8 @@ void ForwardMaterialShader::Bind(BindParameters& params) // Setup features if ((_info.FeaturesFlags & MaterialFeaturesFlags::GlobalIllumination) != MaterialFeaturesFlags::None) GlobalIlluminationFeature::Bind(params, cb, srv); + if ((_info.FeaturesFlags & MaterialFeaturesFlags::ScreenSpaceReflections) != MaterialFeaturesFlags::None) + SDFReflectionsFeature::Bind(params, cb, srv); ForwardShadingFeature::Bind(params, cb, srv); // Setup parameters diff --git a/Source/Engine/Graphics/Materials/MaterialShaderFeatures.cpp b/Source/Engine/Graphics/Materials/MaterialShaderFeatures.cpp index d385ec24f..5fa33b10f 100644 --- a/Source/Engine/Graphics/Materials/MaterialShaderFeatures.cpp +++ b/Source/Engine/Graphics/Materials/MaterialShaderFeatures.cpp @@ -100,15 +100,6 @@ void ForwardShadingFeature::Bind(MaterialShader::BindParameters& params, SpanUnBindSR(envProbeShaderRegisterIndex); } - // Bind sdf resources if using software reflections - if (!GlobalSignDistanceFieldPass::Instance()->Render(params.RenderContext, params.GPUContext, bindingDataSDF) && - !GlobalSurfaceAtlasPass::Instance()->Render(params.RenderContext, params.GPUContext, bindingDataSurfaceAtlas)) - { - useGlobalSurfaceAtlas = true; - data.GlobalSDF = bindingDataSDF.Constants; - data.GlobalSurfaceAtlas = bindingDataSurfaceAtlas.Constants; - } - // Set local lights data.LocalLightsCount = 0; const BoundingSphere objectBounds(drawCall.ObjectPosition, drawCall.ObjectRadius); @@ -143,13 +134,13 @@ bool LightmapFeature::Bind(MaterialShader::BindParameters& params, Span& c const bool useLightmap = EnumHasAnyFlags(params.RenderContext.View.Flags, ViewFlags::GI) #if USE_EDITOR - && EnableLightmapsUsage + && EnableLightmapsUsage #endif - && drawCall.Surface.Lightmap != nullptr; + && drawCall.Surface.Lightmap != nullptr; if (useLightmap) { // Bind lightmap textures - GPUTexture *lightmap0, *lightmap1, *lightmap2; + GPUTexture* lightmap0, * lightmap1, * lightmap2; drawCall.Features.Lightmap->GetTextures(&lightmap0, &lightmap1, &lightmap2); params.GPUContext->BindSR(srv + 0, lightmap0); params.GPUContext->BindSR(srv + 1, lightmap1); @@ -207,6 +198,61 @@ bool GlobalIlluminationFeature::Bind(MaterialShader::BindParameters& params, Spa return useGI; } +bool SDFReflectionsFeature::Bind(MaterialShader::BindParameters& params, Span& cb, int32& srv) +{ + auto& data = *(Data*)cb.Get(); + ASSERT_LOW_LAYER(cb.Length() >= sizeof(Data)); + + bool useSDFReflections = false; + if (EnumHasAnyFlags(params.RenderContext.View.Flags, ViewFlags::Reflections)) + { + switch (params.RenderContext.List->Settings.ScreenSpaceReflections.TraceMode) + { + case ReflectionsTraceMode::SoftwareTracing: + { + GlobalSignDistanceFieldPass::BindingData bindingDataSDF; + GlobalSurfaceAtlasPass::BindingData bindingDataSurfaceAtlas; + + if (!GlobalSignDistanceFieldPass::Instance()->Get(params.RenderContext.Buffers, bindingDataSDF) && + !GlobalSurfaceAtlasPass::Instance()->Get(params.RenderContext.Buffers, bindingDataSurfaceAtlas)) + { + useSDFReflections = true; + + // Bind DDGI data + data.GlobalSDF = bindingDataSDF.Constants; + data.GlobalSurfaceAtlas = bindingDataSurfaceAtlas.Constants; + + params.GPUContext->BindSR(srv + 0, bindingDataSDF.Texture ? bindingDataSDF.Texture->ViewVolume() : nullptr); + params.GPUContext->BindSR(srv + 1, bindingDataSDF.TextureMip ? bindingDataSDF.TextureMip->ViewVolume() : nullptr); + params.GPUContext->BindSR(srv + 2, bindingDataSurfaceAtlas.Chunks ? bindingDataSurfaceAtlas.Chunks->View() : nullptr); + params.GPUContext->BindSR(srv + 3, bindingDataSurfaceAtlas.CulledObjects ? bindingDataSurfaceAtlas.CulledObjects->View() : nullptr); + params.GPUContext->BindSR(srv + 4, bindingDataSurfaceAtlas.Objects ? bindingDataSurfaceAtlas.Objects->View() : nullptr); + params.GPUContext->BindSR(srv + 5, bindingDataSurfaceAtlas.AtlasDepth->View()); + params.GPUContext->BindSR(srv + 6, bindingDataSurfaceAtlas.AtlasLighting->View()); + } + break; + } + } + } + + if (!useSDFReflections) + { + data.GlobalSDF.CascadesCount = 0; + // Unbind SRVs to prevent issues + params.GPUContext->UnBindSR(srv + 0); + params.GPUContext->UnBindSR(srv + 1); + params.GPUContext->UnBindSR(srv + 2); + params.GPUContext->UnBindSR(srv + 3); + params.GPUContext->UnBindSR(srv + 4); + params.GPUContext->UnBindSR(srv + 5); + params.GPUContext->UnBindSR(srv + 6); + } + + cb = Span(cb.Get() + sizeof(Data), cb.Length() - sizeof(Data)); + srv += SRVs; + return useSDFReflections; +} + #if USE_EDITOR void ForwardShadingFeature::Generate(GeneratorData& data) @@ -234,6 +280,11 @@ void GlobalIlluminationFeature::Generate(GeneratorData& data) data.Template = TEXT("Features/GlobalIllumination.hlsl"); } +void SDFReflectionsFeature::Generate(GeneratorData& data) +{ + data.Template = TEXT("Features/SDFReflections.hlsl"); +} + void DistortionFeature::Generate(GeneratorData& data) { data.Template = TEXT("Features/Distortion.hlsl"); diff --git a/Source/Engine/Graphics/Materials/MaterialShaderFeatures.h b/Source/Engine/Graphics/Materials/MaterialShaderFeatures.h index 0df2e9a2e..5b85353a0 100644 --- a/Source/Engine/Graphics/Materials/MaterialShaderFeatures.h +++ b/Source/Engine/Graphics/Materials/MaterialShaderFeatures.h @@ -6,6 +6,8 @@ #include "Engine/Core/Math/Rectangle.h" #include "Engine/Core/Types/Span.h" #include "Engine/Renderer/GI/DynamicDiffuseGlobalIllumination.h" +#include "Engine/Renderer/GlobalSignDistanceFieldPass.h" +#include "Engine/Renderer/GI/GlobalSurfaceAtlasPass.h" // Material shader features are plugin-based functionalities that are reusable between different material domains. struct MaterialShaderFeature @@ -91,6 +93,25 @@ struct GlobalIlluminationFeature : MaterialShaderFeature #endif }; +// Material shader feature that adds SDF Reflections feature (software reflections). +struct SDFReflectionsFeature : MaterialShaderFeature +{ + enum { SRVs = 7 }; + + PACK_STRUCT(struct Data + { + GlobalSignDistanceFieldPass::ConstantsData GlobalSDF; + GlobalSurfaceAtlasPass::ConstantsData GlobalSurfaceAtlas; + }); + + + + static bool Bind(MaterialShader::BindParameters& params, Span& cb, int32& srv); +#if USE_EDITOR + static void Generate(GeneratorData& data); +#endif +}; + // Material shader feature that adds distortion vectors rendering pass. struct DistortionFeature : MaterialShaderFeature { diff --git a/Source/Engine/Renderer/GI/GlobalSurfaceAtlasPass.cpp b/Source/Engine/Renderer/GI/GlobalSurfaceAtlasPass.cpp index fb0faa27a..f2bc3169d 100644 --- a/Source/Engine/Renderer/GI/GlobalSurfaceAtlasPass.cpp +++ b/Source/Engine/Renderer/GI/GlobalSurfaceAtlasPass.cpp @@ -360,6 +360,17 @@ void GlobalSurfaceAtlasPass::Dispose() _shader = nullptr; } +bool GlobalSurfaceAtlasPass::Get(const RenderBuffers* buffers, BindingData& result) +{ + auto* surfaceAtlasData = buffers ? buffers->FindCustomBuffer(TEXT("GlobalSurfaceAtlas")) : nullptr; + if (surfaceAtlasData && surfaceAtlasData->LastFrameUsed + 1 >= Engine::FrameCount) // Allow to use Surface Atlas from the previous frame (not used currently) + { + result = surfaceAtlasData->Result; + return false; + } + return true; +} + bool GlobalSurfaceAtlasPass::Render(RenderContext& renderContext, GPUContext* context, BindingData& result) { // Skip if not supported diff --git a/Source/Engine/Renderer/GI/GlobalSurfaceAtlasPass.h b/Source/Engine/Renderer/GI/GlobalSurfaceAtlasPass.h index 443b3a401..45d144767 100644 --- a/Source/Engine/Renderer/GI/GlobalSurfaceAtlasPass.h +++ b/Source/Engine/Renderer/GI/GlobalSurfaceAtlasPass.h @@ -65,6 +65,14 @@ private: void* _currentActorObject; public: + /// + /// Gets the Global Surface Atlas (only if enabled in Graphics Settings). + /// + /// The rendering context buffers. + /// The result Global Surface Atlas data for binding to the shaders. + /// True if there is no valid Global Surface Atlas rendered during this frame, otherwise false. + bool Get(const RenderBuffers* buffers, BindingData& result); + /// /// Renders the Global Surface Atlas. /// diff --git a/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.cpp b/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.cpp index 8cacddf51..87e73871f 100644 --- a/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.cpp +++ b/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.cpp @@ -199,6 +199,8 @@ bool MaterialGenerator::Generate(WriteStream& source, MaterialInfo& materialInfo ADD_FEATURE(DistortionFeature); if (materialInfo.BlendMode != MaterialBlendMode::Opaque && EnumHasAnyFlags(materialInfo.FeaturesFlags, MaterialFeaturesFlags::GlobalIllumination)) ADD_FEATURE(GlobalIlluminationFeature); + if (materialInfo.BlendMode != MaterialBlendMode::Opaque && EnumHasAnyFlags(materialInfo.FeaturesFlags, MaterialFeaturesFlags::ScreenSpaceReflections)) + ADD_FEATURE(SDFReflectionsFeature); if (materialInfo.BlendMode != MaterialBlendMode::Opaque) ADD_FEATURE(ForwardShadingFeature); break; diff --git a/Source/Shaders/SSR.shader b/Source/Shaders/SSR.shader index ca177ff09..de9cb891c 100644 --- a/Source/Shaders/SSR.shader +++ b/Source/Shaders/SSR.shader @@ -150,8 +150,8 @@ float4 PS_RayTracePass(Quad_VS2PS input) : SV_Target0 float surfaceThreshold = GetGlobalSurfaceAtlasThreshold(GlobalSDF, sdfHit); float4 surfaceAtlas = SampleGlobalSurfaceAtlas(GlobalSurfaceAtlas, GlobalSurfaceAtlasChunks, RWGlobalSurfaceAtlasCulledObjects, GlobalSurfaceAtlasObjects, GlobalSurfaceAtlasDepth, GlobalSurfaceAtlasTex, hitPosition, -reflectWS, surfaceThreshold); // Now the sdf reflection part is significantly darker than the screen space part - // TODO: Maybe multiply surfaceAtlas by a constant to make it brighter - result = lerp(surfaceAtlas, float4(result.rgb, 1), result.a); + // TODO: Maybe multiply surfaceAtlas by a constant to make it brighter, adding 2* looks fine + result = lerp(2 * surfaceAtlas, float4(result.rgb, 1), result.a); } #endif