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
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.
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):
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
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:
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();
andgraphicsDevice.DrawPrimitives(...)
and similar drawing functions interfere with SpriteBatch’s drawing block (everything between spriteBatch.Begin(…) and spriteBatch.End()).Try something like this:
Important is that you draw your 3D models/shapes not from within an active SpriteBatch Begin() End() block.