How to normalise the SceneDepth

I am following this video tutorial but I’m struggling to get the effect I want/understand what is going on. My primary question related to the SceneDepth node. In the documentation, there is a cryptic remark:

"SceneDepth returns a raw depth value (integer from 0 to 2^24-1). This non-linear depth can be normalized"

Quite aside from what the raw depth value means, there must be either a flaw in my understanding or an error in the equation since, the equation to normalize it (again, not clear what range we are normalising under, the max draw distance?)

MaxZ = 16777215
NormalizedDepth = 1 - MaxZ / (SceneDepth + MaxZ)

Under this transformation, if SceneDepth is in range [0, 2^24-1 = 16777215] the top of the fraction is = -16777214 < 0 and the bottom is x + 16777215 > 0. Therefore the result will be < 0. However, the documentation claims this will give a depth in the range [0, 1].

Hi thk123 -

You are misunderstanding the equation and admittedly I looked at it incorrectly to the first time. Remember PEMDAS, your order of Mathematical operations (Parentheses, Exponents, Multiplication, Division, Addition, Subtraction). In the equation:

1 - MaxZ / (SceneDepth + MaxZ)

You would first add the Scene Depth to the MaxZ then divide the MaxZ by that number then you would take the value away from 1. In this order you will get a positive value between 0 and 1.

Thank You

Eric Ketchum

Can I ask: does this formula work irrespective of whether there is a finite far plane? And should the same calculation be applied to PixelDepth?
After calculating the result, do we have zero at infinity or at the near plane?

Furthermore, if SceneDepth is in the range [0,MaxZ], the equation gives a range from 0 to 0.5.

SceneDepth=0   : D = 1 - MaxZ / MaxZ = 0
SceneDepth=MaxZ: D = 1 - MaxZ / ( MaxZ + MaxZ ) = 1 - 1/2 = 0.5

Hi Roderick -

I talked with our programmers and it looks like the documentation here is a little out of date in the way we deal the Depth Buffer. Take a look at this code from Common.usf:

// Converts depth buffer Z / W into W
float ConvertFromDeviceZ(float DeviceZ)
{
	return 1.f / (DeviceZ * View.InvDeviceZToWorldZTransform[2] - View.InvDeviceZToWorldZTransform[3]);	
}

// inverse opteration of ConvertFromDeviceZ
float ConvertToDeviceZ(float SceneDepth)
{
	return 1.0f / ((SceneDepth + View.InvDeviceZToWorldZTransform[3]) * View.InvDeviceZToWorldZTransform[2]);
}

/** Returns clip space W, which is world space distance along the View Z axis. */
float CalcSceneDepth( float2 ScreenUV )
{
#if FEATURE_LEVEL > FEATURE_LEVEL_ES3_1
	return ConvertFromDeviceZ(Texture2DSampleLevel(SceneDepthTexture, SceneDepthTextureSampler, ScreenUV, 0).r);
#else
	#if COMPILER_GLSL_ES2
		#if IOS
			// Only call FramebufferFetch when actually compiling for IOS ES2.
			return FramebufferFetchES2().w;
		#elif WEBGL
			return Texture2DSampleLevel(SceneAlphaCopyTexture, SceneAlphaCopyTextureSampler, ScreenUV, 0).r;
		#else 
			float SceneW = ConvertFromDeviceZ(Texture2DSampleLevel(SceneDepthTexture, SceneDepthTextureSampler, ScreenUV, 0).r);		
			return DepthbufferFetchES2(SceneW, View.InvDeviceZToWorldZTransform[2], View.InvDeviceZToWorldZTransform[3]);
		#endif 
	#elif METAL_PROFILE
			return FramebufferFetchES2().w;
	#else
		return ConvertFromDeviceZ(Texture2DSampleLevel(SceneDepthTexture, SceneDepthTextureSampler, ScreenUV, 0).r);
	#endif
#endif
}

#if FEATURE_LEVEL >= FEATURE_LEVEL_SM4 || MOBILE_EMULATION

	// depth in in DeviceZ
	Texture2D<float> SceneDepthTextureNonMS;

	/** Returns clip space W, which is world space distance along the View Z axis. */
	float CalcSceneDepth(uint2 PixelPos)
	{
		float DeviceZ = SceneDepthTextureNonMS.Load(int3(PixelPos, 0));

		// Fetch the depth buffer Z / W value, solve for W
		return ConvertFromDeviceZ(DeviceZ);
	}
#endif

Hi Eric, I am confused, so is SceneDepth actually calling CalcSceneDepth above? Does that mean PixelDepth also calls that? So are those still returning [0, 2^24-1]??

The Scene Depth Node accesses the calculation of Scene Depth on a particular material and is still 0 - 2^24-1. I believe (have not confirmed) that Pixel Depth references Scene Depth but its calculations are slightly different as you are dealing with the pixel being rendered not the object being rendered as in Scene Depth.

The code I posted was to point out the the simplification to normalize Scene Depth listed in the documentation is not as accurate based on changes to the Scene Depth Calculations.

Thank You

Eric Ketchum

Hi thk123,
I am trying to acess the depth and color map of a frame, but failed after having tried in several ways. Can you give me some advice?