Skip to main content
GameDev.net gamedev.net
🔒 Locked

Reconstructing position from depth

Started by Viik Dec 13, 2008 at 8:26 AM 3 replies 1.2k views
Original Post
Viik
Viik
Used Reconstructing pixel 3D position from depth as a reference. Trying to reconstruct position as MJP proposed - using frustum corner and linear depth. No luck so far. This is what kind of problem I have now: Direct output and reconstruction comparison On the left is a direct output of WorldView transformation, on the right is a reconstructed view position, as you can see they don't match. Depth generation:

Vertex shader
   output.clip_pos_depth = mul(input.pos, WorldView);

Pixel shader
   float d = input.clip_pos_depth.z;



Position reconstruction:

float4 main_ps(in_ps input, float2 screenPos :VPOS) : COLOR
{
	float2	coord = screenPos * pixel_size;
  		coord += pixel_size * 0.5;

	float4 	pos_depth = tex2D(positionDepth_sampler, coord);

	float	depth = pos_depth.a / farClippingPlane; // 1000 is a test value

	float3	ViewDir;
		ViewDir.x = lerp(-corner_position.x, corner_position.x, coord.x);	
                ViewDir.y = lerp(corner_position.y, -corner_position.y, coord.y);	
                ViewDir.z = corner_position.z;

	float3	position = ViewDir * depth;
			
	return float4(position.xyz,1);

}



corner_position is a top right corner of frustum. Was calculated this way: farH = 2 * tan(fov/2) * farClip farW = farH * aspect_ratio farX = farW/2 farY = farH/2 corner_position = (farX, farY, farClip)
MJP
MJP
Hi Viik.

It looks like you're pretty close to the correct results...it might even just be a precision issue (although that's not really what it looks like in the picture). Are you storing depth in 32-bit floating point surface? I believe you get better precision for that format if you divide the depth by the distance to your far-clip plane before outputting it (you'd also get slightly better precision than that by adjusting it to use the range [-1,1] so that you make use of the sign bit).

If that's not it I'm not sure what the issue would be...everything else you posted looks okay. I'll post the code I currently use, in case it helps...

Depth generation:
VertexShaderOutput VS(VertexShaderInput input, float4x4 matWorld, float4 vInstanceData){	VertexShaderOutput output;		// Pull out the instance data;	float4 vScale = float4(vInstanceData.xyz, 1.0f);		// Figure out the position of the vertex in view space and clip space	float4x4 matWorldView = mul(matWorld, g_matView);	float4 vPositionVS = mul(input.vPositionOS * vScale, matWorldView);        output.vPositionCS = mul(vPositionVS, g_matProj);	output.fDepth = vPositionVS.z;		return output;}float4 PS(VertexShaderOutput input) : COLOR0{	// Negate and divide by distance to far clip (XNA uses right-handed coordinates, so Z will be negative)	float fDepth = -input.fDepth/g_fFarClip;        return float4(fDepth, 1.0f, 1.0f, 1.0f);}


Reconstruction for a full-screen quad:
float3	g_vFrustumCornersVS [4];float2	g_vSourceDimensions;float2	g_vDestinationDimensions;void VS ( in float3 in_vPositionOS	: POSITION,	  in float3 in_vTexCoord	: TEXCOORD0,		  out float4 out_vPositionCS	: POSITION,	  out float2 out_vTexCoord	: TEXCOORD0,	  out float3 out_vFrustumPlaneVS	: TEXCOORD1	){	out_vPositionCS.x = in_vPositionOS.x - (1.0f / g_vDestinationDimensions.x);	out_vPositionCS.y = in_vPositionOS.y + (1.0f / g_vDestinationDimensions.y);	out_vPositionCS.z = in_vPositionOS.z;	out_vPositionCS.w = 1.0f;	out_vTexCoord = in_vTexCoord.xy;	out_vFrustumPlaneVS = g_vFrustumCornersVS[in_vTexCoord.z];}float4 PS( in float2 in_vTexCoord	: TEXCOORD0,	   in float3 in_vFrustumPlaneVS	: TEXCOORD1 )	: COLOR0{	// Reconstruct eye-space position from the depth buffer	float fPixelDepth = tex2D(depthTextureSampler, in_vTexCoord).r;	float4 vPositionVS = float4(fPixelDepth * in_vFrustumPlaneVS, 1.0f);        ...}

Viik
Viik
Thank you! I'll look at code, maybe i'm missing something. I'm using 32 bits and scaling depth to 0..1 after reading it from texture, so there should be no precision issue, it give the same result if I render depth/farclip plane or if it done later after reading.
It looks like mismatch starts where linear depth is bigger than 1.
Viik
Viik
It looks like I found a bug, fov value was not right, engine that i'm using dosnt use fov value explicitely and it's need to be calculated, this is where it went wrong.
Viik
Viik
Issue solved in view space it works ok. Now to restore a world space position i'm calculating four corners of frustum in world space by multiplying each of them by inverse view matrix, so I get four vectors that need to be interpolated. But how I can do it if i'm not using a full screen quad as in MJP example? In my case current pixel coordinate is known, for view space simple lerp would do the trick, but in world space frustum corners have completely different coordinates.
To summarize question - How coordinates of four frusutm corners can be interpolated using screen pixel coordinate?
I'm using light primitives and not a full screen quad.

[Edited by - Viik on December 15, 2008 1:37:20 AM]

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.