Problem with position reconstruction from depth

This is the output of my view positions, reconstructed from depth:

But, it looks incorrect, as it really should look like this:

Any idea what I’m doing wrong?

Trimmed code is here:

		v2f_ao vert_ao (appdata_full v)
		{
			v2f_ao o;
			o.pos = mul (UNITY_MATRIX_MVP, v.vertex); 
			o.uv = ComputeScreenPos (o.pos);
			o.ray = mul (UNITY_MATRIX_MV, v.vertex).xyz * float3(-1,-1,1);
			o.ray = lerp(o.ray, v.texcoord, v.texcoord.z != 0); 
			return o;
		} 

			inline float3 getPosition(in float2 uv, in float3 ray)
			{
			    float4 depthnormal = tex2D (_CameraDepthNormalsTexture, uv);
				float3 viewNorm;
				float depth;
				DecodeDepthNormal (depthnormal, depth, viewNorm);
				depth = Linear01Depth (depth);
				return ray * depth;
			}

			half4 frag (v2f_ao i) : COLOR
			{
				i.ray *= (_ProjectionParams.z / i.ray.z);
				float2 uv = i.uv.xy / i.uv.w;
				float3 viewPos = getPosition(uv,i.ray);
				return  float4(getPosition(uv,i.ray),1f);

Apparently the depth values are rendered in screen space. I just need to convert them to view space in order to reconstruct the view space position.

To calculate the view space position (from screen space), can I just multiply the depth value with the far clipping plane? I’m trying it but it doesn’t seem to be correct.

Ok I think this is correct:

depth = (zNear * zFar) / (zFar - depth * (zFar - zNear));

Now, how to get the inverse projection matrix?

Is there a builtin variable for that or do I have to calculate and set with SetGlobalMatrix?

I put this in update:

inverseProjection = camera.projectionMatrix.inverse;

And pass to the shader with SetGlobalMatrix.

So far, so good.

Ok I scrapped the ray frustum method and just used the reconstruction code in the Light Prepass shader.

Although there are a few bugs left, this is the result of an SSAO method I’m working on:

around 15-20 fps gain in performance over the default SSAO.

Cool, although it looks like you’re using a very tight sampling area, which makes it look more like an edge detection method than ambient occlusion. Also, it doesn’t look like you’re taking surface normals into account, which means that surfaces are essentially self-shadowing the more they point away from the camera.

That sounds good, but it’s a relative metric without a baseline. How many milliseconds per frame does your method take, vs. the built-in one in the same scene?

The solution does use view space normals however it appears to not use them correctly :b. The normals appear correctly when I output them directly, but I think there is an issue with the sampling space and / or the view space conversion.

How can I reliably measure the ms per frame? I know this is an important metric, but the Unity ms readout wasn’t giving me consistent results so I chose to use fraps enabling / disabling both shaders in a build.

*EDIT → removed most of the diagonal self shadowing artifacts: