Advertisement

[D3D11]Access Depth Buffer using SV_Depth

Started by August 18, 2018 03:27 AM
5 comments, last by AireSpringfield 6 years, 5 months ago

Hi,

We know that it is possible to modify the pixel's depth value using "System Value" semantic SV_Depth in this way:


struct PixelOut
{
	float4 color : SV_Target;
	float depth : SV_Depth;
};
PixelOut PS(VertexOut pin)
{
	PixelOut pout;
	// … usual pixel work
	pout.Color = float4(litColor, alpha);
	// set pixel depth in normalized [0, 1] range
	pout.depth = pin.PosH.z - 0.05f;
	return pout;
}

As many post-effect requires the depth value of current pixel (such as fog, screen space reflection), we need to acquire it in the PS. A common way to do that is to render the depth value to a separate texture and sample it in the PS. But I found this method a bit clumsy because we already have depth value stored in the depth-stencil buffer, so I wonder whether it is possible to access from NATIVE depth buffer instead of ANOTHER depth texture. 

I found this on MSDN:  https://docs.microsoft.com/en-us/windows/desktop/direct3dhlsl/dx-graphics-hlsl-semantics

image.png.85d5e6e68ea311a165d2722acca514fd.png

that mentions READ depth data in shader. I tried this in Unity:


half4 frag (Vert2Frag v2f, float depth : SV_Depth) : SV_Target
{
	return half4(depth, depth, depth, 1);
}

However it turns out to be a pure white image, which means this depth values in all pixels are 1. So is that MSDN wrong? Is it possible to sampling a NATIVE depth buffer?

Thanks!

MSDN has some weird things to say about reading from output semantics... I think that wording means that you can read any value that you have written into it :( 

IIRC, to get the depth value of a fragment you want:


float4 frag (Vert2Frag v2f, float4 pos : SV_Position) : SV_Target
{
	float depth = pos.z / pos.w;
	return half4(depth, depth, depth, 1);
}

This isn't the same as sampling the depth buffer - this is reading the value that was just written into the depth buffer. To sample from a depth buffer, you create a SRV for it and sample it like any other texture.

If you want to sample from the currently-bound depth buffer, you need to bind it with a read-only DSV and make sure that your draw calls have depth-writes disabled.

Advertisement
24 minutes ago, Hodgman said:

MSDN has some weird things to say about reading from output semantics... I think that wording means that you can read any value that you have written into it :( 

IIRC, to get the depth value of a fragment you want:



float4 frag (Vert2Frag v2f, float4 pos : SV_Position) : SV_Target
{
	float depth = pos.z / pos.w;
	return half4(depth, depth, depth, 1);
}

This isn't the same as sampling the depth buffer - this is reading the value that was just written into the depth buffer. To sample from a depth buffer, you create a SRV for it and sample it like any other texture.

If you want to sample from the currently-bound depth buffer, you need to bind it with a read-only DSV and make sure that your draw calls have depth-writes disabled.

So by my understanding,  SV_Depth is useful only when writing custom depth values, but CANNOT be used to achieve custom reading. When writing to SV_Depth, the pipeline discard to write to depth buffer with z/w in SV_Position, which is the default. Am I right?

5 hours ago, Hodgman said:

MSDN has some weird things to say about reading from output semantics... I think that wording means that you can read any value that you have written into it :( 

IIRC, to get the depth value of a fragment you want:



float4 frag (Vert2Frag v2f, float4 pos : SV_Position) : SV_Target
{
	float depth = pos.z / pos.w;
	return half4(depth, depth, depth, 1);
}

This isn't the same as sampling the depth buffer - this is reading the value that was just written into the depth buffer. To sample from a depth buffer, you create a SRV for it and sample it like any other texture.

If you want to sample from the currently-bound depth buffer, you need to bind it with a read-only DSV and make sure that your draw calls have depth-writes disabled.

Thanks for your help!

21 hours ago, AireSpringfield said:

So by my understanding,  SV_Depth is useful only when writing custom depth values, but CANNOT be used to achieve custom reading. When writing to SV_Depth, the pipeline discard to write to depth buffer with z/w in SV_Position, which is the default. Am I right?

Yes, SV_Depth is write-only (same as SV_Target). There's no way to read the current value of the depth buffer before your pixel shader writes to it, just like there's no way to read from a render target before your pixel shader writes to it.

The z component of SV_Position gives you the value that would normally be written into the depth buffer if your pixel shader didn't output to SV_Depth. Note that you don't want to do SV_Position.z / SV_Position.w: the z input to your pixel shader has already been pre-divided by w (since this needs to be done for perspective-correct linear interpolation). 

On 8/19/2018 at 9:31 AM, MJP said:

Yes, SV_Depth is write-only (same as SV_Target). There's no way to read the current value of the depth buffer before your pixel shader writes to it, just like there's no way to read from a render target before your pixel shader writes to it.

The z component of SV_Position gives you the value that would normally be written into the depth buffer if your pixel shader didn't output to SV_Depth. Note that you don't want to do SV_Position.z / SV_Position.w: the z input to your pixel shader has already been pre-divided by w (since this needs to be done for perspective-correct linear interpolation). 

Thank you very much!

 

This topic is closed to new replies.

Advertisement