# Drawing transparent and opaque 3D objects. How do I preventing z-fighting?

I am using a transparent weighted average algorithm to draw my transparent objects.

The transparent object is drawn with the following notable render states (the rest are default XNA values):

    CustomBlendState.Additive,
DepthStencilState.DepthRead,
RasterizerState.CullNone,
SamplerState.PointClamp


The opaque object is drawn using the following states:

    BlendState.Opaque;
DepthStencilState.Default;
RasterizerState.CullCounterClockwise;
SamplerState.PointClamp;


In the picture below there is what I believe is a z-fighting issue where the green block and the wooden block meet.

How can I keep the objects in the same location and stop this issue from occurring?

When changing the transparent object's DepthStencilState.DepthRead state to DepthStencilState.None the issue goes away. While this is what led me to believe it was a z-fighting issue, the opaque object will then no longer occlude the transparent object when viewed from another angle.

EDIT:

Applying a depth bias to the situation makes no discernible difference either:

    public static RasterizerState SolidNoCullBias = new RasterizerState()
{
CullMode = CullMode.None,
FillMode = FillMode.Solid,
DepthBias = 1f,
SlopeScaleDepthBias = 1f,
};


EDIT 2:

Culling the triangles will cause the object to look incorrect as a transparent object should show both the inside and outside faces.

EDIT 3:

Depth Stencil State is as follows with 'LessEqual' compare function (doesn't solve the issue)

• Are the two faces that are fighting designed to be coplanar? Or is there seporation (a small gap between)? (if the latter, increase the nearclip value in your projection Matrix for a more accurate calculation). Sep 18, 2013 at 20:39
• Yes, they are designed to be coplanar. I'm using a 24-bit depth buffer for greater precision also. It looks like adjusting the screen space depth is the best option. The DepthBias option doesn't provide consistent results and can cause some strange clipping issues within the view frustum. Sep 18, 2013 at 21:00
• well, still it's worth a shot extending the near clip if you can and see what happens. In terms of z-fighting, it can be visualized as the distance from the camera to the nearclip is like the barrel of a gun... the longer the barrel, the more accurate the shot. If you can move the decimal point on the nearclip even one place to the right, it gives an extra order of precision to the z value calculation. Sep 18, 2013 at 21:07
• Near clip is currently 0.1f and the far clip is 1000f. I was thinking that should be precise enough? Sep 19, 2013 at 10:10

## 5 Answers

Have you tried to set the cull mode for the transparent cube to a state other than CullNone? It seems like the problem would go away if the backsides of the transparent cube were not drawn.

• I have. I've also added an edit as to why I don't believe this is a viable solution. Do you agree? Sep 16, 2013 at 9:25

Use the "less than or equal to" depth compare function instead of a hacky bias, and render transparent polygons last using painters algorithm (as it looks like you are already doing).

• The depth compare function is already "less than or equal to". I've added a third edit to give the exact state. Is there something else that requires changing? Sep 17, 2013 at 15:11

I have found a method which works and allows me to keep CullMode.None.

This involves the introduction of a small epsilon value which translates the triangle face along the normal. It is only activated for transparent objects.

The following line is added to the HLSL shader:

input.Position.xyz -= (input.Normal.xyz * 0.0001);


Perhaps this is an acceptable approach?

It can also be applied in screen space without the need for a multiplication

Output.Position.z -= 0.00001;


this can be accomplished by a modified RasterizerState, that is set before drawing transparent objects.

private readonly RasterizerState _antiDepthFightingState
= new RasterizerState{DepthBias = -0.000001f}


As far as I understand this, it adds a little bit to your (projected) z or depth value, before comparing it with the already existing value in the DepthBuffer. So for the graphics card my transparent objects are hovering over the other objects. But as far as you don't make DepthBias to big, this is not visible. Because of the fact the DepthBias is added to your depth value of a certain pixel, its amount has to be carefully adjusted to your near- and far-plane settings.

Finally your code should look something like this:

//set some paramters
...
//set antidepthFightingState
GraphicsDevice.RasterizerState = _antiDepthFightingState;
//draw your transparent stuff
...
//!reset RasterizerState State to default
GraphicsDevice.RasterizerState = RasterizerState.CullCounterClockwise


I can't find the source, but I remember someone suggesting that this z-fight could be caused by the vertex coordinates of the adjacent cubes not matching exactly due to floating point inaccuracy. For example if you render the left cube in left = x * cube_width; right = left + cube_width;, the position of right for cube x can differ from the position of left for cube x + 1. If you instead replace the second calculation with right = (x + 1) * cube_width; (assuming x is integer), the values would exactly match. When you render the exact same polygon twice, the z-fight should disappear.