【问题标题】:Z buffer issue by mixing 2D sprites with 3D model将 2D 精灵与 3D 模型混合导致的 Z 缓冲区问题
【发布时间】:2011-02-14 20:38:40
【问题描述】:

我必须使用 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);
}

【问题讨论】:

    标签: xna buffer depth


    【解决方案1】:

    一旦在设备上设置了 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() 会自动将渲染状态更改为 DepthStencilState.None 和 BlendState.AlphaBlend(参见 MSDN Documentation for SpriteBatch.Begin)。

    【讨论】:

    • 那么,如何让我的 3D 模型与 2D 精灵一起显示?
    • 在绘制模型之前,在设备上设置 3d 深度模板状态。然后使用允许您将 2D 深度模板状态作为参数传递的重载调用 SpriteBatch.Begin。使 2d 和 3d 深度模板状态对象成为类成员,并且只在初始化期间创建它们一次,而不是在您的 draw 方法中。在 XNA 4.0 渲染状态范例中,最好在每次绘制调用之前使用现有状态对象设置整个状态,而不是在绘制后尝试将状态重置为某个默认值。
    • 糟糕!太混乱了!抱歉,我刚开始,所以,我基本上无法理解您的回复。
    • 好的。一个更简单的版本。在渲染模型之前(即在绘制函数中的 foreach 循环之前)添加以下代码行: GraphicsDevice.DepthStencilState = DepthStencilState.Default;删除设置 DepthStencilState 的绘图函数底部的代码。
    • 还是不行。模型实际上看起来是 3d,但有些部分仍然是半透明的。无论如何,这里是完整解决方案的链接,以帮助您理解问题。 rapidshare.com/files/448435742/TestGame.zip(已扫描恶意软件,仍然扫描一次,以防万一)。
    【解决方案2】:

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

    GraphicsDevice.DepthStencilState = DepthStencilState.Default;
    

    【讨论】:

      【解决方案3】:

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

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

      【讨论】:

      • 也试过了。在 Draw 方法中使用它。模型仍未正确显示。虽然,游戏不会抛出错误。如果有帮助,我将使用 Draw 方法中的代码更新问题。
      【解决方案4】:

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

      GraphicsDevice.DepthStencilState = DepthStencilState.Default;

      【讨论】:

      • 几周前就解决了,伙计。无论如何感谢您的回复。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-07-27
      • 2013-09-10
      • 1970-01-01
      相关资源
      最近更新 更多