Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: improve vanilla VL #569

Merged
merged 1 commit into from
Sep 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions package/Shaders/ISApplyVolumetricLighting.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,11 @@ PS_OUTPUT main(PS_INPUT input)
float depth = DepthTex.Sample(DepthSampler, screenPosition).x;
float repartition = clamp(RepartitionTex.SampleLevel(RepartitionSampler, depth, 0).x, 0, 0.9999);
float vl = g_IntensityX_TemporalY.x * VLTex.SampleLevel(VLSampler, float3(input.TexCoord, repartition), 0).x;
float multipleScattering = vl * (1.0 + vl * (0.5 + vl * 0.25));

float noiseGrad = 0.03125 * NoiseGradSamplerTex.Sample(NoiseGradSamplerSampler, 0.125 * input.Position.xy).x;

float adjustedVl = noiseGrad + vl - 0.0078125;
float adjustedVl = noiseGrad + multipleScattering - 0.0078125;

if (0.001 < g_IntensityX_TemporalY.y) {
float2 motionVector = MotionVectorsTex.Sample(MotionVectorsSampler, screenPosition).xy;
Expand All @@ -50,12 +51,11 @@ PS_OUTPUT main(PS_INPUT input)
float previousVl = PreviousFrameTex.Sample(PreviousFrameSampler, previousScreenPosition).x;
float previousDepth = PreviousDepthTex.Sample(PreviousDepthSampler, previousScreenPosition).x;

float temporalContribution = g_IntensityX_TemporalY.y * (1 - smoothstep(0, 1, min(1, 100 * abs(depth - previousDepth))));
float depthDifference = abs(depth - previousDepth);
float temporalContribution = saturate(g_IntensityX_TemporalY.y * exp(-depthDifference * 100.0));
temporalContribution *= saturate(1.0 - length(motionVector) * 10.0);

float isValid = 0;
if (previousTexCoord.x >= 0 && previousTexCoord.x < 1 && previousTexCoord.y >= 0 && previousTexCoord.y < 1) {
isValid = 1;
}
float isValid = (previousTexCoord.x >= 0 && previousTexCoord.x < 1 && previousTexCoord.y >= 0 && previousTexCoord.y < 1);
psout.VL = lerp(adjustedVl, previousVl, temporalContribution * isValid);
} else {
psout.VL = adjustedVl;
Expand Down
71 changes: 69 additions & 2 deletions package/Shaders/ISVolumetricLightingGenerateCS.hlsl
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "Common/Constants.hlsli"
#include "Common/Random.hlsli"

#if defined(CSHADER)
SamplerState ShadowmapSampler : register(s0);
Expand Down Expand Up @@ -33,6 +34,69 @@ cbuffer PerTechnique : register(b0)
float DensityContribution : packoffset(c23.z);
}

/**
* @brief Computes the Schlick phase function for approximating scattering.
*
* The Schlick phase function is a simplified approximation of the Henyey-Greenstein phase function.
* It provides a computationally efficient way to model anisotropic scattering effects in real-time applications.
*
* @param cosTheta The cosine of the scattering angle (cosine of the angle between the light and the view direction).
* @param g The anisotropy factor (-1 for full backward scattering, 1 for full forward scattering, and 0 for isotropic).
* @return The Schlick phase function value for the given parameters.
*
* @note Performance vs Quality:
* - Schlick is a faster approximation compared to Henyey-Greenstein because it avoids the expensive power operations.
* - It provides visually similar results but sacrifices some accuracy, especially for complex anisotropic scattering.
* - Ideal for real-time rendering where performance is critical, such as games (default for Skyrim).
*/
float SchlickPhase(float cosTheta, float g)
{
float k = (1 - g * g) / (4 * M_PI * pow(1 + g * cosTheta, 2));
return k;
}

/**
* @brief Computes the Henyey-Greenstein phase function for scattering.
*
* The Henyey-Greenstein phase function is a widely used model for simulating light scattering in participating media.
* It accurately models the anisotropy of light scattering, providing good realism for both forward and backward scattering.
*
* @param cosTheta The cosine of the scattering angle (cosine of the angle between the light and the view direction).
* @param g The anisotropy factor (-1 for full backward scattering, 1 for full forward scattering, and 0 for isotropic).
* @return The Henyey-Greenstein phase function value for the given parameters.
*
* @note Performance vs Quality:
* - More computationally expensive than Schlick due to the use of power operations.
* - Offers a more physically accurate representation of scattering, particularly for media with pronounced forward or backward scattering behavior.
* - Suitable for applications where visual fidelity is more important than real-time performance.
*/
float HenyeyGreensteinPhase(float cosTheta, float g)
{
float g2 = g * g;
return (1.0 - g2) / (4.0 * M_PI * pow(1.0 + g2 - 2.0 * g * cosTheta, 1.5));
}

