Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Z buffer issue by mixing 2D sprites with 3D model

Tags:

buffer

xna

depth

I have to create a 2d menu, over a 3d model, using XNA. Right now, I have created spritebatch for 2D, and a 3d model. But, as i have noticed, and was mentioned in other places, model is not being displayed properly, because of z buffer issue. According to the tutorial, I am supposed to enable the DepthBuffer again, in the draw method. But, somehow, when I use:

GraphicsDevice.DepthStencilState.DepthBufferEnable = true;

code throws an error during debugging, saying,

Cannot change read-only DepthStencilState. State objects become read-only the first time they are bound to a GraphicsDevice. To change property values, create a new DepthStencilState instance.

Now, I have tried to create a new instance of DepthStencilState too, but, even that doesn't seem to work. I get the same error always, even though, the help document suggests its a Read/Write value.

Kindly help me figure out how to get the 3D model displayed properly.

Here is the Draw code for reference.

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);
}
like image 438
jitendragarg Avatar asked Feb 14 '11 20:02

jitendragarg


3 Answers

You cannot modify a DepthStencilState object once it has been set on the device. You should create a single DepthStencilState object for each unique depth/stencil setting you want to use. Optimally, these states should only be created once in your program and then set onto the device when required.

For more information see State Objects in XNA Game Studio 4.0 by Shawn Hargreaves.

Additional Details:

You are setting DepthBufferEnable to true but not DepthBufferWriteEnable to true as well. Instead of trying to set these properties individually, you would be better off using the prebuilt DepthStencilState objects provided by the framework. Before rendering your model set the GraphicsDevice.DepthStencilState to DepthStencilState.Default. This will set both the DepthBufferEnable and DepthBufferWriteEnable properties to true.

You also need to set the BlendState on the device to BlendState.Opaque.

You need to set these renderstates before you draw your model because SpriteBatch.Begin() automatically changes the renderstate to DepthStencilState.None and BlendState.AlphaBlend (see the MSDN Documentation for SpriteBatch.Begin).

like image 132
Empyrean Avatar answered Oct 22 '22 04:10

Empyrean


Solution is to add the following before your 3D render code:

GraphicsDevice.DepthStencilState = DepthStencilState.Default;
like image 4
David D. Avatar answered Oct 22 '22 05:10

David D.


I've tested this code before posting it. By creating a new DepthStencilState, you can set the GraphicsDevice property to your new State, like so:


DepthStencilState d = new DepthStencilState();
d.DepthBufferEnable = true;
GraphicsDevice.DepthStencilState = d;
like image 1
Darkhydro Avatar answered Oct 22 '22 03:10

Darkhydro