Add Start Distance to volumetric fog to match Exponential Fog more
This commit is contained in:
Binary file not shown.
@@ -47,8 +47,8 @@ GPU_CB_STRUCT(Data {
|
|||||||
uint32 GridSizeIntZ;
|
uint32 GridSizeIntZ;
|
||||||
float PhaseG;
|
float PhaseG;
|
||||||
|
|
||||||
Float2 Dummy0;
|
Float2 VolumetricFogRange;
|
||||||
float VolumetricFogMaxDistance;
|
float Dummy0;
|
||||||
float InverseSquaredLightDistanceBiasScale;
|
float InverseSquaredLightDistanceBiasScale;
|
||||||
|
|
||||||
Float4 FogParameters;
|
Float4 FogParameters;
|
||||||
@@ -161,8 +161,9 @@ Float4 GetGridSliceParameters(float fogStart, float fogEnd, int32 gridSizeZ)
|
|||||||
{
|
{
|
||||||
float sliceToUV = 1.0f / (float)gridSizeZ;
|
float sliceToUV = 1.0f / (float)gridSizeZ;
|
||||||
#if VOLUMETRIC_FOG_GRID_Z_LINEAR
|
#if VOLUMETRIC_FOG_GRID_Z_LINEAR
|
||||||
float sliceToDepth = fogEnd / (float)gridSizeZ;
|
float sliceToDepth = (fogEnd - fogStart) / (float)(gridSizeZ - 1);
|
||||||
return Float4(sliceToDepth, 1.0f / sliceToDepth, 0.0f, sliceToUV);
|
float sliceToDepthInv = 1.0f / sliceToDepth;
|
||||||
|
return Float4(sliceToDepth, 1.0f / sliceToDepth, -fogStart * sliceToDepthInv, sliceToUV);
|
||||||
#else
|
#else
|
||||||
// Use logarithmic distribution for Z slices to have more resolution for close distances and less for far ones (less aliasing near camera)
|
// Use logarithmic distribution for Z slices to have more resolution for close distances and less for far ones (less aliasing near camera)
|
||||||
const float distribution = 220.0f; // Manually adjusted to give a good distribution across the range
|
const float distribution = 220.0f; // Manually adjusted to give a good distribution across the range
|
||||||
@@ -176,7 +177,7 @@ Float4 GetGridSliceParameters(float fogStart, float fogEnd, int32 gridSizeZ)
|
|||||||
float GetDepthFromSlice(float slice, const Float4& gridSliceParameters)
|
float GetDepthFromSlice(float slice, const Float4& gridSliceParameters)
|
||||||
{
|
{
|
||||||
#if VOLUMETRIC_FOG_GRID_Z_LINEAR
|
#if VOLUMETRIC_FOG_GRID_Z_LINEAR
|
||||||
return slice * gridSliceParameters.X;
|
return (slice - gridSliceParameters.Z) * gridSliceParameters.X;
|
||||||
#else
|
#else
|
||||||
return (Math::Exp2(slice / gridSliceParameters.Z) - gridSliceParameters.Y) / gridSliceParameters.X;
|
return (Math::Exp2(slice / gridSliceParameters.Z) - gridSliceParameters.Y) / gridSliceParameters.X;
|
||||||
#endif
|
#endif
|
||||||
@@ -185,7 +186,7 @@ float GetDepthFromSlice(float slice, const Float4& gridSliceParameters)
|
|||||||
float GetSliceFromDepth(float sceneDepth, const Float4& gridSliceParameters)
|
float GetSliceFromDepth(float sceneDepth, const Float4& gridSliceParameters)
|
||||||
{
|
{
|
||||||
#if VOLUMETRIC_FOG_GRID_Z_LINEAR
|
#if VOLUMETRIC_FOG_GRID_Z_LINEAR
|
||||||
return sceneDepth * gridSliceParameters.Y;
|
return sceneDepth * gridSliceParameters.Y + gridSliceParameters.Z;
|
||||||
#else
|
#else
|
||||||
return Math::Log2(sceneDepth * gridSliceParameters.X + gridSliceParameters.Y) * gridSliceParameters.Z;
|
return Math::Log2(sceneDepth * gridSliceParameters.X + gridSliceParameters.Y) * gridSliceParameters.Z;
|
||||||
#endif
|
#endif
|
||||||
@@ -205,10 +206,12 @@ bool VolumetricFogPass::Init(FrameCache& cache, RenderContext& renderContext, GP
|
|||||||
const auto& fog = renderContext.List->Fog;
|
const auto& fog = renderContext.List->Fog;
|
||||||
if (renderContext.Buffers->LastFrameVolumetricFog == Engine::FrameCount)
|
if (renderContext.Buffers->LastFrameVolumetricFog == Engine::FrameCount)
|
||||||
return false;
|
return false;
|
||||||
|
float fogStart = Math::Max(renderContext.View.Near, fog.ExponentialHeightFogData.StartDistance);
|
||||||
if (fog.Renderer == nullptr ||
|
if (fog.Renderer == nullptr ||
|
||||||
!renderContext.List->Setup.UseVolumetricFog ||
|
!renderContext.List->Setup.UseVolumetricFog ||
|
||||||
!_isSupported ||
|
!_isSupported ||
|
||||||
!fog.VolumetricFog.UseVolumetricFog() ||
|
!fog.VolumetricFog.UseVolumetricFog() ||
|
||||||
|
fogStart + METERS_TO_UNITS(1) >= fog.VolumetricFog.Distance ||
|
||||||
checkIfSkipPass())
|
checkIfSkipPass())
|
||||||
{
|
{
|
||||||
RenderTargetPool::Release(renderContext.Buffers->VolumetricFog);
|
RenderTargetPool::Release(renderContext.Buffers->VolumetricFog);
|
||||||
@@ -245,6 +248,13 @@ bool VolumetricFogPass::Init(FrameCache& cache, RenderContext& renderContext, GP
|
|||||||
cache.MissedHistorySamplesCount = 8;
|
cache.MissedHistorySamplesCount = 8;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
auto& fogData = renderContext.Buffers->VolumetricFogData;
|
||||||
|
fogData.MaxDistance = options.Distance;
|
||||||
|
|
||||||
|
// Reduce Z resolution when fog range is smaller than reference
|
||||||
|
float referenceRangeScaleZ = METERS_TO_UNITS(60);
|
||||||
|
float fogRange = fogData.MaxDistance - fogStart;
|
||||||
|
cache.GridSizeZ = Math::CeilToInt(Math::Clamp(fogRange / referenceRangeScaleZ, 0.3f, 1.5f) * cache.GridSizeZ);
|
||||||
|
|
||||||
// Calculate volumetric fog size
|
// Calculate volumetric fog size
|
||||||
const int32 width = renderContext.Buffers->GetWidth();
|
const int32 width = renderContext.Buffers->GetWidth();
|
||||||
@@ -265,8 +275,6 @@ bool VolumetricFogPass::Init(FrameCache& cache, RenderContext& renderContext, GP
|
|||||||
(float)Math::DivideAndRoundUp(width, cache.GridPixelSize),
|
(float)Math::DivideAndRoundUp(width, cache.GridPixelSize),
|
||||||
(float)Math::DivideAndRoundUp(height, cache.GridPixelSize),
|
(float)Math::DivideAndRoundUp(height, cache.GridPixelSize),
|
||||||
(float)cache.GridSizeZ);
|
(float)cache.GridSizeZ);
|
||||||
auto& fogData = renderContext.Buffers->VolumetricFogData;
|
|
||||||
fogData.MaxDistance = options.Distance;
|
|
||||||
if (renderContext.Task->IsCameraCut ||
|
if (renderContext.Task->IsCameraCut ||
|
||||||
renderContext.View.IsOriginTeleport() ||
|
renderContext.View.IsOriginTeleport() ||
|
||||||
(renderContext.Buffers->VolumetricFog && renderContext.Buffers->VolumetricFog->Size3() != cache.GridSize) ||
|
(renderContext.Buffers->VolumetricFog && renderContext.Buffers->VolumetricFog->Size3() != cache.GridSize) ||
|
||||||
@@ -287,17 +295,22 @@ bool VolumetricFogPass::Init(FrameCache& cache, RenderContext& renderContext, GP
|
|||||||
cache.Data.GridSizeIntZ = (uint32)cache.GridSize.Z;
|
cache.Data.GridSizeIntZ = (uint32)cache.GridSize.Z;
|
||||||
cache.Data.HistoryWeight = cache.HistoryWeight;
|
cache.Data.HistoryWeight = cache.HistoryWeight;
|
||||||
cache.Data.FogParameters = options.FogParameters;
|
cache.Data.FogParameters = options.FogParameters;
|
||||||
cache.Data.GridSliceParameters = GetGridSliceParameters(renderContext.View.Near, options.Distance, cache.GridSizeZ);
|
cache.Data.GridSliceParameters = GetGridSliceParameters(fogStart, fogData.MaxDistance, cache.GridSizeZ);
|
||||||
/*static bool log = true;
|
/*static bool log = true;
|
||||||
if (log)
|
if (log)
|
||||||
{
|
{
|
||||||
log = false;
|
log = false;
|
||||||
|
LOG(Info, "Fog range: {} - {}", fogStart, fogData.MaxDistance);
|
||||||
for (int slice = 0; slice < cache.GridSizeZ; slice++)
|
for (int slice = 0; slice < cache.GridSizeZ; slice++)
|
||||||
LOG(Error, "Slice {} -> {}", slice, GetDepthFromSlice((float)slice, cache.Data.GridSliceParameters));
|
{
|
||||||
|
float depth = GetDepthFromSlice((float)slice, cache.Data.GridSliceParameters);
|
||||||
|
LOG(Info, "Slice {} -> {}", slice, depth);
|
||||||
|
ASSERT((int32)GetSliceFromDepth(depth, cache.Data.GridSliceParameters) == slice);
|
||||||
|
}
|
||||||
}*/
|
}*/
|
||||||
cache.Data.InverseSquaredLightDistanceBiasScale = cache.InverseSquaredLightDistanceBiasScale;
|
cache.Data.InverseSquaredLightDistanceBiasScale = cache.InverseSquaredLightDistanceBiasScale;
|
||||||
cache.Data.PhaseG = options.ScatteringDistribution;
|
cache.Data.PhaseG = options.ScatteringDistribution;
|
||||||
cache.Data.VolumetricFogMaxDistance = options.Distance;
|
cache.Data.VolumetricFogRange = Float2(fogStart, options.Distance);
|
||||||
cache.Data.MissedHistorySamplesCount = Math::Clamp(cache.MissedHistorySamplesCount, 1, (int32)ARRAY_COUNT(cache.Data.FrameJitterOffsets));
|
cache.Data.MissedHistorySamplesCount = Math::Clamp(cache.MissedHistorySamplesCount, 1, (int32)ARRAY_COUNT(cache.Data.FrameJitterOffsets));
|
||||||
Matrix::Transpose(renderContext.View.PrevViewProjection, cache.Data.PrevWorldToClip);
|
Matrix::Transpose(renderContext.View.PrevViewProjection, cache.Data.PrevWorldToClip);
|
||||||
cache.Data.SkyLight.VolumetricScatteringIntensity = 0;
|
cache.Data.SkyLight.VolumetricScatteringIntensity = 0;
|
||||||
@@ -362,7 +375,7 @@ bool VolumetricFogPass::InitSphereRasterize(FrameCache& cache, RasterizeSphere&
|
|||||||
sphere.VolumeZBoundsMax = (uint16)Math::Clamp(furthestSliceIndex, 0.0f, cache.GridSize.Z - 1.0f);
|
sphere.VolumeZBoundsMax = (uint16)Math::Clamp(furthestSliceIndex, 0.0f, cache.GridSize.Z - 1.0f);
|
||||||
|
|
||||||
// Cull
|
// Cull
|
||||||
if ((view.Position - sphere.Center).LengthSquared() >= Math::Square(cache.Data.VolumetricFogMaxDistance + sphere.Radius) ||
|
if ((view.Position - sphere.Center).LengthSquared() >= Math::Square(cache.Data.VolumetricFogRange.Y + sphere.Radius) ||
|
||||||
sphere.VolumeZBoundsMin > sphere.VolumeZBoundsMax)
|
sphere.VolumeZBoundsMin > sphere.VolumeZBoundsMax)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
@@ -395,7 +408,7 @@ void VolumetricFogPass::RenderRadialLight(FrameCache& cache, RenderContext& rend
|
|||||||
|
|
||||||
// Setup data
|
// Setup data
|
||||||
perLight.SliceToDepth.X = cache.Data.GridSize.Z;
|
perLight.SliceToDepth.X = cache.Data.GridSize.Z;
|
||||||
perLight.SliceToDepth.Y = cache.Data.VolumetricFogMaxDistance;
|
perLight.SliceToDepth.Y = cache.Data.VolumetricFogRange.Y;
|
||||||
perLight.MinZ = sphere.VolumeZBoundsMin;
|
perLight.MinZ = sphere.VolumeZBoundsMin;
|
||||||
perLight.LocalLightScatteringIntensity = light.VolumetricScatteringIntensity;
|
perLight.LocalLightScatteringIntensity = light.VolumetricScatteringIntensity;
|
||||||
perLight.ViewSpaceBoundingSphere = Float4(sphere.ViewSpaceCenter, sphere.Radius);
|
perLight.ViewSpaceBoundingSphere = Float4(sphere.ViewSpaceCenter, sphere.Radius);
|
||||||
@@ -532,7 +545,7 @@ void VolumetricFogPass::Render(RenderContext& renderContext)
|
|||||||
CustomData customData;
|
CustomData customData;
|
||||||
customData.Shader = _shader->GetShader();
|
customData.Shader = _shader->GetShader();
|
||||||
customData.GridSize = cache.GridSize;
|
customData.GridSize = cache.GridSize;
|
||||||
customData.VolumetricFogMaxDistance = cache.Data.VolumetricFogMaxDistance;
|
customData.VolumetricFogMaxDistance = cache.Data.VolumetricFogRange.Y;
|
||||||
customData.GridSliceParameters = cache.Data.GridSliceParameters;
|
customData.GridSliceParameters = cache.Data.GridSliceParameters;
|
||||||
bindParams.CustomData = &customData;
|
bindParams.CustomData = &customData;
|
||||||
bindParams.BindViewData();
|
bindParams.BindViewData();
|
||||||
@@ -554,7 +567,7 @@ void VolumetricFogPass::Render(RenderContext& renderContext)
|
|||||||
PerLight perLight;
|
PerLight perLight;
|
||||||
auto cb2 = _shader->GetShader()->GetCB(2);
|
auto cb2 = _shader->GetShader()->GetCB(2);
|
||||||
perLight.SliceToDepth.X = cache.Data.GridSize.Z;
|
perLight.SliceToDepth.X = cache.Data.GridSize.Z;
|
||||||
perLight.SliceToDepth.Y = cache.Data.VolumetricFogMaxDistance;
|
perLight.SliceToDepth.Y = cache.Data.VolumetricFogRange.Y;
|
||||||
perLight.MinZ = sphere.VolumeZBoundsMin;
|
perLight.MinZ = sphere.VolumeZBoundsMin;
|
||||||
perLight.ViewSpaceBoundingSphere = Float4(sphere.ViewSpaceCenter, sphere.Radius);
|
perLight.ViewSpaceBoundingSphere = Float4(sphere.ViewSpaceCenter, sphere.Radius);
|
||||||
Matrix::Transpose(renderContext.View.Projection, perLight.ViewToVolumeClip);
|
Matrix::Transpose(renderContext.View.Projection, perLight.ViewToVolumeClip);
|
||||||
@@ -582,7 +595,7 @@ void VolumetricFogPass::Render(RenderContext& renderContext)
|
|||||||
Array<uint16, InlinedAllocation<64, RendererAllocation>> pointLights;
|
Array<uint16, InlinedAllocation<64, RendererAllocation>> pointLights;
|
||||||
Array<uint16, InlinedAllocation<64, RendererAllocation>> spotLights;
|
Array<uint16, InlinedAllocation<64, RendererAllocation>> spotLights;
|
||||||
Float3 viewPosition = renderContext.View.Position;
|
Float3 viewPosition = renderContext.View.Position;
|
||||||
float distance = cache.Data.VolumetricFogMaxDistance;
|
float distance = cache.Data.VolumetricFogRange.Y;
|
||||||
for (int32 i = 0; i < renderContext.List->PointLights.Count(); i++)
|
for (int32 i = 0; i < renderContext.List->PointLights.Count(); i++)
|
||||||
{
|
{
|
||||||
const auto& light = renderContext.List->PointLights.Get()[i];
|
const auto& light = renderContext.List->PointLights.Get()[i];
|
||||||
@@ -609,7 +622,7 @@ void VolumetricFogPass::Render(RenderContext& renderContext)
|
|||||||
// Prepare
|
// Prepare
|
||||||
PerLight perLight;
|
PerLight perLight;
|
||||||
perLight.SliceToDepth.X = cache.Data.GridSize.Z;
|
perLight.SliceToDepth.X = cache.Data.GridSize.Z;
|
||||||
perLight.SliceToDepth.Y = cache.Data.VolumetricFogMaxDistance;
|
perLight.SliceToDepth.Y = cache.Data.VolumetricFogRange.Y;
|
||||||
auto cb2 = _shader->GetShader()->GetCB(2);
|
auto cb2 = _shader->GetShader()->GetCB(2);
|
||||||
|
|
||||||
// Bind the output
|
// Bind the output
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ struct VolumetricFogData
|
|||||||
float GetDepthFromSlice(float4 gridSliceParameters, float zSlice)
|
float GetDepthFromSlice(float4 gridSliceParameters, float zSlice)
|
||||||
{
|
{
|
||||||
#if VOLUMETRIC_FOG_GRID_Z_LINEAR
|
#if VOLUMETRIC_FOG_GRID_Z_LINEAR
|
||||||
return zSlice * gridSliceParameters.x;
|
return (zSlice - gridSliceParameters.z) * gridSliceParameters.x;
|
||||||
#else
|
#else
|
||||||
return (exp2(zSlice / gridSliceParameters.z) - gridSliceParameters.y) / gridSliceParameters.x;
|
return (exp2(zSlice / gridSliceParameters.z) - gridSliceParameters.y) / gridSliceParameters.x;
|
||||||
#endif
|
#endif
|
||||||
@@ -27,7 +27,7 @@ float GetDepthFromSlice(float4 gridSliceParameters, float zSlice)
|
|||||||
float GetSliceFromDepth(float4 gridSliceParameters, float sceneDepth)
|
float GetSliceFromDepth(float4 gridSliceParameters, float sceneDepth)
|
||||||
{
|
{
|
||||||
#if VOLUMETRIC_FOG_GRID_Z_LINEAR
|
#if VOLUMETRIC_FOG_GRID_Z_LINEAR
|
||||||
return sceneDepth * gridSliceParameters.y;
|
return sceneDepth * gridSliceParameters.y + gridSliceParameters.z;
|
||||||
#else
|
#else
|
||||||
return (log2(sceneDepth * gridSliceParameters.x + gridSliceParameters.y) * gridSliceParameters.z);
|
return (log2(sceneDepth * gridSliceParameters.x + gridSliceParameters.y) * gridSliceParameters.z);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -47,8 +47,8 @@ uint MissedHistorySamplesCount;
|
|||||||
uint3 GridSizeInt;
|
uint3 GridSizeInt;
|
||||||
float PhaseG;
|
float PhaseG;
|
||||||
|
|
||||||
float2 Dummy0;
|
float2 VolumetricFogRange;
|
||||||
float VolumetricFogMaxDistance;
|
float Dummy0;
|
||||||
float InverseSquaredLightDistanceBiasScale;
|
float InverseSquaredLightDistanceBiasScale;
|
||||||
|
|
||||||
float4 FogParameters;
|
float4 FogParameters;
|
||||||
@@ -104,7 +104,8 @@ float3 GetVolumeUV(float3 worldPosition, float4x4 worldToClip)
|
|||||||
{
|
{
|
||||||
float4 ndcPosition = mul(float4(worldPosition, 1), worldToClip);
|
float4 ndcPosition = mul(float4(worldPosition, 1), worldToClip);
|
||||||
ndcPosition.xy /= ndcPosition.w;
|
ndcPosition.xy /= ndcPosition.w;
|
||||||
return float3(ndcPosition.xy * float2(0.5f, -0.5f) + 0.5f, ndcPosition.w / VolumetricFogMaxDistance);
|
ndcPosition.w = (ndcPosition.w - VolumetricFogRange.x) / VolumetricFogRange.y; // TODO: convert into MAD
|
||||||
|
return float3(ndcPosition.xy * float2(0.5f, -0.5f) + 0.5f, ndcPosition.w);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Vertex shader that writes to a range of slices of a volume texture
|
// Vertex shader that writes to a range of slices of a volume texture
|
||||||
@@ -340,7 +341,7 @@ void CS_FinalIntegration(uint3 DispatchThreadId : SV_DispatchThreadID)
|
|||||||
if (any(gridCoordinate.xy >= GridSizeInt.xy))
|
if (any(gridCoordinate.xy >= GridSizeInt.xy))
|
||||||
return;
|
return;
|
||||||
float4 acc = float4(0, 0, 0, 1);
|
float4 acc = float4(0, 0, 0, 1);
|
||||||
float3 prevPositionWS = GBuffer.ViewPos;
|
float3 prevPositionWS = GetCellPositionWS(uint3(gridCoordinate.xy, 0), 0.5f);
|
||||||
|
|
||||||
for (uint layerIndex = 0; layerIndex < GridSizeInt.z; layerIndex++)
|
for (uint layerIndex = 0; layerIndex < GridSizeInt.z; layerIndex++)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user