Fix Forward shading to match Deferred in fog and reflections rendering

#3717
This commit is contained in:
2026-02-11 00:06:44 +01:00
parent e851efa0a8
commit ef551c36ae
7 changed files with 45 additions and 40 deletions
@@ -28,6 +28,7 @@ TextureCube SkyLightTexture : register(t__SRV__);
Buffer<float4> ShadowsBuffer : register(t__SRV__); Buffer<float4> ShadowsBuffer : register(t__SRV__);
Texture2D<float> ShadowMap : register(t__SRV__); Texture2D<float> ShadowMap : register(t__SRV__);
Texture3D VolumetricFogTexture : register(t__SRV__); Texture3D VolumetricFogTexture : register(t__SRV__);
Texture2D PreIntegratedGF : register(t__SRV__);
@4// Forward Shading: Utilities @4// Forward Shading: Utilities
// Public accessors for lighting data, use them as data binding might change but those methods will remain. // Public accessors for lighting data, use them as data binding might change but those methods will remain.
LightData GetDirectionalLight() { return DirectionalLight; } LightData GetDirectionalLight() { return DirectionalLight; }
@@ -108,7 +109,8 @@ void PS_Forward(
// Calculate reflections // Calculate reflections
#if USE_REFLECTIONS #if USE_REFLECTIONS
float3 reflections = SampleReflectionProbe(ViewPos, EnvProbe, EnvironmentProbe, gBuffer.WorldPos, gBuffer.Normal, gBuffer.Roughness).rgb; float4 reflections = SampleReflectionProbe(ViewPos, EnvProbe, EnvironmentProbe, gBuffer.WorldPos, gBuffer.Normal, gBuffer.Roughness);
reflections.rgb *= reflections.a;
#if MATERIAL_REFLECTIONS == MATERIAL_REFLECTIONS_SSR #if MATERIAL_REFLECTIONS == MATERIAL_REFLECTIONS_SSR
// Screen Space Reflections // Screen Space Reflections
@@ -124,7 +126,7 @@ void PS_Forward(
if (hit.z > 0) if (hit.z > 0)
{ {
float3 screenColor = sceneColorTexture.SampleLevel(SamplerPointClamp, hit.xy, 0).rgb; float3 screenColor = sceneColorTexture.SampleLevel(SamplerPointClamp, hit.xy, 0).rgb;
reflections = lerp(reflections, screenColor, hit.z); reflections.rgb = lerp(reflections.rgb, screenColor, hit.z);
} }
// Fallback to software tracing if possible // Fallback to software tracing if possible
@@ -136,13 +138,13 @@ void PS_Forward(
if (TraceSDFSoftwareReflections(gBuffer, reflectWS, surfaceAtlas)) if (TraceSDFSoftwareReflections(gBuffer, reflectWS, surfaceAtlas))
{ {
float3 screenColor = sceneColorTexture.SampleLevel(SamplerPointClamp, hit.xy, 0).rgb; float3 screenColor = sceneColorTexture.SampleLevel(SamplerPointClamp, hit.xy, 0).rgb;
reflections = lerp(surfaceAtlas, float4(screenColor, 1), hit.z); reflections.rgb = lerp(surfaceAtlas, float4(screenColor, 1), hit.z);
} }
} }
#endif #endif
#endif #endif
light.rgb += reflections * GetReflectionSpecularLighting(ViewPos, gBuffer) * light.a; light.rgb += reflections.rgb * GetReflectionSpecularLighting(PreIntegratedGF, ViewPos, gBuffer);
#endif #endif
// Add lighting // Add lighting
@@ -158,7 +160,8 @@ void PS_Forward(
#else #else
float fogSceneDistance = gBuffer.ViewPos.z; float fogSceneDistance = gBuffer.ViewPos.z;
#endif #endif
float4 fog = GetExponentialHeightFog(ExponentialHeightFog, materialInput.WorldPosition, ViewPos, 0, fogSceneDistance); float fogSkipDistance = max(ExponentialHeightFog.VolumetricFogMaxDistance - 100, 0);
float4 fog = GetExponentialHeightFog(ExponentialHeightFog, materialInput.WorldPosition, ViewPos, fogSkipDistance, fogSceneDistance);
if (ExponentialHeightFog.VolumetricFogMaxDistance > 0) if (ExponentialHeightFog.VolumetricFogMaxDistance > 0)
{ {
@@ -10,7 +10,7 @@
/// <summary> /// <summary>
/// Current materials shader version. /// Current materials shader version.
/// </summary> /// </summary>
#define MATERIAL_GRAPH_VERSION 179 #define MATERIAL_GRAPH_VERSION 180
class Material; class Material;
class GPUShader; class GPUShader;
@@ -10,9 +10,11 @@
#if USE_EDITOR #if USE_EDITOR
#include "Engine/Renderer/Lightmaps.h" #include "Engine/Renderer/Lightmaps.h"
#endif #endif
#include "Engine/Content/Content.h"
#include "Engine/Graphics/GPUContext.h" #include "Engine/Graphics/GPUContext.h"
#include "Engine/Level/Scene/Lightmap.h" #include "Engine/Level/Scene/Lightmap.h"
#include "Engine/Level/Actors/EnvironmentProbe.h" #include "Engine/Level/Actors/EnvironmentProbe.h"
#include "Engine/Renderer/ReflectionsPass.h"
void ForwardShadingFeature::Bind(MaterialShader::BindParameters& params, Span<byte>& cb, int32& srv) void ForwardShadingFeature::Bind(MaterialShader::BindParameters& params, Span<byte>& cb, int32& srv)
{ {
@@ -26,6 +28,7 @@ void ForwardShadingFeature::Bind(MaterialShader::BindParameters& params, Span<by
const int32 shadowsBufferRegisterIndex = srv + 2; const int32 shadowsBufferRegisterIndex = srv + 2;
const int32 shadowMapShaderRegisterIndex = srv + 3; const int32 shadowMapShaderRegisterIndex = srv + 3;
const int32 volumetricFogTextureRegisterIndex = srv + 4; const int32 volumetricFogTextureRegisterIndex = srv + 4;
const int32 preIntegratedGFRegisterIndex = srv + 5;
const bool canUseShadow = view.Pass != DrawPass::Depth; const bool canUseShadow = view.Pass != DrawPass::Depth;
// Set fog input // Set fog input
@@ -47,6 +50,7 @@ void ForwardShadingFeature::Bind(MaterialShader::BindParameters& params, Span<by
data.ExponentialHeightFog.FogCutoffDistance = 0.1f; data.ExponentialHeightFog.FogCutoffDistance = 0.1f;
data.ExponentialHeightFog.StartDistance = 0.0f; data.ExponentialHeightFog.StartDistance = 0.0f;
data.ExponentialHeightFog.ApplyDirectionalInscattering = 0.0f; data.ExponentialHeightFog.ApplyDirectionalInscattering = 0.0f;
data.ExponentialHeightFog.VolumetricFogMaxDistance = -1.0f;
} }
params.GPUContext->BindSR(volumetricFogTextureRegisterIndex, volumetricFogTexture); params.GPUContext->BindSR(volumetricFogTextureRegisterIndex, volumetricFogTexture);
@@ -100,9 +104,12 @@ void ForwardShadingFeature::Bind(MaterialShader::BindParameters& params, Span<by
} }
if (noEnvProbe) if (noEnvProbe)
{ {
data.EnvironmentProbe.Data1 = Float4::Zero; Platform::MemoryClear(&data.EnvironmentProbe, sizeof(data.EnvironmentProbe));
params.GPUContext->UnBindSR(envProbeShaderRegisterIndex); params.GPUContext->UnBindSR(envProbeShaderRegisterIndex);
} }
// TODO: find a better way to find this texture (eg. cache GPUTextureView* handle within ForwardShading cache for a whole frame)
static AssetReference<Texture> PreIntegratedGF = Content::LoadAsyncInternal<Texture>(PRE_INTEGRATED_GF_ASSET_NAME);
params.GPUContext->BindSR(preIntegratedGFRegisterIndex, PreIntegratedGF->GetTexture());
// Set local lights // Set local lights
data.LocalLightsCount = 0; data.LocalLightsCount = 0;
@@ -25,10 +25,9 @@ struct ForwardShadingFeature : MaterialShaderFeature
{ {
enum { MaxLocalLights = 4 }; enum { MaxLocalLights = 4 };
enum { SRVs = 5 }; enum { SRVs = 6 };
PACK_STRUCT(struct Data PACK_STRUCT(struct Data {
{
ShaderLightData DirectionalLight; ShaderLightData DirectionalLight;
ShaderLightData SkyLight; ShaderLightData SkyLight;
ShaderEnvProbeData EnvironmentProbe; ShaderEnvProbeData EnvironmentProbe;
@@ -76,8 +75,7 @@ struct GlobalIlluminationFeature : MaterialShaderFeature
{ {
enum { SRVs = 3 }; enum { SRVs = 3 };
PACK_STRUCT(struct Data PACK_STRUCT(struct Data {
{
DynamicDiffuseGlobalIlluminationPass::ConstantsData DDGI; DynamicDiffuseGlobalIlluminationPass::ConstantsData DDGI;
}); });
@@ -92,13 +90,10 @@ struct SDFReflectionsFeature : MaterialShaderFeature
{ {
enum { SRVs = 7 }; enum { SRVs = 7 };
PACK_STRUCT(struct Data PACK_STRUCT(struct Data {
{
GlobalSignDistanceFieldPass::ConstantsData GlobalSDF; GlobalSignDistanceFieldPass::ConstantsData GlobalSDF;
GlobalSurfaceAtlasPass::ConstantsData GlobalSurfaceAtlas; GlobalSurfaceAtlasPass::ConstantsData GlobalSurfaceAtlas;
}); });
static bool Bind(MaterialShader::BindParameters& params, Span<byte>& cb, int32& srv); static bool Bind(MaterialShader::BindParameters& params, Span<byte>& cb, int32& srv);
#if USE_EDITOR #if USE_EDITOR
+1 -11
View File
@@ -76,18 +76,8 @@ float4 PS_CombinePass(Quad_VS2PS input) : SV_Target0
// Sample reflections buffer // Sample reflections buffer
float3 reflections = SAMPLE_RT(Reflections, input.TexCoord).rgb; float3 reflections = SAMPLE_RT(Reflections, input.TexCoord).rgb;
// Calculate specular color
float3 specularColor = GetSpecularColor(gBuffer);
// Calculate reflection color // Calculate reflection color
float3 V = normalize(gBufferData.ViewPos - gBuffer.WorldPos); reflections *= GetReflectionSpecularLighting(PreIntegratedGF, gBufferData.ViewPos, gBuffer);
float NoV = saturate(dot(gBuffer.Normal, V));
reflections *= EnvBRDF(PreIntegratedGF, specularColor, gBuffer.Roughness, NoV);
// Apply specular occlusion
float roughnessSq = gBuffer.Roughness * gBuffer.Roughness;
float specularOcclusion = GetSpecularOcclusion(NoV, roughnessSq, gBuffer.AO);
reflections *= specularOcclusion;
return float4(reflections, 0); return float4(reflections, 0);
} }
+21 -6
View File
@@ -4,6 +4,7 @@
#define __REFLECTIONS_COMMON__ #define __REFLECTIONS_COMMON__
#include "./Flax/GBufferCommon.hlsl" #include "./Flax/GBufferCommon.hlsl"
#include "./Flax/BRDF.hlsl"
// Hit depth (view space) threshold to detect if sky was hit (value above it where 1.0f is default) // Hit depth (view space) threshold to detect if sky was hit (value above it where 1.0f is default)
#define REFLECTIONS_HIT_THRESHOLD 0.9f #define REFLECTIONS_HIT_THRESHOLD 0.9f
@@ -48,15 +49,29 @@ float4 SampleReflectionProbe(float3 viewPos, TextureCube probe, ProbeData data,
// Calculates the reflective environment lighting to multiply the raw reflection color for the specular light (eg. from Env Probe or SSR). // Calculates the reflective environment lighting to multiply the raw reflection color for the specular light (eg. from Env Probe or SSR).
float3 GetReflectionSpecularLighting(float3 viewPos, GBufferSample gBuffer) float3 GetReflectionSpecularLighting(float3 viewPos, GBufferSample gBuffer)
{ {
// Calculate reflection color // Calculate reflection color
float3 specularColor = GetSpecularColor(gBuffer);
float3 V = normalize(viewPos - gBuffer.WorldPos); float3 V = normalize(viewPos - gBuffer.WorldPos);
float NoV = saturate(dot(gBuffer.Normal, V)); float NoV = saturate(dot(gBuffer.Normal, V));
float3 specularColor = GetSpecularColor(gBuffer);
float3 reflections = EnvBRDFApprox(specularColor, gBuffer.Roughness, NoV); float3 reflections = EnvBRDFApprox(specularColor, gBuffer.Roughness, NoV);
// Apply specular occlusion // Apply specular occlusion
float roughnessSq = gBuffer.Roughness * gBuffer.Roughness; float roughnessSq = gBuffer.Roughness * gBuffer.Roughness;
reflections *= GetSpecularOcclusion(NoV, roughnessSq, gBuffer.AO); reflections *= GetSpecularOcclusion(NoV, roughnessSq, gBuffer.AO);
return reflections;
}
float3 GetReflectionSpecularLighting(Texture2D preIntegratedGF, float3 viewPos, GBufferSample gBuffer)
{
// Calculate reflection color
float3 V = normalize(viewPos - gBuffer.WorldPos);
float NoV = saturate(dot(gBuffer.Normal, V));
float3 specularColor = GetSpecularColor(gBuffer);
float3 reflections = EnvBRDF(preIntegratedGF, specularColor, gBuffer.Roughness, NoV);
// Apply specular occlusion
float roughnessSq = gBuffer.Roughness * gBuffer.Roughness;
reflections *= GetSpecularOcclusion(NoV, roughnessSq, gBuffer.AO);
return reflections; return reflections;
} }
+1 -6
View File
@@ -81,13 +81,8 @@ float4 PS_CombinePass(Quad_VS2PS input) : SV_Target0
// Sample reflections buffer // Sample reflections buffer
float3 reflections = SAMPLE_RT(Texture1, input.TexCoord).rgb; float3 reflections = SAMPLE_RT(Texture1, input.TexCoord).rgb;
// Calculate specular color
float3 specularColor = GetSpecularColor(gBuffer);
// Calculate reflection color // Calculate reflection color
float3 V = normalize(gBufferData.ViewPos - gBuffer.WorldPos); light.rgb += reflections * GetReflectionSpecularLighting(Texture2, gBufferData.ViewPos, gBuffer);
float NoV = saturate(dot(gBuffer.Normal, V));
light.rgb += reflections * EnvBRDF(Texture2, specularColor, gBuffer.Roughness, NoV) * gBuffer.AO;
} }
return light; return light;