Add dithering to Volumetric Fog to reduce aliasing
This commit is contained in:
@@ -20,6 +20,7 @@ LightData DirectionalLight;
|
||||
LightData SkyLight;
|
||||
EnvProbeData EnvironmentProbe;
|
||||
ExponentialHeightFogData ExponentialHeightFog;
|
||||
VolumetricFogData VolumetricFog;
|
||||
float3 Dummy2;
|
||||
uint LocalLightsCount;
|
||||
LightData LocalLights[MAX_LOCAL_LIGHTS];
|
||||
@@ -35,6 +36,7 @@ LightData GetDirectionalLight() { return DirectionalLight; }
|
||||
LightData GetSkyLight() { return SkyLight; }
|
||||
EnvProbeData GetEnvironmentProbe() { return EnvironmentProbe; }
|
||||
ExponentialHeightFogData GetExponentialHeightFog() { return ExponentialHeightFog; }
|
||||
VolumetricFogData GetVolumetricFog() { return VolumetricFog; }
|
||||
uint GetLocalLightsCount() { return LocalLightsCount; }
|
||||
LightData GetLocalLight(uint i) { return LocalLights[i]; }
|
||||
@5// Forward Shading: Shaders
|
||||
@@ -164,7 +166,7 @@ void PS_Forward(
|
||||
{
|
||||
// Sample volumetric fog and mix it in
|
||||
float2 screenUV = materialInput.SvPosition.xy * ScreenSize.zw;
|
||||
float4 volumetricFog = SampleVolumetricFog(VolumetricFogTexture, ExponentialHeightFog.VolumetricFogGrid, materialInput.WorldPosition - ViewPos, screenUV);
|
||||
float4 volumetricFog = SampleVolumetricFog(VolumetricFogTexture, VolumetricFog, materialInput.WorldPosition - ViewPos, screenUV, TemporalAAJitter);
|
||||
fog = CombineVolumetricFog(fog, volumetricFog);
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,8 @@ void ForwardShadingFeature::Bind(MaterialShader::BindParameters& params, Span<by
|
||||
const bool canUseShadow = view.Pass != DrawPass::Depth;
|
||||
|
||||
// Set fog input
|
||||
data.ExponentialHeightFog = cache->Fog.ExponentialHeightFog;
|
||||
data.ExponentialHeightFog = cache->Fog.ExponentialHeightFogData;
|
||||
data.VolumetricFogData = cache->Fog.VolumetricFogData;
|
||||
params.GPUContext->BindSR(volumetricFogTextureRegisterIndex, cache->Fog.VolumetricFogTexture);
|
||||
|
||||
// Set directional light input
|
||||
|
||||
@@ -33,6 +33,7 @@ struct ForwardShadingFeature : MaterialShaderFeature
|
||||
ShaderLightData SkyLight;
|
||||
ShaderEnvProbeData EnvironmentProbe;
|
||||
ShaderExponentialHeightFogData ExponentialHeightFog;
|
||||
ShaderVolumetricFogData VolumetricFogData;
|
||||
Float3 Dummy2;
|
||||
uint32 LocalLightsCount;
|
||||
ShaderLightData LocalLights[MaxLocalLights];
|
||||
|
||||
@@ -182,6 +182,8 @@ void ExponentialHeightFog::GetExponentialHeightFogData(const RenderView& view, S
|
||||
GPU_CB_STRUCT(Data {
|
||||
ShaderGBufferData GBuffer;
|
||||
ShaderExponentialHeightFogData ExponentialHeightFog;
|
||||
ShaderVolumetricFogData VolumetricFog;
|
||||
Float4 TemporalAAJitter;
|
||||
});
|
||||
|
||||
void ExponentialHeightFog::DrawFog(GPUContext* context, RenderContext& renderContext, GPUTextureView* output)
|
||||
@@ -193,7 +195,9 @@ void ExponentialHeightFog::DrawFog(GPUContext* context, RenderContext& renderCon
|
||||
// Setup shader inputs
|
||||
Data data;
|
||||
GBufferPass::SetInputs(renderContext.View, data.GBuffer);
|
||||
data.ExponentialHeightFog = renderContext.List->Fog.ExponentialHeightFog;
|
||||
data.ExponentialHeightFog = renderContext.List->Fog.ExponentialHeightFogData;
|
||||
data.VolumetricFog = renderContext.List->Fog.VolumetricFogData;
|
||||
data.TemporalAAJitter = renderContext.View.TemporalAAJitter;
|
||||
auto cb = _shader->GetShader()->GetCB(0);
|
||||
ASSERT_LOW_LAYER(cb->GetSize() == sizeof(Data));
|
||||
context->UpdateCB(cb, &data);
|
||||
|
||||
@@ -42,8 +42,15 @@ GPU_CB_STRUCT(ShaderExponentialHeightFogData {
|
||||
float VolumetricFogMaxDistance;
|
||||
float DirectionalInscatteringStartDistance;
|
||||
float StartDistance;
|
||||
});
|
||||
|
||||
Float4 VolumetricFogGrid;
|
||||
/// <summary>
|
||||
/// Structure that contains information about volumetric fog
|
||||
/// </summary>
|
||||
GPU_CB_STRUCT(ShaderVolumetricFogData {
|
||||
Float4 GridSliceParameters;
|
||||
Float2 ScreenSize;
|
||||
Float2 VolumeTexelSize; // Scaled for dithering
|
||||
});
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -183,19 +183,20 @@ RenderFogData::RenderFogData()
|
||||
{
|
||||
Renderer = nullptr;
|
||||
VolumetricFogTexture = nullptr;
|
||||
ExponentialHeightFog.FogMinOpacity = 1.0f;
|
||||
ExponentialHeightFog.FogDensity = 0.0f;
|
||||
ExponentialHeightFog.FogCutoffDistance = 0.1f;
|
||||
ExponentialHeightFog.StartDistance = 0.0f;
|
||||
ExponentialHeightFog.ApplyDirectionalInscattering = 0.0f;
|
||||
ExponentialHeightFog.VolumetricFogMaxDistance = -1.0f;
|
||||
ExponentialHeightFog.VolumetricFogGrid = Float4::One;
|
||||
ExponentialHeightFogData.FogMinOpacity = 1.0f;
|
||||
ExponentialHeightFogData.FogDensity = 0.0f;
|
||||
ExponentialHeightFogData.FogCutoffDistance = 0.1f;
|
||||
ExponentialHeightFogData.StartDistance = 0.0f;
|
||||
ExponentialHeightFogData.ApplyDirectionalInscattering = 0.0f;
|
||||
ExponentialHeightFogData.VolumetricFogMaxDistance = -1.0f;
|
||||
VolumetricFogData.GridSliceParameters = Float4::One;
|
||||
VolumetricFogData.ScreenSize = VolumetricFogData.VolumeTexelSize = Float2::Zero;
|
||||
}
|
||||
|
||||
void RenderFogData::Init(const RenderView& view, IFogRenderer* renderer)
|
||||
{
|
||||
Renderer = renderer;
|
||||
renderer->GetExponentialHeightFogData(view, ExponentialHeightFog);
|
||||
renderer->GetExponentialHeightFogData(view, ExponentialHeightFogData);
|
||||
renderer->GetVolumetricFogOptions(VolumetricFog);
|
||||
}
|
||||
|
||||
|
||||
@@ -179,7 +179,8 @@ struct RenderFogData
|
||||
{
|
||||
IFogRenderer* Renderer;
|
||||
GPUTextureView* VolumetricFogTexture;
|
||||
ShaderExponentialHeightFogData ExponentialHeightFog;
|
||||
ShaderExponentialHeightFogData ExponentialHeightFogData;
|
||||
ShaderVolumetricFogData VolumetricFogData;
|
||||
VolumetricFogOptions VolumetricFog;
|
||||
|
||||
RenderFogData();
|
||||
|
||||
@@ -679,8 +679,11 @@ void VolumetricFogPass::Render(RenderContext& renderContext)
|
||||
renderContext.Buffers->LastFrameVolumetricFog = Engine::FrameCount;
|
||||
|
||||
// Update fog to be used by other passes
|
||||
const float ditherNoiseScale = 0.2f; // Scales noise in SampleVolumetricFog
|
||||
renderContext.List->Fog.VolumetricFogTexture = integratedLightScattering->ViewVolume();
|
||||
renderContext.List->Fog.ExponentialHeightFog.VolumetricFogGrid = cache.Data.GridSliceParameters;
|
||||
renderContext.List->Fog.VolumetricFogData.GridSliceParameters = cache.Data.GridSliceParameters;
|
||||
renderContext.List->Fog.VolumetricFogData.ScreenSize = renderContext.Buffers->GetSize();
|
||||
renderContext.List->Fog.VolumetricFogData.VolumeTexelSize = Float2(1.0f / cache.GridSize.X, 1.0f / cache.GridSize.Y) * ditherNoiseScale;
|
||||
|
||||
groupCountX = Math::DivideAndRoundUp((int32)cache.GridSize.X, VolumetricFogIntegrationGroupSize);
|
||||
groupCountY = Math::DivideAndRoundUp((int32)cache.GridSize.Y, VolumetricFogIntegrationGroupSize);
|
||||
|
||||
@@ -27,8 +27,6 @@ struct ExponentialHeightFogData
|
||||
float VolumetricFogMaxDistance;
|
||||
float DirectionalInscatteringStartDistance;
|
||||
float StartDistance;
|
||||
|
||||
float4 VolumetricFogGrid;
|
||||
};
|
||||
|
||||
float4 GetExponentialHeightFog(ExponentialHeightFogData exponentialHeightFog, float3 posWS, float3 camWS, float skipDistance, float sceneDistance)
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
META_CB_BEGIN(0, Data)
|
||||
GBufferData GBuffer;
|
||||
ExponentialHeightFogData ExponentialHeightFog;
|
||||
VolumetricFogData VolumetricFog;
|
||||
float4 TemporalAAJitter;
|
||||
META_CB_END
|
||||
|
||||
DECLARE_GBUFFERDATA_ACCESS(GBuffer)
|
||||
@@ -46,7 +48,7 @@ float4 PS_Fog(Quad_VS2PS input) : SV_Target0
|
||||
|
||||
#if VOLUMETRIC_FOG
|
||||
// Sample volumetric fog and mix it in
|
||||
float4 volumetricFog = SampleVolumetricFog(VolumetricFogTexture, ExponentialHeightFog.VolumetricFogGrid, worldPos - GBuffer.ViewPos, input.TexCoord);
|
||||
float4 volumetricFog = SampleVolumetricFog(VolumetricFogTexture, VolumetricFog, worldPos - GBuffer.ViewPos, input.TexCoord, TemporalAAJitter);
|
||||
fog = CombineVolumetricFog(fog, volumetricFog);
|
||||
#endif
|
||||
|
||||
|
||||
@@ -3,8 +3,18 @@
|
||||
#ifndef __VOLUMETRIC_FOG__
|
||||
#define __VOLUMETRIC_FOG__
|
||||
|
||||
#include "./Flax/Noise.hlsl"
|
||||
|
||||
#define VOLUMETRIC_FOG_GRID_Z_LINEAR 1
|
||||
|
||||
// Structure that contains information about volumetric fog
|
||||
struct VolumetricFogData
|
||||
{
|
||||
float4 GridSliceParameters;
|
||||
float2 ScreenSize;
|
||||
float2 VolumeTexelSize; // Scaled for dithering
|
||||
};
|
||||
|
||||
float GetDepthFromSlice(float4 gridSliceParameters, float zSlice)
|
||||
{
|
||||
#if VOLUMETRIC_FOG_GRID_Z_LINEAR
|
||||
@@ -23,11 +33,19 @@ float GetSliceFromDepth(float4 gridSliceParameters, float sceneDepth)
|
||||
#endif
|
||||
}
|
||||
|
||||
float4 SampleVolumetricFog(Texture3D volumetricFogTexture, float4 gridSliceParameters, float3 viewVector, float2 uv)
|
||||
float4 SampleVolumetricFog(Texture3D volumetricFogTexture, VolumetricFogData volumetricFogData, float3 viewVector, float2 uv, float4 temporalAAJitter = 0)
|
||||
{
|
||||
// Project view vector to get 3D frustum UVW coordinates
|
||||
float sceneDepth = length(viewVector);
|
||||
float zSlice = GetSliceFromDepth(gridSliceParameters, sceneDepth) * gridSliceParameters.w;
|
||||
float zSlice = GetSliceFromDepth(volumetricFogData.GridSliceParameters, sceneDepth) * volumetricFogData.GridSliceParameters.w;
|
||||
float3 volumeUV = float3(uv, zSlice);
|
||||
|
||||
// Dither to reduce banding artifacts
|
||||
float2 noiseUV = volumeUV.xy + temporalAAJitter.xy;
|
||||
float2 noise = rand2dTo2d(noiseUV * volumetricFogData.ScreenSize) * 2.0f - 1.0f;
|
||||
volumeUV.xy += noise * volumetricFogData.VolumeTexelSize;
|
||||
|
||||
// Sample 3D texture
|
||||
return volumetricFogTexture.SampleLevel(SamplerLinearClamp, volumeUV, 0);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user