How can we write to depth (and velocity) from a global shader?

I’ve been attempting to write a sceneviewextension shader that can write to the main depth buffer

Following the information from Global shaders in Unreal without engine modification - Caius' Blog I happily have shaders that can write to custom buffers, and the main scene color, but not the main depth buffer.

In the pixel shader I’ve tried:
returning a struct

struct PS_OUTPUT
{
    float4 Color : SV_Target0;
    float Depth : SV_Depth;
};
...
{
    PS_OUTPUT Output;

    Output.Depth = 0.5;
    Output.Color = float4(0, 1, 0, 0);
    
    return Output;
}

as well as adding depth as an out param

void CombineMainPS(float4 SvPosition : SV_POSITION
					, out float SceneColorOut : SV_Target0
					, out float OutDepth  : SV_Target1
					, out float OutDepth  : SV_Depth
	) {

And on the C++ side of things getting a reference to the scene depth

	FScreenPassTexture SceneDepth((*Inputs.SceneTextures)->SceneDepthTexture, Viewport);

changing the depth texture flags


	FRDGTextureDesc DepthBufferOutputDesc = SceneDepth.Texture->Desc;
	DepthBufferOutputDesc.Format = EPixelFormat::PF_DepthStencil;
	DepthBufferOutputDesc.ClearValue = FClearValueBinding(0);
	DepthBufferOutputDesc.Flags = TexCreate_RenderTargetable | TexCreate_DepthStencilTargetable;
	DepthBufferOutputDesc.ClearValue = FClearValueBinding(0, 0);

and binding or nulling the scene depth reference


	CombineParameters->SceneDepth = (*Inputs.SceneTextures)->SceneDepthTexture;
	//CombineParameters->SceneDepth = NULL;

and adding the scene depth as a render target

	CombineParameters->RenderTargets[1] = FRenderTargetBinding(SceneDepth.Texture, ERenderTargetLoadAction::ELoad);// , FExclusiveDepthStencil::DepthWrite_StencilWrite);
	//CombineParameters->RenderTargets[1] = FDepthStencilBinding(SceneDepth.Texture, ERenderTargetLoadAction::ELoad, FExclusiveDepthStencil::DepthWrite_StencilWrite);

but have not yet been able to affect the scene depth.

This seems like something that should be possible, but not sure if it’s a small change I’m missing, perhaps preventing the shader from getting read access to the depth buffer? Or some larger conceptual change is needed.

Any hints on how to proceed would be very welcome, particularly with any direction on where to look to better understand how global shaders can interact with depth and velocity buffers.

Thanks!

– edit –
I’ve found this will clear the depth buffer if set to EClear

	FDepthStencilBinding DepthStencilBinding(
		SceneDepth.Texture, 
		ERenderTargetLoadAction::ELoad,//ELoad, EClear
		FExclusiveDepthStencil::DepthWrite_StencilWrite
	);
	
	CombineParameters->RenderTargets.DepthStencil = DepthStencilBinding;

but still havn’t gotten the pixel shader to write custom values to the depth buffer

Have you set the correct depthstencil state on your drawcall? See TStaticDepthStencilState and for example FPixelShaderUtils::AddFullscreenPass

I had not!

Thanks for the tip, I’m now able to alter the depth buffer :slight_smile:

	const uint32 StencilRef = STENCIL_SANDBOX_MASK;

	FRHIDepthStencilState* DepthStencilState = TStaticDepthStencilState<true, CF_Always,
		true, CF_Always, SO_Keep, SO_Keep, SO_Replace,
		false, CF_Always, SO_Keep, SO_Keep, SO_Keep,
		STENCIL_SANDBOX_MASK, STENCIL_SANDBOX_MASK>::GetRHI();

	//FRHIDepthStencilState* DepthStencilState = TStaticDepthStencilState<true, CF_Always>::GetRHI()
	
	FPixelShaderUtils::AddFullscreenPass(
		GraphBuilder,
		GlobalShaderMap,
		FRDGEventName(TEXT("Combine")),
		CombinePixelShader,
		CombineParameters,
		Viewport,
		nullptr, nullptr,
		DepthStencilState,
		StencilRef);

Though there’s still some more I need to learn about this area, it’s great to have something up and running enough to follow the source and look things up.

Would you mind elaborating on your final solution? I followed the same base tutorial, needing to also write to the depth and velocity buffers haha

Pinging again here haha