Reconstructing world pos from depth, imprecision?

Hi,

I’m trying to reconstruct world position from depth buffer in post process (image effect). This pos is later used to map a texture (based on xz plane of world pos). It looks like it is very imprecise, is that normal (reconstructed pos floating around when rotating camera)?

I’m using GPU Gems 3 method: http://http.developer.nvidia.com/GPUGems3/gpugems3_ch27.html

float depth = tex2D (_CameraDepthTexture, i.uv);
			
// scale it to -1..1 (screen coordinates)
float2 projectedXY = float2( i.uv)*2-1;
				
//unproject to world space
float4 H = float4(projectedXY, depth, 1);
float4 D = mul(_ViewProjectionInverseMatrix,H);
float4 worldPos = D / D.w;

I’m pretty new to unity and cannot find any real documentation on what type of render buffer it is using (linear, logarithmic, etc.), whether it is configurable (f32 texture for example) + there are tons of undocumented internal shaderLab related methods in examples.

Should I linearize it (Linear01Depth)? That doesn’t seem to work.

Inverse matrix is passed from script like this:

material.SetMatrix("_ViewProjectionInverseMatrix",(m_cam.projectionMatrix*m_cam.worldToCameraMatrix).inverse)

Results look like this (pseudo colorizing with overlay based on reconstructed world pos: float4(worldPos.x,0,worldPos.z,1) :

but they deviate too much with camera strafe, and rotation… So I’m curious if anyone had problems like this and whether it is related with some imprecision issue of depth buffer/reconstruction.

Camera is perspective, near 2, far 100, fow 60.

Ive been struggling with the same issue, it turns out this solved it:

//main problem encountered is camera.projectionMatrix = ??????? worked but further from camera became more inaccurate
//had to use GL.GetGPUProjectionMatrix( ) seems to stay pretty exact now

//in script somewhere:
Matrix4x4 viewMat = camera.worldToCameraMatrix;
Matrix4x4 projMat = GL.GetGPUProjectionMatrix( camera.projectionMatrix, false );
Matrix4x4 viewProjMat = (projMat * viewMat);          
Shader.SetGlobalMatrix("_ViewProjInv", viewProjMat.inverse);

//in fragment shader:
uniform float4x4 _ViewProjInv;
float4 GetWorldPositionFromDepth( float2 uv_depth )
{     
        float depth = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, uv_depth);
        float4 H = float4(uv_depth.x*2.0-1.0, (uv_depth.y)*2.0-1.0, depth, 1.0);
        float4 D = mul(_ViewProjInv,H);
        return D/D.w;
}
5 Likes