Fix fog to draw Fog Cutoff Distance via a plane, not sphere test
Add support for negative Fog Cutoff Distance on fog to draw it in front of the camera Far Plane, no matter the setup. Fix hot-reloading Fog shader in Editor.
This commit is contained in:
@@ -151,7 +151,7 @@ void PS_Forward(
|
||||
|
||||
#if USE_FOG
|
||||
// Calculate exponential height fog
|
||||
float4 fog = GetExponentialHeightFog(ExponentialHeightFog, materialInput.WorldPosition, ViewPos, 0);
|
||||
float4 fog = GetExponentialHeightFog(ExponentialHeightFog, materialInput.WorldPosition, ViewPos, 0, gBuffer.ViewPos.z);
|
||||
|
||||
// Apply fog to the output color
|
||||
#if MATERIAL_BLEND == MATERIAL_BLEND_OPAQUE
|
||||
|
||||
BIN
Content/Editor/Particles/Smoke Material.flax
(Stored with Git LFS)
BIN
Content/Editor/Particles/Smoke Material.flax
(Stored with Git LFS)
Binary file not shown.
BIN
Content/Shaders/Fog.flax
(Stored with Git LFS)
BIN
Content/Shaders/Fog.flax
(Stored with Git LFS)
Binary file not shown.
@@ -41,11 +41,10 @@ void ExponentialHeightFog::Draw(RenderContext& renderContext)
|
||||
&& _shader->IsLoaded()
|
||||
&& renderContext.View.IsPerspectiveProjection())
|
||||
{
|
||||
// Prepare
|
||||
if (_psFog.States[0] == nullptr)
|
||||
{
|
||||
// Create pipeline states
|
||||
_psFog.CreatePipelineStates();
|
||||
if (!_psFog.States[0]->IsValid())
|
||||
{
|
||||
GPUPipelineState::Description psDesc = GPUPipelineState::Description::DefaultFullscreenTriangle;
|
||||
psDesc.DepthWriteEnable = false;
|
||||
psDesc.BlendMode.BlendEnable = true;
|
||||
@@ -59,6 +58,7 @@ void ExponentialHeightFog::Draw(RenderContext& renderContext)
|
||||
if (_psFog.Create(psDesc, _shader->GetShader(), "PS_Fog"))
|
||||
{
|
||||
LOG(Warning, "Cannot create graphics pipeline state object for '{0}'.", ToString());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -160,7 +160,7 @@ void ExponentialHeightFog::GetExponentialHeightFogData(const RenderView& view, S
|
||||
result.FogAtViewPosition = density * Math::Pow(2.0f, Math::Clamp(-heightFalloff * (viewHeight - height), -125.f, 126.f));
|
||||
result.StartDistance = StartDistance;
|
||||
result.FogMinOpacity = 1.0f - FogMaxOpacity;
|
||||
result.FogCutoffDistance = FogCutoffDistance;
|
||||
result.FogCutoffDistance = FogCutoffDistance >= 0 ? FogCutoffDistance : view.Far + FogCutoffDistance;
|
||||
if (useDirectionalLightInscattering)
|
||||
{
|
||||
result.InscatteringLightDirection = -DirectionalInscatteringLight->GetDirection();
|
||||
|
||||
@@ -55,9 +55,9 @@ public:
|
||||
float StartDistance = 0.0f;
|
||||
|
||||
/// <summary>
|
||||
/// Scene elements past this distance will not have fog applied. This is useful for excluding skyboxes which already have fog baked in. Setting this value to 0 disables it.
|
||||
/// Scene elements past this distance will not have fog applied. This is useful for excluding skyboxes which already have fog baked in. Setting this value to 0 disables it. Negative value sets the cutoff distance relative to the far plane of the camera.
|
||||
/// </summary>
|
||||
API_FIELD(Attributes="EditorOrder(60), DefaultValue(0.0f), Limit(0), EditorDisplay(\"Exponential Height Fog\")")
|
||||
API_FIELD(Attributes="EditorOrder(60), DefaultValue(0.0f), EditorDisplay(\"Exponential Height Fog\")")
|
||||
float FogCutoffDistance = 0.0f;
|
||||
|
||||
public:
|
||||
|
||||
@@ -29,7 +29,7 @@ struct ExponentialHeightFogData
|
||||
float StartDistance;
|
||||
};
|
||||
|
||||
float4 GetExponentialHeightFog(ExponentialHeightFogData exponentialHeightFog, float3 posWS, float3 camWS, float skipDistance)
|
||||
float4 GetExponentialHeightFog(ExponentialHeightFogData exponentialHeightFog, float3 posWS, float3 camWS, float skipDistance, float sceneDistance)
|
||||
{
|
||||
float3 cameraToPos = posWS - camWS;
|
||||
float cameraToPosSqr = dot(cameraToPos, cameraToPos);
|
||||
@@ -78,7 +78,7 @@ float4 GetExponentialHeightFog(ExponentialHeightFogData exponentialHeightFog, fl
|
||||
|
||||
// Disable fog after a certain distance
|
||||
FLATTEN
|
||||
if (exponentialHeightFog.FogCutoffDistance > 0 && cameraToPosLen > exponentialHeightFog.FogCutoffDistance)
|
||||
if (exponentialHeightFog.FogCutoffDistance > 0 && sceneDistance > exponentialHeightFog.FogCutoffDistance)
|
||||
{
|
||||
expFogFactor = 1;
|
||||
directionalInscattering = 0;
|
||||
@@ -87,4 +87,9 @@ float4 GetExponentialHeightFog(ExponentialHeightFogData exponentialHeightFog, fl
|
||||
return float4(inscatteringColor * (1.0f - expFogFactor) + directionalInscattering, expFogFactor);
|
||||
}
|
||||
|
||||
float4 GetExponentialHeightFog(ExponentialHeightFogData exponentialHeightFog, float3 posWS, float3 camWS, float skipDistance)
|
||||
{
|
||||
return GetExponentialHeightFog(exponentialHeightFog, posWS, camWS, skipDistance, distance(posWS, camWS));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -24,41 +24,17 @@ Texture2D Depth : register(t0);
|
||||
Texture3D IntegratedLightScattering : register(t1);
|
||||
#endif
|
||||
|
||||
// Get world space position at given pixel coordinate
|
||||
float3 GetWorldPos(float2 uv)
|
||||
{
|
||||
float depth = SAMPLE_RT(Depth, uv).r;
|
||||
GBufferData gBufferData = GetGBufferData();
|
||||
float3 viewPos = GetViewPos(gBufferData, uv, depth);
|
||||
return mul(float4(viewPos, 1), gBufferData.InvViewMatrix).xyz;
|
||||
}
|
||||
|
||||
float4 CalculateCombinedFog(float3 posWS, float sceneDepth, float3 volumeUV)
|
||||
{
|
||||
float skipDistance = 0;
|
||||
|
||||
#if VOLUMETRIC_FOG
|
||||
skipDistance = max(ExponentialHeightFog.VolumetricFogMaxDistance - 100, 0);
|
||||
#endif
|
||||
|
||||
float4 fog = GetExponentialHeightFog(ExponentialHeightFog, posWS, GBuffer.ViewPos, skipDistance);
|
||||
|
||||
#if VOLUMETRIC_FOG
|
||||
float4 volumetricFog = IntegratedLightScattering.SampleLevel(SamplerLinearClamp, volumeUV, 0);
|
||||
fog = float4(volumetricFog.rgb + fog.rgb * volumetricFog.a, volumetricFog.a * fog.a);
|
||||
#endif
|
||||
|
||||
return fog;
|
||||
}
|
||||
|
||||
META_PS(true, FEATURE_LEVEL_ES2)
|
||||
META_PERMUTATION_1(VOLUMETRIC_FOG=0)
|
||||
META_PERMUTATION_1(VOLUMETRIC_FOG=1)
|
||||
float4 PS_Fog(Quad_VS2PS input) : SV_Target0
|
||||
{
|
||||
// Calculate pixel world space position
|
||||
float3 posWS = GetWorldPos(input.TexCoord);
|
||||
float3 viewVector = posWS - GBuffer.ViewPos;
|
||||
// Get world space position at given pixel coordinate
|
||||
float rawDepth = SAMPLE_RT(Depth, input.TexCoord).r;
|
||||
GBufferData gBufferData = GetGBufferData();
|
||||
float3 viewPos = GetViewPos(gBufferData, input.TexCoord, rawDepth);
|
||||
float3 worldPos = mul(float4(viewPos, 1), gBufferData.InvViewMatrix).xyz;
|
||||
float3 viewVector = worldPos - GBuffer.ViewPos;
|
||||
float sceneDepth = length(viewVector);
|
||||
|
||||
// Calculate volumetric fog coordinates
|
||||
@@ -67,17 +43,28 @@ float4 PS_Fog(Quad_VS2PS input) : SV_Target0
|
||||
|
||||
// Debug code
|
||||
#if VOLUMETRIC_FOG && 0
|
||||
volumeUV = posWS / 1000;
|
||||
volumeUV = worldPos / 1000;
|
||||
if (!all(volumeUV >= 0 && volumeUV <= 1))
|
||||
return 0;
|
||||
|
||||
return float4(IntegratedLightScattering.SampleLevel(SamplerLinearClamp, volumeUV, 0).rgb, 1);
|
||||
//return float4(volumeUV, 1);
|
||||
//return float4(posWS / 100, 1);
|
||||
//return float4(worldPos / 100, 1);
|
||||
#endif
|
||||
|
||||
// Calculate fog color
|
||||
float4 fog = CalculateCombinedFog(posWS, sceneDepth, volumeUV);
|
||||
float skipDistance = 0;
|
||||
#if VOLUMETRIC_FOG
|
||||
skipDistance = max(ExponentialHeightFog.VolumetricFogMaxDistance - 100, 0);
|
||||
#endif
|
||||
|
||||
// Calculate exponential fog color
|
||||
float4 fog = GetExponentialHeightFog(ExponentialHeightFog, worldPos, GBuffer.ViewPos, skipDistance, viewPos.z);
|
||||
|
||||
#if VOLUMETRIC_FOG
|
||||
// Sample volumetric fog and mix it in
|
||||
float4 volumetricFog = IntegratedLightScattering.SampleLevel(SamplerLinearClamp, volumeUV, 0);
|
||||
fog = float4(volumetricFog.rgb + fog.rgb * volumetricFog.a, volumetricFog.a * fog.a);
|
||||
#endif
|
||||
|
||||
return fog;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user