8

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

GraphicsDevice.DepthStencilState.DepthBufferEnable = true;

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

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

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

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

这是供参考的绘图代码。

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

4 回答 4

8

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

有关详细信息,请参阅Shawn Hargreaves的 XNA Game Studio 4.0 中的状态对象。

额外细节:

您将 DepthBufferEnable 设置为 true,但也没有将 DepthBufferWriteEnable 设置为 true。与其尝试单独设置这些属性,不如使用框架提供的预构建 DepthStencilState 对象。在渲染模型之前,将 GraphicsDevice.DepthStencilState 设置为 DepthStencilState.Default。这会将 DepthBufferEnable 和 DepthBufferWriteEnable 属性都设置为 true。

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

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

于 2011-02-15T01:44:32.337 回答
4

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

GraphicsDevice.DepthStencilState = DepthStencilState.Default;
于 2011-08-12T14:06:40.460 回答
1

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


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

于 2011-02-15T01:40:39.517 回答
0

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

GraphicsDevice.DepthStencilState = DepthStencilState.Default;

于 2011-03-09T00:01:35.773 回答