我试图在切换渲染目标之前从深度缓冲区复制IDirect3DSurface9来绕过XNA 3.1的自动清除深度缓冲区,然后在稍后的点恢复深度缓冲区。
在代码中,getDepthBuffer方法是指向IDirect3DDevice9 GetDepthStencilBuffer函数的指针。指向该方法的指针似乎是正确的,但是当我试图获得IDirect3DSurface9指针时,它返回一个异常(0x8876086C - D3DERR_INVALIDCALL)。surfacePtr指针最终指向0x00000000。
知道为什么它不工作吗?有什么好办法吗?
下面是代码: public static unsafe Texture2D GetDepthStencilBuffer(GraphicsDevice g)
{
if (g.DepthStencilBuffer.Format != DepthFormat.Depth24Stencil8)
{
return null;
}
Texture2D t2d = new Texture2D(g, g.DepthStencilBuffer.Width, g.DepthStencilBuffer.Height, 1, TextureUsage.None, SurfaceFormat.Color);
FieldInfo f = typeof(GraphicsDevice).GetField("pComPtr", BindingFlags.NonPublic | BindingFlags.GetField | BindingFlags.Instance);
object o = f.GetValue(g);
void* devicePtr = Pointer.Unbox(f.GetValue(g));
void* getDepthPtr = AccessVTable(devicePtr, 160);
void* surfacePtr;
var getDepthBuffer = (GetDepthStencilBufferDelegate)Marshal.GetDelegateForFunctionPointer(new IntPtr(getDepthPtr), typeof(GetDepthStencilBufferDelegate));
var rv = getDepthBuffer(&surfacePtr);
SetData(t2d, 0, surfacePtr, g.DepthStencilBuffer.Width, g.DepthStencilBuffer.Height, (uint)(g.DepthStencilBuffer.Width / 4), D3DFORMAT.D24S8);
Marshal.Release(new IntPtr(devicePtr));
Marshal.Release(new IntPtr(getDepthPtr));
Marshal.Release(new IntPtr(surfacePtr));
return t2d;
}
XNA3.1在改变渲染目标时不会清除你的深度模板缓冲区,但是如果你不小心改变渲染目标,它会解决这个问题(因此它无法用于深度测试)。
例如:SetRenderTarget(someRenderTarget)
DrawStuff()
SetRenderTarget(null)
SetRenderTarget(someOtherRenderTarget)
将导致depth-stencil缓冲区被解析,但以下语句不会:
SetRenderTarget(someRenderTarget)
DrawStuff()
SetRenderTarget(someOtherRenderTarget)
我不确定为什么XNA3.1(和更早的版本)会发生这种情况,但自从弄清楚之后,我已经能够通过许多渲染目标更改保持相同的深度模板缓冲区,甚至清除操作,只要清除指定的ClearOptions。目标。