skip to Main Content

https://www.youtube.com/watch?v=QWImAT-g7tE

Hey, I’m having trouble with overlapping 3d objects. My 3D rendered models/objects are drawn on top of each other based on which draw method gets called last instead of basing it off the pixel’s position relative to the camera. Depth buffering is supposed to solve this issue on it’s own.. but it doesn’t

I was told that either my “depth read” or “depth write” are failing. My “Depth read” is I assume setting the DepthStencilState to default:

            graphicsDevice.DepthStencilState = DepthStencilState.Default;

And the depth write is this right:

GraphicsDevice.Clear(Color.CornflowerBlue);
GraphicsDevice.Clear(ClearOptions.DepthBuffer, Color.Black, 1.0f, 0);

I’ve tried everything. Even removing the spritebatch because that has some effect on the buffering and rendering. My only theory left is that I keep resetting the graphicsDevice Vertexbuffer by this line of code

                graphicsDevice.SetVertexBuffer(shape.vertexBuffer);

But ChatGPT informed me that isn’t a problem. Does anyone have an idea where my problem could possible be? Here is how I draw my 3D objects:

    public override void Draw(GameTime gameTime, SpriteBatch spriteBatch) {
            graphicsDevice.DepthStencilState = DepthStencilState.Default;
            graphicsDevice.BlendState = BlendState.Opaque; // Spritebatch sets it default to AlphaBlend

            base.Draw(gameTime, spriteBatch);
            Draw3DModels();
            Draw3DShapes();
        }

        private void Draw3DModels() {
            foreach (ThreeDGameObject threeDGameObject in ThreeDObjects) {
                Model model = threeDGameObject.model;
                foreach (ModelMesh mesh in model.Meshes) {
                    foreach (BasicEffect effect in mesh.Effects) {

                        // Transformations
                        Matrix worldMatrix = Matrix.CreateTranslation(threeDGameObject.Position) *
                            Matrix.CreateFromYawPitchRoll(threeDGameObject.Rotation.Y, threeDGameObject.Rotation.X, threeDGameObject.Rotation.Z);
                        effect.World = worldMatrix;
                        effect.View = camera.View;
                        effect.Projection = camera.Projection;

                        // Light
                        // effect.AmbientLightColor = new Vector3(1f, 0, 0);
                        // effect.EnableDefaultLighting();

                        // Other shader settings
                        effect.TextureEnabled = true;
                        effect.Alpha = threeDGameObject.Alpha;

                        effect.CurrentTechnique.Passes[0].Apply();
                    }

                    mesh.Draw();
                }
            }
        }

        private void Draw3DShapes() {
            basicEffect.Projection = camera.Projection;
            basicEffect.View = camera.View;
            basicEffect.World = camera.World;

            // Draw all shapes
            foreach (Shape shape in shapes) { 
                // Transformations
                Matrix worldMatrix = Matrix.CreateTranslation(shape.Position) *
                    Matrix.CreateFromYawPitchRoll(shape.Rotation.Y, shape.Rotation.X, shape.Rotation.Z);
                basicEffect.World = worldMatrix;

                graphicsDevice.SetVertexBuffer(shape.vertexBuffer);
                graphicsDevice.Indices = shape.indexBuffer;

                foreach (EffectPass pass in basicEffect.CurrentTechnique.Passes) { 
                    pass.Apply();
                    graphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, shape.vertices.Length / 3);
                }
            }
        }

Could the problem be in the camera?

I am in Visual Studio Code
Monogame version: 3.8.1.303

