0

我试图通过在切换渲染目标之前从深度缓冲区复制 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;
    }
4

1 回答 1

1

XNA3.1 不会在更改渲染目标时清除您的深度模板缓冲区,但是如果您对渲染目标更改不小心,它会解决它(因此它无法用于深度测试)。

例如:

SetRenderTarget(someRenderTarget)
DrawStuff()
SetRenderTarget(null)
SetRenderTarget(someOtherRenderTarget)

将导致深度模板缓冲区被解析,但以下不会:

SetRenderTarget(someRenderTarget)
DrawStuff()
SetRenderTarget(someOtherRenderTarget)

我不确定为什么 XNA3.1(和更早版本)会发生这种情况,但自从弄清楚这一点以来,我已经能够通过许多渲染目标更改保持相同的深度模板缓冲区活动,甚至只要清除操作仅清除指定的 ClearOptions.Target。

于 2012-01-11T20:08:08.630 回答