objects rendering order

Apr 10, 2012 at 11:45 AM

When checking the debugger primitives sample I noticed some rendering issues; with the default code the primitives, in the 'primitives' list, are always drawn over everything else (http://i39.tinypic.com/8xj1qb.png) but if I change the draw code to:


            modelBatch.Begin(camera.View, camera.Projection);
                for (int i = 0; i < primitives.Count; i++)
                    Matrix world = Matrix.CreateTranslation(i * 4 - 16, 5, 0);

                    modelBatch.DrawPrimitive(primitives[i], world, primitiveEffect);

            primitiveBatch.Begin(PrimitiveSortMode.Deferred, camera.View, camera.Projection);
                primitiveBatch.DrawBillboard(butterfly, Vector3.Zero, 2, Color.White);
                primitiveBatch.DrawSphere(new BoundingSphere(Vector3.UnitX * 4, 1), 24, null, Color.White);
                primitiveBatch.DrawGrid(1, 128, 128, null, Color.White * 0.25f);
                primitiveBatch.DrawGrid(8, 16, 16, null, Color.Black);
                primitiveBatch.DrawLine(new Vector3(5, 5, 0), new Vector3(5, 5, 5), new Color(0, 0, 255, 255));
                primitiveBatch.DrawConstrainedBillboard(null, new Vector3(5, -5, 0), new Vector3(5, -5, 5), 0.05f, null, null, new Color(255, 255, 0, 255));
                primitiveBatch.DrawConstrainedBillboard(lightning, new Vector3[] { new Vector3(5, -5, 0), new Vector3(5, 0, 2), new Vector3(5, 5, 0) }, 1f, null, null, Color.White);
                primitiveBatch.DrawArrow(Vector3.Zero, Vector3.UnitZ * 2, null, Color.White);
                primitiveBatch.DrawBox(new BoundingBox(-Vector3.One, Vector3.One), null, Color.White);
                primitiveBatch.DrawSolidBox(new BoundingBox(-Vector3.One, Vector3.One), null, new Color(255, 255, 0, 255) * 0.2f);
                primitiveBatch.DrawCircle(Vector3.UnitX * 2, 1, 24, null, new Color(255, 255, 0, 255));
                primitiveBatch.DrawSolidSphere(new BoundingSphere(Vector3.UnitX * 4, 1), 24, null, new Color(255, 0, 0, 255) * 0.2f);
                primitiveBatch.DrawGeometry(model, Matrix.CreateTranslation(-4, 0, 0), new Color(255, 255, 0, 255) * 0.5f);
                primitiveBatch.DrawAxis(Matrix.CreateTranslation(-4, 0, 0));
                primitiveBatch.DrawFrustum(frustum, null, Color.White);
                primitiveBatch.DrawSolidFrustum(frustum, null, new Color(255, 192, 203, 255) * 0.5f);
                primitiveBatch.DrawCentrum(new Vector3(-5, -2, 0), 2, 1, 24, null, new Color(245, 245, 245, 255) * 0.5f);
                primitiveBatch.DrawSolidCentrum(new Vector3(-5, -2, 0), 2, 1, 24, null, new Color(124, 252, 0, 255) * 0.3f);
                primitiveBatch.DrawCylinder(new Vector3(-5, -6, 0), 2, 1, 24, null, new Color(245, 245, 245, 255) * 0.5f);
                primitiveBatch.DrawSolidCylinder(new Vector3(-5, -6, 0), 2, 1, 24, null, new Color(230, 230, 255, 255) * 0.3f);


switching the 'primitiveBatch' with the 'modelBatch', everything works fine (http://i40.tinypic.com/5bzp03.png).

What is happening? How do I avoid these issues?

Apr 11, 2012 at 3:47 AM

This is actually the expected behavior.

The difference has to with how PrimitiveBatch and ModelBatch handles depth buffer. By default, ModelBatch enables both depth read and depth write when drawing models, this make sure all the models are sorted correctly. In contrast, PrimitiveBatch, which is typically used to draw debug overlays and transparent primitives, uses depth read but do not write to the depth buffer.

The sample code provided is somewhat misleading. In real cases, you should almost always draw opaque objects before transparent objects, that is, drawing with ModelBatch and than PrimitiveBatch like in your modified version.

However, if you do want to enable depth sorting on PrimtiveBatch, use one of the overload of PrimitiveBatch.Begin and pass DepthStencilState.Default to enable depth buffer for primtives.

Hope this explains the problem.

Apr 12, 2012 at 4:58 PM

How about tutorial 02? http://i41.tinypic.com/4i0qkx.png

Why is the palm tree always in front of the tank?

I wasn't expecting that to happen because the Draw is being handled by Nine.Graphics.ObjectModel.Scene

Apr 13, 2012 at 8:48 AM

Are you talking about the palm leave hides the left most wheel of the tank?

The problem occurs because the material system cannot determine if a custom .fx shader is transparent or not. You have to give it a hint by setting IsTransparent=true on CustomMaterialContent.

Apr 13, 2012 at 11:25 AM

my bad. My description of the problem was exactly the opposite of what is happening. :/

now with the correct description:

The palm tree should be in front of the tank, but it is always rendered behind, the same does not happen with the dude model, which is why you see that strange behavior near the wheel. (images from the side and back may help with the scene perspective).

Apr 14, 2012 at 11:44 AM

The problem occurs because the cage.fx shader explicitly disables depth write in the .fx file, while the engine assumes that custom shaders should not modify any render states in their pass definition. The solution is to manually set IsTransparent=true on CustomMaterialContent, this way, the material system knows that the palm leaves are transparent and will draw them after drawing the tanks.

So the rule of thumb is, do not explicitly setup any render states in the custom fx file.