Jump to content
  • Advertisement
Sign in to follow this  
Anfaenger

DX11 Voxelization (VCT GI) - Handing out-of-bounds writes

Recommended Posts

Posted (edited)

I'm implementing single-pass surface voxelization (via Geometry Shader) for Voxel Cone Tracing (VCT),

and after some debugging I've discovered that I have to insert out-of-bounds checks into the pixel shader to avoid voxelizing geometry which is outside the voxel grid:

 

void main_PS_VoxelTerrain_DLoD( VSOutput pixelInput )
{
	const float3 posInVoxelGrid =
		(pixelInput.position_world - g_vxgi_voxel_radiance_grid_min_corner_world) * g_vxgi_inverse_voxel_size_world;

	const uint color_encoded = packR8G8B8A8( float4( posInVoxelGrid, 1 ) );

	const int3 writecoord = (int3) floor( posInVoxelGrid );

	const uint writeIndex1D = flattenIndex3D( (uint3)writecoord, (uint3)g_vxgi_voxel_radiance_grid_resolution_int );

	// HACK:
	bool inBounds =
		writecoord.x >= 0 && writecoord.x < g_vxgi_voxel_radiance_grid_resolution_int &&
		writecoord.y >= 0 && writecoord.y < g_vxgi_voxel_radiance_grid_resolution_int &&
		writecoord.z >= 0 && writecoord.z < g_vxgi_voxel_radiance_grid_resolution_int ;

	if( inBounds )
	{
		rwsb_voxelGrid[writeIndex1D] = color_encoded;
	}
	else
	{
		rwsb_voxelGrid[writeIndex1D] = 0xFF0000FF; //RED, ALPHA
	}
}

 

Why is this check needed, and how can I avoid it? Shouldn't Direct3D automatically clip the pixels falling outside the viewport? (I tried to ensure that out-of-bounds pixels are clipped in the geometry shader and I also enable depthClip in rasterizer, but it doesn't work.)

Here's a picture illustrating the problem (extraneous voxels are highlighted with red):

Spoiler

1749378791_voxelizationerrors.png.732787c796e05670b3b69a4b6243a4b7.png

And here the full HLSL code of the voxelization shader:

Spoiler

 


int maxIndex3( in float3 v )
{
	return ( v.x > v.y )
		? ( ( v.x > v.z ) ? 0 : 2 )
		: ( ( v.y > v.z ) ? 1 : 2 );
}

cbuffer Uniforms
{
	row_major float4x4	u_local_to_world_space;
};

RWStructuredBuffer< uint >	rwsb_voxelGrid;

//-----------------------------------------------------------------------------

struct VSOutput
{
	float3 position_world : Position;	// world-space position
	float3 normalWS : Normal0;	// world-space normal
};

VSOutput main_VS_VoxelTerrain_DLoD( in Vertex_DLOD vertexInput )
{
	VSOutput	vertexOutput;
	vertexOutput.position_world = mul( u_local_to_world_space, float4( vertexInput.localPosition, 1.0f ) ).xyz;
	vertexOutput.normalWS = Dir_Local_To_World( vertexInput.localNormal );
	return vertexOutput;
}

//-----------------------------------------------------------------------------

struct GSOutput
{
  	float4 positionNDC : SV_Position;	// clip-space position
	float3 position_world : Position;	// world-space position
	float3 normalWS : Normal0;	// world-space normal
};

[maxvertexcount(3)]
void main_GS(
	triangle VSOutput input[3],
	inout TriangleStream< GSOutput > outputStream
)
{
	// Calculate the dominant direction of the surface normal.
	const int axis = maxIndex3( abs( input[0].normalWS + input[1].normalWS + input[2].normalWS ) );
	
	// Project the triangle in the dominant direction for rasterization,
	// but not for lighting.
	[unroll]
	for( uint i = 0; i < 3; i++ )
	{
		GSOutput	output;

		output.position_world = input[i].position_world;
		
		const float3 position01_in_voxel_grid =
			((input[i].position_world - g_vxgi_voxel_radiance_grid_min_corner_world) * g_vxgi_inverse_voxel_size_world) * g_vxgi_voxel_radiance_grid_inverse_resolution;
	
		output.positionNDC.xyz = position01_in_voxel_grid * 2 - 1;

		[flatten]
		switch (axis) {
		case 0:
			output.positionNDC.xy = output.positionNDC.yz;
			break;
		case 1:
			output.positionNDC.xy = output.positionNDC.zx;
			break;
		default:
			break;
		}

		output.positionNDC.zw = 1;
		
		output.normalWS = input[i].normalWS;
		
		outputStream.Append(output);
	}

  	outputStream.RestartStrip();
}

//-----------------------------------------------------------------------------

void main_PS_VoxelTerrain_DLoD( VSOutput pixelInput )
{
	const float3 posInVoxelGrid =
		(pixelInput.position_world - g_vxgi_voxel_radiance_grid_min_corner_world) * g_vxgi_inverse_voxel_size_world;

	const uint color_encoded = packR8G8B8A8( float4( posInVoxelGrid, 1 ) );

	const int3 writecoord = (int3) floor( posInVoxelGrid );

	const uint writeIndex1D = flattenIndex3D( (uint3)writecoord, (uint3)g_vxgi_voxel_radiance_grid_resolution_int );

	// HACK:
	bool inBounds =
		writecoord.x >= 0 && writecoord.x < g_vxgi_voxel_radiance_grid_resolution_int &&
		writecoord.y >= 0 && writecoord.y < g_vxgi_voxel_radiance_grid_resolution_int &&
		writecoord.z >= 0 && writecoord.z < g_vxgi_voxel_radiance_grid_resolution_int ;

	if( inBounds )
	{
		rwsb_voxelGrid[writeIndex1D] = color_encoded;
	}
	else
	{
		rwsb_voxelGrid[writeIndex1D] = 0xFF0000FF; //RED, ALPHA
	}
}

 

Edited by Anfaenger
fix spoiler headers - move them out of spoilers

Share this post


Link to post
Share on other sites
Advertisement

You will only get pixel shader executions for pixels that lie within your specified viewport. With your current method you're not going to get any clipping along the Z axis in NDC space, since you're forcing z = w = 1. I would try setting w to 1.0, and outputting a proper value for Z instead of forcing it to 1 (keep in mind that Z is [0, 1] in NDC space, unlike X and Y which are [-1, 1]. So basically you'll want to generate Z by swizzling just like you're doing for X and Y, but then do Z = Z * 0.5 + 0.5 to get it to the [0, 1] range.

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  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!