Direct3D9 - access depth/stencil buffer in pixel s

2019-08-17 06:20发布

问题:

EDIT: D24S8 textures cannot be copied. Period. Sometimes, however, it is possible to change the depth buffer format to INTZ, a special FOURCC format, which has the same layout, but can be set as input for texture samplers.

Finally my approach was to use a proxy dll to intercept all texture creation calls to be able to change the format wherever D24S8 was given. Afterwards I could then bind this texture to a texture sampler of the pixel shader, set a R32F render target and write the sampled values (DrawPrimitive on a triangle strip of two primitives) to this target.

Often the developers already used an R32F texture with D3D9 to store the depth values there and circumvent the D3D9 depth/stencil problem. In this case it is possible to straightly copy this texture to system memory if you need access.


The original post:

I am developing a Lidar sensor plugin used with a simulation environment called VBS which gets called after a new frame has been rendered to the back buffer. It has two input parameters of type IDirect3DSurface9*, one to the render target (with format X8R8G8B8) and one to the depth buffer (with format D24S8).

Currently I am trying to somehow extract the position of each pixel relative to the camera. Because I need to use the game API to retrieve the frustum values that are necessary to calculate the projection matrix, I first thought about copying the depth buffer values from GPU to system memory. I already tried GetRenderTargetData and DXLoadSurfaceFromSurface to copy the depth buffer values to a texture created in system memory, but neither of those methods succeeded.

In [1] @ozeanix suggests to use a pixel shader and add an additional render pass to copy the depth values to a texture with a format that is not a depth/stencil format and afterwards "LockRect" this texture.

Trying to implement that approach I realized that I don't know how to pass the depth buffer values to the pixel shader. The only way that I came up with was to copy the depth buffer surface to a newly created 1-level texture of the same format (and afterwards pass that texture to a ps shader), but neither GetRenderTargetData nor DXLoadSurfaceFromSurface nor UpdateSurface succeeded.

Just to make sure that the restrictions are clear: I cannot repeat the render calls (as I said, my plugin gets called only after the whole frame has been rendered), I cannot change the existing shaders (so I think I cannot enable MRT) and I also cannot redirect the depth/stencil output to a different texture (render target) first and copy this texture to the final depth buffer afterwards.

  1. Is there any way how I can pass the depth buffer to the pixel shader?

  2. In case my shader has access to the buffer how am I supposed to execute this pixel shader? Do I have to use "DrawPrimitive" or something similar (in which case I don't know which vertices I have to set as parameters)?

  3. Writing this post I thought about calculating the relative position inside the pixel shader (so setting the projection matrix in my callback, then outputting the positions directly) - is that perhaps a better approach?

Thanks in advance!

[1] Copy depth buffer with non-lockable format (D24S8) to system memory with Direct3D9, Win 8.1