Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

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,
    };

Transparency Issue

EDIT 2:

TransparencyCullingIssue

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)

DepthStencilState

share|improve this question
    
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). –  Steve H Sep 18 '13 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. –  user1423893 Sep 18 '13 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. –  Steve H Sep 18 '13 at 21:07
    
Near clip is currently 0.1f and the far clip is 1000f. I was thinking that should be precise enough? –  user1423893 Sep 19 '13 at 10:10
add comment

5 Answers 5

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.

share|improve this answer
    
I have. I've also added an edit as to why I don't believe this is a viable solution. Do you agree? –  user1423893 Sep 16 '13 at 9:25
add comment

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).

share|improve this answer
    
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? –  user1423893 Sep 17 '13 at 15:11
add comment
up vote 0 down vote accepted

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;
share|improve this answer
add comment

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 
share|improve this answer
add comment

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.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.