From af886ca483b7742ec229dd176b2eeba4333f3250 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Mon, 22 Jun 2026 23:39:04 +0200 Subject: [PATCH] Update `Common.hlsl` shader library --- .../MaterialGenerator.Material.cpp | 2 +- Source/Shaders/AtmosphereFog.hlsl | 20 ++++++ Source/Shaders/Common.hlsl | 62 ++++++------------- Source/Shaders/GBufferCommon.hlsl | 22 +++++++ Source/Shaders/GI/DDGI.shader | 1 + Source/Shaders/GUI.shader | 15 +---- Source/Shaders/Lights.shader | 8 +-- Source/Shaders/Reflections.shader | 4 +- Source/Shaders/SSR.hlsl | 24 +------ Source/Shaders/Shadows.shader | 4 +- Source/Shaders/Sky.shader | 2 +- 11 files changed, 74 insertions(+), 90 deletions(-) diff --git a/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.Material.cpp b/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.Material.cpp index 73e4ee31a..c26789514 100644 --- a/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.Material.cpp +++ b/Source/Engine/Tools/MaterialGenerator/MaterialGenerator.Material.cpp @@ -56,7 +56,7 @@ void MaterialGenerator::ProcessGroupMaterial(Box* box, Node* node, Value& value) { // Transform world position into main viewport texcoord space Value clipPosition = writeLocal(VariantType::Float4, TEXT("PROJECT_POINT(float4(input.WorldPosition.xyz, 1), MainViewProjectionMatrix)"), node); - Value uvPos = writeLocal(VariantType::Float2, String::Format(TEXT("(({0}.xy / {0}.w) * float2(0.5, -0.5) + float2(0.5, 0.5))"), clipPosition.Value), node); + Value uvPos = writeLocal(VariantType::Float2, String::Format(TEXT("ProjectClipToUV({0}.xy / {0}.w)"), clipPosition.Value), node); // Position if (box->ID == 0) diff --git a/Source/Shaders/AtmosphereFog.hlsl b/Source/Shaders/AtmosphereFog.hlsl index 527260d5a..635f82ece 100644 --- a/Source/Shaders/AtmosphereFog.hlsl +++ b/Source/Shaders/AtmosphereFog.hlsl @@ -22,6 +22,26 @@ #include "./Flax/Atmosphere.hlsl" +// Structure that contains information about atmosphere fog +struct AtmosphericFogData +{ + float AtmosphericFogDensityScale; + float AtmosphericFogSunDiscScale; + float AtmosphericFogDistanceScale; + float AtmosphericFogGroundOffset; + + float AtmosphericFogAltitudeScale; + float AtmosphericFogStartDistance; + float AtmosphericFogPower; + float AtmosphericFogDistanceOffset; + + float3 AtmosphericFogSunDirection; + float AtmosphericFogSunPower; + + float3 AtmosphericFogSunColor; + float AtmosphericFogDensityOffset; +}; + static const float HeightOffset = 0.01f; // inscattered light along ray x+tv, when sun in direction s (=S[L]-T(x,x0)S[L]|x0) diff --git a/Source/Shaders/Common.hlsl b/Source/Shaders/Common.hlsl index 3360f0380..e8ad9a586 100644 --- a/Source/Shaders/Common.hlsl +++ b/Source/Shaders/Common.hlsl @@ -181,48 +181,6 @@ float4 LoadTextureWGSL(Texture2D tex, float2 uv) #define PI 3.1415926535897932 #define UNITS_TO_METERS_SCALE 0.01f -// Structure that contains information about GBuffer -struct GBufferData -{ - // If reverse Z enabled: - // x-1/Projection[0,0], y-1/Projection[1,1], z-(-Near / (Far - Near)), w-((Far * Near) / (Far - Near) / Far) - // Otherwise: - // x-1/Projection[0,0], y-1/Projection[1,1], z-(Far / (Far - Near)), w-(-(Far * Near) / (Far - Near) / Far) - float4 ViewInfo; - float4 ScreenSize; // x-Width, y-Height, z-1/Width, w-1/Height - float3 ViewPos; // view position (in world space) - float ViewFar; // view far plane distance (in world space) - float4x4 InvViewMatrix; // inverse view matrix (4 rows by 4 columns) - float4x4 InvProjectionMatrix; // inverse projection matrix (4 rows by 4 columns) -}; - -#ifdef PLATFORM_ANDROID -// #AdrenoVK_CB_STRUCT_MEMBER_ACCESS_BUG -#define DECLARE_GBUFFERDATA_ACCESS(uniformName) GBufferData Get##uniformName##Data() { GBufferData tmp; tmp.ViewInfo = uniformName.ViewInfo; tmp.ScreenSize = uniformName.ScreenSize; tmp.ViewPos = uniformName.ViewPos; tmp.ViewFar = uniformName.ViewFar; tmp.InvViewMatrix = uniformName.InvViewMatrix; tmp.InvProjectionMatrix = uniformName.InvProjectionMatrix; return tmp; } -#else -#define DECLARE_GBUFFERDATA_ACCESS(uniformName) GBufferData Get##uniformName##Data() { return uniformName; } -#endif - -// Structure that contains information about atmosphere fog -struct AtmosphericFogData -{ - float AtmosphericFogDensityScale; - float AtmosphericFogSunDiscScale; - float AtmosphericFogDistanceScale; - float AtmosphericFogGroundOffset; - - float AtmosphericFogAltitudeScale; - float AtmosphericFogStartDistance; - float AtmosphericFogPower; - float AtmosphericFogDistanceOffset; - - float3 AtmosphericFogSunDirection; - float AtmosphericFogSunPower; - - float3 AtmosphericFogSunColor; - float AtmosphericFogDensityOffset; -}; - struct Quad_VS2PS { float4 Position : SV_Position; @@ -277,4 +235,24 @@ float4x4 ToMatrix4x4(float4x3 m) return float4x4(float4(m[0].xyz, 0.0f), float4(m[1].xyz, 0.0f), float4(m[2].xyz, 0.0f), float4(m._m30, m._m31, m._m32, 1.0f)); } +// Maps clip-space position into screen-UV space. 1:-1 to 0:1 +float2 ProjectClipToUV(float2 clipPos) +{ + return clipPos * float2(0.5, -0.5) + float2(0.5, 0.5); +} + +// Projects world-space position into clip-space space. (-1:1 from bottom/left to up/right) +float3 ProjectWorldToClip(float3 wsPos, float4x4 viewProjectionMatrix) +{ + float4 clipPos = PROJECT_POINT(float4(wsPos, 1), viewProjectionMatrix); + return clipPos.xyz / clipPos.w; +} + +// Projects world-space position into screen-UV space. (0:1 from top/left to bottom/right) +float3 ProjectWorldToUV(float3 wsPos, float4x4 viewProjectionMatrix) +{ + float3 clipPos = ProjectWorldToClip(wsPos, viewProjectionMatrix); + return float3(ProjectClipToUV(clipPos.xy), clipPos.z); +} + #endif diff --git a/Source/Shaders/GBufferCommon.hlsl b/Source/Shaders/GBufferCommon.hlsl index 678168220..355705881 100644 --- a/Source/Shaders/GBufferCommon.hlsl +++ b/Source/Shaders/GBufferCommon.hlsl @@ -5,6 +5,28 @@ #include "./Flax/Common.hlsl" +// Structure that contains information about GBuffer +struct GBufferData +{ + // If reverse Z enabled: + // x-1/Projection[0,0], y-1/Projection[1,1], z-(-Near / (Far - Near)), w-((Far * Near) / (Far - Near) / Far) + // Otherwise: + // x-1/Projection[0,0], y-1/Projection[1,1], z-(Far / (Far - Near)), w-(-(Far * Near) / (Far - Near) / Far) + float4 ViewInfo; + float4 ScreenSize; // x-Width, y-Height, z-1/Width, w-1/Height + float3 ViewPos; // view position (in world space) + float ViewFar; // view far plane distance (in world space) + float4x4 InvViewMatrix; // inverse view matrix (4 rows by 4 columns) + float4x4 InvProjectionMatrix; // inverse projection matrix (4 rows by 4 columns) +}; + +#ifdef PLATFORM_ANDROID +// #AdrenoVK_CB_STRUCT_MEMBER_ACCESS_BUG +#define DECLARE_GBUFFERDATA_ACCESS(uniformName) GBufferData Get##uniformName##Data() { GBufferData tmp; tmp.ViewInfo = uniformName.ViewInfo; tmp.ScreenSize = uniformName.ScreenSize; tmp.ViewPos = uniformName.ViewPos; tmp.ViewFar = uniformName.ViewFar; tmp.InvViewMatrix = uniformName.InvViewMatrix; tmp.InvProjectionMatrix = uniformName.InvProjectionMatrix; return tmp; } +#else +#define DECLARE_GBUFFERDATA_ACCESS(uniformName) GBufferData Get##uniformName##Data() { return uniformName; } +#endif + // GBuffer sample data structure struct GBufferSample { diff --git a/Source/Shaders/GI/DDGI.shader b/Source/Shaders/GI/DDGI.shader index 79a395104..6c4e65572 100644 --- a/Source/Shaders/GI/DDGI.shader +++ b/Source/Shaders/GI/DDGI.shader @@ -16,6 +16,7 @@ #include "./Flax/Common.hlsl" #include "./Flax/Math.hlsl" #include "./Flax/Noise.hlsl" +#include "./Flax/GBufferCommon.hlsl" #include "./Flax/Quaternion.hlsl" #include "./Flax/MonteCarlo.hlsl" #include "./Flax/GlobalSignDistanceField.hlsl" diff --git a/Source/Shaders/GUI.shader b/Source/Shaders/GUI.shader index 35a79210d..4ccdd5139 100644 --- a/Source/Shaders/GUI.shader +++ b/Source/Shaders/GUI.shader @@ -115,21 +115,12 @@ float4 GetSample(float weight, float offset, float2 uv) + Image.Sample(SamplerLinearClamp, uv - uvOffset) * weight; } -// 1:-1 to 0:1 -float2 ClipToUv(float2 clipPos) -{ - return clipPos * float2(0.5, -0.5) + float2(0.5, 0.5); -} - META_PS(true, FEATURE_LEVEL_ES2) float4 PS_Downscale(Quad_VS2PS input) : SV_Target0 { - float2 boundsPos = input.TexCoord * Bounds.zw + Bounds.xy; - - float4 clipPos = PROJECT_POINT(float4(boundsPos, DEPTH_RANGE_MIN, 1), ViewProjection); - clipPos.xy /= clipPos.w; - - float2 uvPos = ClipToUv(clipPos.xy); + float2 boundsPos = input.TexCoord * Bounds.zw + Bounds.xy; + float3 clipPos = ProjectWorldToClip(float3(boundsPos, DEPTH_RANGE_MIN), ViewProjection); + float2 uvPos = ProjectClipToUV(clipPos.xy); // TODO: use 4-tap box blur to reduce aliasing when downscaling diff --git a/Source/Shaders/Lights.shader b/Source/Shaders/Lights.shader index e10e3c574..a0c765d8f 100644 --- a/Source/Shaders/Lights.shader +++ b/Source/Shaders/Lights.shader @@ -80,10 +80,8 @@ void PS_LocalLight(Model_VS2PS input, out float4 output : SV_Target0) { output = 0; - // Obtain UVs corresponding to the current pixel - float2 uv = (input.ScreenPos.xy / input.ScreenPos.w) * float2(0.5, -0.5) + float2(0.5, 0.5); - // Sample GBuffer + float2 uv = ProjectClipToUV(input.ScreenPos.xy / input.ScreenPos.w); GBufferData gBufferData = GetGBufferData(); GBufferSample gBuffer = SampleGBuffer(gBufferData, uv); @@ -117,10 +115,8 @@ float4 PS_Sky(Model_VS2PS input) : SV_Target0 { float4 output = 0; - // Obtain UVs corresponding to the current pixel - float2 uv = (input.ScreenPos.xy / input.ScreenPos.w) * float2(0.5, -0.5) + float2(0.5, 0.5); - // Sample GBuffer + float2 uv = ProjectClipToUV(input.ScreenPos.xy / input.ScreenPos.w); GBufferData gBufferData = GetGBufferData(); GBufferSample gBuffer = SampleGBuffer(gBufferData, uv); diff --git a/Source/Shaders/Reflections.shader b/Source/Shaders/Reflections.shader index 5a06853b8..d195efeb7 100644 --- a/Source/Shaders/Reflections.shader +++ b/Source/Shaders/Reflections.shader @@ -40,10 +40,8 @@ Model_VS2PS VS_Model(ModelInput_PosOnly input) META_PS(true, FEATURE_LEVEL_ES2) float4 PS_EnvProbe(Model_VS2PS input) : SV_Target0 { - // Obtain UVs corresponding to the current pixel - float2 uv = (input.ScreenPos.xy / input.ScreenPos.w) * float2(0.5, -0.5) + float2(0.5, 0.5); - // Sample GBuffer + float2 uv = ProjectClipToUV(input.ScreenPos.xy / input.ScreenPos.w); GBufferData gBufferData = GetGBufferData(); GBufferSample gBuffer = SampleGBuffer(gBufferData, uv); diff --git a/Source/Shaders/SSR.hlsl b/Source/Shaders/SSR.hlsl index bc934b1bf..e504b9655 100644 --- a/Source/Shaders/SSR.hlsl +++ b/Source/Shaders/SSR.hlsl @@ -12,26 +12,6 @@ #include "./FlaxThirdParty/FidelityFX/ffx_sssr.h" #endif -// 1:-1 to 0:1 -float2 ClipToUv(float2 clipPos) -{ - return clipPos * float2(0.5, -0.5) + float2(0.5, 0.5); -} - -// go into clip space (-1:1 from bottom/left to up/right) -float3 ProjectWorldToClip(float3 wsPos, float4x4 viewProjectionMatrix) -{ - float4 clipPos = PROJECT_POINT(float4(wsPos, 1), viewProjectionMatrix); - return clipPos.xyz / clipPos.w; -} - -// go into UV space. (0:1 from top/left to bottom/right) -float3 ProjectWorldToUv(float3 wsPos, float4x4 viewProjectionMatrix) -{ - float3 clipPos = ProjectWorldToClip(wsPos, viewProjectionMatrix); - return float3(ClipToUv(clipPos.xy), clipPos.z); -} - float3 TangentToWorld(float3 N, float4 H) { float3 upVector = abs(N.z) < 0.999 ? float3(0.0, 0.0, 1.0) : float3(1.0, 0.0, 0.0); @@ -88,8 +68,8 @@ float3 TraceScreenSpaceReflection( worldAntiSelfOcclusionBias *= 10.0f; // Higher bias for HZB trace to reduce artifacts #endif float3 startWS = gBuffer.WorldPos + gBuffer.Normal * worldAntiSelfOcclusionBias; - float3 startUV = ProjectWorldToUv(startWS, viewProjectionMatrix); - float3 endUV = ProjectWorldToUv(startWS + reflectWS, viewProjectionMatrix); + float3 startUV = ProjectWorldToUV(startWS, viewProjectionMatrix); + float3 endUV = ProjectWorldToUV(startWS + reflectWS, viewProjectionMatrix); float3 rayUV = endUV - startUV; float2 rayUVAbs = abs(rayUV.xy); rayUV *= stepSize / max(rayUVAbs.x, rayUVAbs.y); diff --git a/Source/Shaders/Shadows.shader b/Source/Shaders/Shadows.shader index d96192381..7f5b81511 100644 --- a/Source/Shaders/Shadows.shader +++ b/Source/Shaders/Shadows.shader @@ -140,10 +140,8 @@ META_PERMUTATION_3(SHADOWS_QUALITY=2,CONTACT_SHADOWS=1,LIGHT_TYPE=1) META_PERMUTATION_3(SHADOWS_QUALITY=3,CONTACT_SHADOWS=1,LIGHT_TYPE=1) float4 PS_LocalLight(Model_VS2PS input) : SV_Target0 { - // Obtain texture coordinates corresponding to the current pixel - float2 uv = (input.ScreenPos.xy / input.ScreenPos.w) * float2(0.5, -0.5) + float2(0.5, 0.5); - // Sample GBuffer + float2 uv = ProjectClipToUV(input.ScreenPos.xy / input.ScreenPos.w); GBufferData gBufferData = GetGBufferData(); GBufferSample gBuffer = SampleGBuffer(gBufferData, uv); diff --git a/Source/Shaders/Sky.shader b/Source/Shaders/Sky.shader index 9faef41f7..95cde2ffc 100644 --- a/Source/Shaders/Sky.shader +++ b/Source/Shaders/Sky.shader @@ -55,7 +55,7 @@ GBufferOutput PS_Sky(MaterialInput input) float4 color = GetAtmosphericFog(AtmosphericFog, gBufferData.ViewFar, gBufferData.ViewPos + ViewOffset, viewVector, gBufferData.ViewFar, float3(0, 0, 0)); // Apply dithering to hide banding artifacts - float2 uv = (input.ScreenPos.xy / input.ScreenPos.w) * float2(0.5, -0.5) + float2(0.5, 0.5); + float2 uv = ProjectClipToUV(input.ScreenPos.xy / input.ScreenPos.w); float luminance = Luminance(saturate(color.rgb)); color.rgb += rand2dTo1d(uv) * luminance * NoiseScale;