Sign in to follow this  
Daganar

Volumetric Lighting Acne/Aliasing Issues.

Recommended Posts

Hi guys,

So I'm working on some volumetric lighting effects using the ray marching method. I seem to have it nearly nailed, the way this works is I render my entire scene, then I render a fullscreen quad which takes the scene render target as an input as well as shadow maps which then ray marches for N samples for each pixel and accumulates the scattering along that ray, lastly it adds it on top of the scene render. My issue is however I get some bad acne/aliasing issues.. I've narrowed it down to the scattering equation inputs, I believe I'm incorrectly computing the angle needed for the scattering phase function. Here is the issue I'm seeing (enjoy the hot pink): 

ZJZ43fN.jpg

Here is my HLSL code for this:

float ComputeScattering( float fCos )
{
	float g = -0.94f;
	float g2 = g*g;

	float fCos2 = fCos * fCos;

	float result = 1.5f * ( ( 1.0f - g2 ) / ( 2.0f + g2 ) ) * ( 1.0f * fCos2 ) / pow( abs( 1.0f + g2 - 2.0f * g * fCos ), 1.5f );

	return result;
}

float3 CalculatePosition( float depth, float2 uv )
{
	float x = uv.x * 2 - 1;
	float y = ( 1 - uv.y ) * 2 - 1;
	float4 vProjectedPos = float4( x, y, depth, 1.0f );
	float4 vPositionVS = mul( vProjectedPos, matInvViewProj );
	return vPositionVS.xyz / vPositionVS.w;
}

float4 PSMain( PSInput input ) : SV_TARGET
{
	// Sample scene colour.
	float4 diffuseColour = diffuseTexture.Sample(diffuseSampler, input.uv);

	// Reconstruct world position from depth.
	float worldDepth = depthTexture.Sample( diffuseSampler, input.uv );
	float shadowTex = shadowTexture.Sample( diffuseSampler, input.uv );
	float3 worldPos = CalculatePosition( worldDepth, input.uv );

	// Calculate ray from world pos -> eye 
	float3 rayVector = eyePos.xyz - worldPos.xyz;
	float rayLength = length( rayVector );
	float3 rayDirection = rayVector / rayLength;

	// Calculate step
	float stepLength = rayLength / NUM_SAMPLES;
	float3 step = rayDirection * stepLength;
	
	
	float3 lightVec = float3( 0.1f, 1.0f, 0.0f );
	float4 lightCol = float4( 1.0f, 0.0f, 1.0f, 1.0f );


	float3 accumFog = float3( 0.0f, 0.0f, 0.0f );
	float3 currentPosition = worldPos.xyz;
	
	// Ray March 
	[loop]
	for( int i = 0; i < NUM_SAMPLES; i++ )
	{
		// Advance.
		currentPosition += step;

		// Shadow mapping test.
		float4 shadowPos = mul( float4( currentPosition.xyz, 1.0f ), matShadow );
		float2 shadowCoord;
		shadowCoord.x = shadowPos.x / shadowPos.w / 2.0f + 0.5f;
		shadowCoord.y = -shadowPos.y / shadowPos.w / 2.0f + 0.5f;

		float bias = 0.002f;
		float shadowDepth = ( shadowPos.z / shadowPos.w ) - bias;
		float shadow = shadowTexture.Sample( diffuseSampler, shadowCoord.xy );

		// Check if in shadow.
		if( shadow > shadowDepth )
		{
			// Calculate scattering.
			float d = dot( ( currentPosition ), normalize( rayDirection ) );
			float3 scattering = lightCol * ComputeScattering( d );

			// Accumulate
			accumFog += scattering;
		}

	}

	accumFog /= NUM_SAMPLES;

	// Combine.
	return( diffuseColour + float4( accumFog, 1.0f ) );
}

At first this seemed very familiar to shadow acne, but removing the shadow map test produces the same results, I believe it's down to this line:

float d = dot( ( currentPosition ), normalize( rayDirection ) );

Any advice would be greatly appreciated, thanks.

 

Share this post


Link to post
Share on other sites

Just as an update: I've narrowed it down exactly to the phase function, if I use the isotropic phase function:

1.0 / 4.0 * PI 

I get correct scattering. After a bit of shader debugging with the Henyey-Greenstein phase function it turns out that the dot product I am doing is causing the phase function to produce NaN results:

float d = dot( ( currentPosition ), normalize( rayDirection ) );

Is producing NaN results.. does any one know the correct vectors I should be using here? I can't find much info on this, thanks.

 

EDIT:

Here is my latest Henyey-Greenstein phase function:

float result = ( 1.0f - g2 ) / pow( 4.0f * M_PI * 1.0f + g2 - 2.0f * g * fCos, 1.5f );
Edited by Daganar

Share this post


Link to post
Share on other sites
I guess what's happening is that in the final step the ray is so close to the surface that the shadow test fails. (The artefacts show off only in shadowed regions)

Not sure what's the best way to fix it butn something like step = rayDirection * stepLength * 0.98;

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this