/**
* @brief Computes the Mie phase function for light scattering.
*
* The Mie phase function models the scattering of light by larger particles, such as water droplets or fog.
* It is more complex than the Henyey-Greenstein phase function and is often used to model more realistic atmospheric effects.
*
* @param cosTheta The cosine of the scattering angle (cosine of the angle between the light and the view direction).
* @param g The anisotropy factor (-1 for full backward scattering, 1 for full forward scattering, and 0 for isotropic).
* @return The Mie phase function value for the given parameters.
*
* @note Performance vs Quality:
* - More computationally expensive than both Schlick and Henyey-Greenstein due to the complex denominator and power operations.
* - Produces the most physically accurate results, especially for scenes involving larger particles such as clouds or fog.
* - Best suited for high-fidelity rendering applications, but might be too slow for real-time gaming without optimization.
*/
float MiePhase(float cosTheta, float g)
FlayaN marked this conversation as resolved.
Show resolved Hide resolved
{
float denom = pow(1 + g * g - 2 * g * cosTheta, 1.5);
return (1.0 / (4.0 * M_PI)) * (1 + cosTheta * cosTheta) / denom;
}

[numthreads(32, 32, 1)] void main(uint3 dispatchID
: SV_DispatchThreadID) {
const float3 StepCoefficients[] = { { 0, 0, 0 },
Expand All @@ -46,7 +110,7 @@ cbuffer PerTechnique : register(b0)

float3 depthUv = dispatchID.xyz / TextureDimensions.xyz + 0.001 * StepCoefficients[IterationIndex].xyz;
float depth = InverseRepartitionTex.SampleLevel(InverseRepartitionSampler, depthUv.z, 0).x;
float4 positionCS = float4(2 * depthUv.x - 1, 1 - 2 * depthUv.y, depth, 1);
float4 positionCS = float4(2 * depthUv.x - 1, 1 - 2 * depthUv.y, depth, 1); // UVDepthToView(depthUv)
FlayaN marked this conversation as resolved.
Show resolved Hide resolved

float4 positionWS = mul(transpose(CameraViewProjInverse), positionCS);
positionWS /= positionWS.w;
Expand Down Expand Up @@ -97,11 +161,14 @@ cbuffer PerTechnique : register(b0)

float3 noiseUv = 0.0125 * (InverseDensityScale * (positionWS.xyz + WindInput));
float noise = NoiseTex.SampleLevel(NoiseSampler, noiseUv, 0).x;
noise = lerp(noise, InterleavedGradientNoise(positionWS.xy), 0.5);
float densityFactor = noise * (1 - 0.75 * smoothstep(0, 1, saturate(2 * positionWS.z / 300)));
float densityContribution = lerp(1, densityFactor, DensityContribution);

float LdotN = dot(normalize(-positionWS.xyz), normalize(DirLightDirection));
float phaseFactor = (1 - PhaseScattering * PhaseScattering) / (4 * M_PI * (1 - LdotN * PhaseScattering));
float forwardPhase = SchlickPhase(LdotN, PhaseScattering);
float backwardPhase = SchlickPhase(LdotN, -PhaseScattering * 0.5);
float phaseFactor = lerp(forwardPhase, backwardPhase, 0.5);
float phaseContribution = lerp(1, phaseFactor, PhaseContribution);

float vl = shadowContribution * densityContribution * phaseContribution;
Expand Down
8 changes: 7 additions & 1 deletion package/Shaders/ISVolumetricLightingRaymarchCS.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ cbuffer PerTechnique : register(b0)

float3 position = (0.5 + float3(dispatchID.xy, StepIndex)) / TextureDimensions.xyz;
float density = DensityTex.SampleLevel(DensitySampler, position, 0).x;
DensityRW[uint3(dispatchID.xy, StepIndex)] = previousDensity + density;
// Adaptive step size
float stepSize = 1.0 / TextureDimensions.z;
float gradient = abs(density - previousDensity);
float adaptiveStepSize = stepSize * lerp(1.0, 2.0, saturate(gradient * 10.0));

float transmittance = exp(-density * adaptiveStepSize);
DensityRW[uint3(dispatchID.xy, StepIndex)] = previousDensity + density * (1.0 - transmittance) / max(density, 1e-5);
}
#endif
Loading