Z-fighting

OK, can someone clue me in to EXACTLY what things can cause z-fighting (I know there is a doc somewhere, but I cant seem to find it for some reason).

In my example I am rendering about 20 quads. Then, of those 20 quads, I am going back and “highlighting” a single one of them by drawing it again with a different texture. I know different pipelines cause this (due to slightly different calculations) but both passes of the quad:
1)are calculated at the same time (ie: I calculate one vertex, copy its xyz to the new vertex, and generate new tex coords for it)
2)are in vertex arrays, with only normal pointer and a single tex coord pointer enabled.
3)are rendered with glDrawElements, with the exact same vertex ordering and both with GL_QUADS
4)are the exact same state settings (blending, depth test, no alpah/stencil test, no lighting, single texture, etc).
5)no calls to any matrix function (so the same projection is used)

Now, I may have violated one of the above (sometimes you get that “oh, I’m not actualy doing what I think” moments), but I’m PRETTY SURE the only thing I am changing between renderings is
a) the tex coords (could this be a cause? I doubt it)
b) the texture (both are 2D, same filtering/wraping, although the size might be different…I dont remember)
c) the color (set with glColor3fv)
d) the fact that the quad is drawn with 19 others in the first pass, and by itself in the second pass, but I am NOT using strips (as I said, Im using GL_QUADS)

Other than that, it should be the same settings. As far as I know, the quad should either be fully drawn or fully rejected (depending on depth settings), but instead I am getting that striped look you get when the verts are calculated slightly different.

Any input on what factors can cause this (maybe matt?) Its a GF2 64MB, 11.01 drivers…prehaps its the drivers. I saw in the archives Tom N. solved a similar problem last year with a driver upgrads, so I’ll try that (or actually, a downgrade) tonight.

I could only guess at the reasons, but the solution would be to use glPolygonOffset(-1,-1) with glEnable(GL_POLYGON_OFFSET_FILL) on the selected quad with glDepthFunc(GL_LESS).
Or redraw the whole image with the one quad in another color.


4)are the exact same state settings … depth test…

What depth function do you use ?
I remember I had similar problems with TNT2 and they gone after I used something like this.

glLockArrays()
glDepthFunc(LESS);
glDrawElements();
glDepthFunc(EQUAL);
glDrawElements();

[This message has been edited by Michail Bespalov (edited 04-18-2001).]

Generally Z-fighting is caused by verticies being transformed slightly differently. Usually it happens when a driver needs to transform the verticies in hardware on one pass of an algorithm and in software (ie the driver) on another pass. Somtimes it’s not always obvious what will cause the driver to make these decisions. Given your list it certainly seems like you very similar state for your algorithm, maybe you can post a code snippet of the state you are setting for each pass?

Originally posted by Relic:
but the solution would be to use glPolygonOffset(-1,-1) with glEnable(GL_POLYGON_OFFSET_FILL) on the selected quad with glDepthFunc(GL_LESS).

Yes, that would be the hack solution, but as far as I know, I shouldnt have this problem to begin with. Polygon offset is a little bit of a pain, but in cases where you are using different pipelines, that is about the only way to deal with it. However, I SHOULD be using the same pipeline/codepath, so this problem shouldnt be there. I want to see if I can fix it right before hacking it.


Or redraw the whole image with the one quad in another color.

Yes, another solution I thought of. However, eventually I plan to be drawing more than 1000 quads, and I didnt want to have to dynamically modify the index array for what is (otherwise) a static geometry list. If it comes down to it, I would probably do this before I resorted to something like polygon offset.

Originally posted by Michail Bespalov:
What depth function do you use ?

I am using GL_LEQUAL for both passes. This should succeed on the second pass, and it ensures that I keep that state consitant between passes (thats one less thing that could cause a pipeline/codepath change in driver).

Maybe the highlighted quad is being triangulated differently from the one underneath it? Try converting to triangles and see if that helps.

I don’t know if having two otherwise identical quads with different diagonals could (or should) lead to different depth values, but that’s my best guess.

  • Tom

Originally posted by Tom Nuydens:
[b]Maybe the highlighted quad is being triangulated differently from the one underneath it? Try converting to triangles and see if that helps.

I don’t know if having two otherwise identical quads with different diagonals could (or should) lead to different depth values, but that’s my best guess.[/b]

Yes, I think that would cause a problem, but dont know if its the case. I can give it a try.
Im also wondering if there was any chance of the driver stripifying arrays, although I doubt it because (since it is not currently optimized) I have completely duplicated each vertex for each triangel (in other word, each vertex in the vertex array is referenced exactly once in the index array). Since Im not using VAR or compiled vertex arrays, I doubt it would do this though.

I think there is no otherway to solve your problem than using glPolygonOffset , because fragment rasterisation is only done with a approximated equation (says OpenGl Spec)

Chris

Originally posted by DaViper:
I think there is no otherway to solve your problem than using glPolygonOffset , because fragment rasterisation is only done with a approximated equation (says OpenGl Spec)

But the same code path with the same settings taking the same input should produce the same output z values. If you have the same z-values, a GL_EQUAL or GL_LEQUAL test should pass. The trick is finding out what constitutes “the same code path”. As I said, the only input that I “believe” to be different are tex-coord, texture, color, and how many quads appear in the batch.

As I said earlier, If I cant solve it, I would probably alter my index buffers rather than resort to polygon offset (polygon offset just seems too messy to me). Actually, altering the index buffer is probably a bit easier than I previously though. I can probably just modify the indicies for that quad to make a degenerate quad and then restore them after I render. Its not an enourmous problem at the moment, but I am just hoping that it doesnt become one.

Yes, same geometry, same code path will always result in the same Z values (and fragments rasterized).

Quad triangulation does make a difference.

You will need to find exactly what state you are changing that is causing the problem.

  • Matt

Tom,
Thanks a million. It was the triangulation. Like I thought, it was an “oh, Im not actually doing what I though I was” moment. I thought I was generating my quads the same, and so it never crossed my mind. Well…

If you rotate the indicies 90 degrees (ie: 1230 instead of 0123) it splits it the other way, and I would expect errors to crop up there. What I didnt suspect was that rotating the quad 180 (2301)degrees also causes errors (even though it splits it the same way), and this is what I was doing. In retrospect, yes I can completely see why even the 180 degree rotation would cause a problem (starting from point A and interpolating to B is different than the reverse).

Thanks everyone. I knew I could get this one without hacking it.