Using Custom Depth to create Object ID buffer

We’re trying to create a post process effect that needs an object ID buffer for visible pixels. We only need to know if visible pixels represent a small number of specific objects in the world, with all other pixels having a default value. We’re thinking that the custom depth stencil value should let us achieve this, but it seems to have some limitations. Because only meshes with bRenderCustomDepth enabled actually write to the stencil buffer, the result we get is dependent on draw order. If nearer meshes without the flag set are drawn first, they correctly obscure the flagged meshes, because the depth test fails when later trying to write the stencil value. However, when nearer meshes without the flag set are drawn after the flagged meshes, they do not overwrite the values in the stencil buffer, so we do not know that the object is obscured at that pixel.

It seems we can’t set landscape to write to custom depth, and we’d prefer to avoid manually setting all meshes to render custom depth with a default stencil value. We are going to try a code change to force the engine to write to stencil buffer for all meshes regardless of the flag, but I thought I’d check here to see if there’s a preferred/better approach that we are missing.



Hi Mike,

So to clarify, the custom depth/stencil pass is isolated and handled after the base pass (g-buffer pass). It doesn’t share any data so you shouldn’t be seeing draw-order dependent effects. It writes to and tests against a separate depth buffer (Custom-Depth on buffer visualization modes). It is rather limited but can be utilized as needed for isolating objects in later passes and effects. If you are seeing cases where objects not set to render into the custom depth buffer are interacting with those that are flagged, it’s a bug and not intended. If you have a reproduction I’d really appreciate it, please.

As this is a separate pass it means you will be drawing any flagged meshes an additional time, so I wouldn’t recommend drawing all objects. If you need all objects to write a value, then a cleaner solution is likely to extend the g-buffer with an ID channel. Unless you’re explicitly relying on the data being stored in a stencil buffer, you should be able to add an additional buffer and have all objects output your custom IDs during the base pass. Then follow through the code to use that where necessary. For a similar but more complex example, you can try taking a look at how “r.BasePassOutputsVelocity” is used.

If however you only need a small group of specific objects to write IDs, then the cheapest method if probably to re-work the custom depth-stencil pass. Instead of writing to the custom depth buffer, bind the main scene depth buffer (from the base pass) and run a depth-less-equal test against that. The downside here is that you likely couldn’t write to the main stencil buffer as it’s in use during most of the frame, but as above you could create and bind a single-channel render target for ID storage. If you take a look where the existing custom targets are used you can add new buffers alongside that code to get material graph access, or apply them more directly in code.


Thanks for the info Chris. I’ll have a chat to the coder implementing this effect and see which of the two suggested approaches suits us best. We are only interested in a small number of meshes, but do need to use the actual scene depth, so the second approach sounds more appropriate.

I think the presumed interaction of meshes not included in that pass with meshes included in that pass was a misunderstanding by me and can safely be ignored.



Ah, that’s reassuring at least! Feel free to ask for more information if anything I suggested is unclear.