GameEnvironment class:

    public GameEnvironment() {
        graphics = new GraphicsDeviceManager(this);
        graphics.PreferredBackBufferFormat = SurfaceFormat.Color;
        graphics.PreferredDepthStencilFormat = DepthFormat.Depth24Stencil8;
        graphics.ApplyChanges();


        Content.RootDirectory = "Content";
        inputHelper = new InputHelper();
        gameStateManager = new GameStateManager();
        spriteScale = Matrix.CreateScale(1, 1, 1);
        random = new Random();
        assetManager = new AssetManager(Content);
        gameSettingsManager = new GameSettingsManager();
    }
    protected override void Draw(GameTime gameTime) {
        GraphicsDevice.Clear(Color.CornflowerBlue);
        GraphicsDevice.Clear(ClearOptions.DepthBuffer, Color.Black, 1.0f, 0);

        spriteBatch.Begin(SpriteSortMode.Deferred, null, null, null, null, null, spriteScale);
        gameStateManager.Draw(gameTime, spriteBatch);
        spriteBatch.End();
    }

2

Answers


  1. Chosen as BEST ANSWER

    If anyone else got this problem, create and set your viewport only in the initializer of your game class, doing this anywhere else will break your depth buffer, even if you set the DepthStencilState back to default every frame.

            Viewport viewport = new Viewport();
            viewport.X = (graphics.PreferredBackBufferWidth / 2) - (screenWidth / 2);
            viewport.Y = (graphics.PreferredBackBufferHeight / 2) - (screenHeight / 2);
            viewport.Width = screenWidth;
            viewport.Height = screenHeight;
            GraphicsDevice.Viewport = viewport;
    

    enter image description here


  2. GraphicsDevice.DepthStencilState = DepthStencilState.Default;
    

    is the correct setting to enable writing into and reading from the depth buffer.

    You also need to make sure that your backbuffer (the main target framebuffer) has a depth buffer applied to it. Something like this, where you set up your GraphicsDeviceManager and backbuffer on app start (either the constructor of your inherited Game class or the Initialize() function of it):

    DeviceManager.PreferredBackBufferFormat = SurfaceFormat.Color;
    DeviceManager.PreferredDepthStencilFormat = DepthFormat.Depth24Stencil8;
    

    There are several possible settings for the depth buffer but any except ‘None’ should work.

    It is also a good idea to place this line

    base.Draw(gameTime, spriteBatch);
    

    at the end of the function or at the start (e.g. if you only draw UI with SpriteBatch, then more likely at the end) Let me know if it helped!

    Small addition:

    And the depth write is this right:
    ```cs
    GraphicsDevice.Clear(Color.CornflowerBlue);
    GraphicsDevice.Clear(ClearOptions.DepthBuffer, Color.Black, 1.0f, 0);
    

    This is the clearing of both, the color buffer and the depth buffer, i.e. drawing the background color, and clearing any depth data from the last frame.

    Edit for comment:

    I assume, ‘gameStateManager.Draw(gameTime, spriteBatch)’ is the called function above in your code. AFAIK, 3D-Models should not be drawn inside of a SpriteBatch Begin() End() block as graphicsDevice.DrawPrimitives(...); is actually a different kind of draw call. SpriteBatch defers the rendering to render things in one batch while DrawPrimitives(…) does not. pass.Apply(); and graphicsDevice.DrawPrimitives(...) and similar drawing functions interfere with SpriteBatch’s drawing block (everything between spriteBatch.Begin(…) and spriteBatch.End()).

    Try something like this:

     protected override void Draw(GameTime gameTime) {
            GraphicsDevice.Clear(Color.CornflowerBlue);
            GraphicsDevice.Clear(ClearOptions.DepthBuffer, Color.Black, 1.0f, 0);
    
            spriteBatch.Begin(SpriteSortMode.Deferred, null, null, null, null, null, spriteScale);
            // Here, you only draw 2Dish stuff like UI or sprites which should be depth sorted via their position
            gameStateManager.DrawSprites(gameTime, spriteBatch);
            spriteBatch.End();
            // Then after (or before that) draw your 3D models and shapes in an extra function (no base.Draw(...) in there though!)
            gameStateManager.Draw3DModels(gameTime, spriteBatch);
        }
    

    Important is that you draw your 3D models/shapes not from within an active SpriteBatch Begin() End() block.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search