通过将2D精灵与3D模型混合来实现Z缓冲问题

时间:2011-02-14 20:38:41

标签: xna buffer depth

我必须使用XNA在3D模型上创建一个二维菜单。现在,我已经创建了2D的spritebatch和一个3d模型。但是,正如我已经注意到的,并且在其他地方被提及,由于z缓冲区问题,模型没有正确显示。根据教程,我应该在draw方法中再次启用DepthBuffer。但是,不知何故,当我使用时:

GraphicsDevice.DepthStencilState.DepthBufferEnable = true;

代码在调试期间抛出错误,说,

  

无法更改只读DepthStencilState。状态对象在第一次绑定到GraphicsDevice时变为只读。要更改属性值,请创建一个新的DepthStencilState实例。

现在,我也试图创建一个新的DepthStencilState实例,但是,即使这似乎也不起作用。我总是得到相同的错误,即使帮助文档建议它的读/写值。

请帮助我弄清楚如何正确显示3D模型。

这是Draw代码供参考。

protected override void Draw(GameTime gameTime)
{
     GraphicsDevice.Clear(Color.CornflowerBlue);

     Matrix[] transforms = new Matrix[myModel.Bones.Count];
     myModel.CopyAbsoluteBoneTransformsTo(transforms);

     foreach (ModelMesh mesh in myModel.Meshes)
     {
         foreach (BasicEffect effect in mesh.Effects)
         {
             effect.EnableDefaultLighting();

             //effect.DirectionalLight0.Enabled = true;
             //effect.DirectionalLight0.DiffuseColor = Color.AntiqueWhite.ToVector3();
             //effect.DirectionalLight0.Direction = new Vector3(0, 0, 0);

             effect.World = transforms[mesh.ParentBone.Index] * Matrix.CreateRotationY(myModelRotation) * Matrix.CreateTranslation(myModelPosition);
             effect.View = Matrix.CreateLookAt(new Vector3(0, 0, 3000), Vector3.Zero, Vector3.Up);
             effect.Projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(45f),
             GraphicsDevice.Viewport.AspectRatio, 1, 5000);
         }

         mesh.Draw();
    }

    spriteBatch.Begin();
    spriteBatch.Draw(myTexture, new Vector2(0, 0), Color.White);
    spriteBatch.End();

    DepthStencilState d = new DepthStencilState();
    d.DepthBufferEnable = true;
    GraphicsDevice.DepthStencilState = d;

    base.Draw(gameTime);
}

4 个答案:

答案 0 :(得分:8)

一旦在设备上设置了DepthStencilState对象,就无法对其进行修改。您应该为要使用的每个唯一深度/模板设置创建一个DepthStencilState对象。最理想的是,这些状态只能在程序中创建一次,然后在需要时设置到设备上。

有关更多信息,请参阅Shawn Hargreaves的State Objects in XNA Game Studio 4.0

其他详细信息:

您正在将DepthBufferEnable设置为true,但不将DepthBufferWriteEnable设置为true。您最好不要尝试单独设置这些属性,而是最好使用框架提供的预构建的DepthStencilState对象。在渲染模型之前,将GraphicsDevice.DepthStencilState设置为DepthStencilState.Default。这会将DepthBufferEnable和DepthBufferWriteEnable属性都设置为true。

您还需要将设备上的BlendState设置为BlendState.Opaque。

您需要在绘制模型之前设置这些渲染,因为SpriteBatch.Begin()会自动将renderstate更改为DepthStencilState.None和BlendState.AlphaBlend(请参阅MSDN Documentation for SpriteBatch.Begin)。

答案 1 :(得分:4)

解决方案是在3D渲染代码之前添加以下内容:

GraphicsDevice.DepthStencilState = DepthStencilState.Default;

答案 2 :(得分:1)

我在发布之前测试了这段代码。通过创建新的DepthStencilState,您可以将GraphicsDevice属性设置为新状态,如下所示:


DepthStencilState d = new DepthStencilState();
d.DepthBufferEnable = true;
GraphicsDevice.DepthStencilState = d;

答案 3 :(得分:0)

就像Empyrean所说的那样,您需要做的就是将以下代码行直接放在用于在Draw()函数中绘制模型的代码上方:

  

GraphicsDevice.DepthStencilState =   DepthStencilState.Default;