Index | FAQ | Search | Memberlist | Usergroups | Profile | Log in to check your private messages | Log in | Register

Tutorial: Killing z-fighting in a stock Quake engine

| Inside3d Forums Forum Index -> Programming Tutorials

View previous topic :: View next topic
Author | Message
--- | ---
Baker Joined: 14 Mar 2006 Posts: 1538 |

Posted: Sat Oct 25, 2008 9:53 am Post subject: Tutorial: Killing z-fighting in a stock Quake engine |

I have hated this problem for ages and tonight wanted for myself to solve the problem in my own engine project. -- The area near the Quad secret on E1M1 is notorious for flickering or changing appearance from various angles even with some previous called "z-fighting fixes" that don't really do the job.
The only engine I've tried with a proper z-fighting fix is:
ezQuake (I confess I have not tested FTE for this)
There are a number of engines with ALMOST a proper z-fighting fix. The closest in the almost category is Qrack. However, I get an outline in the start map atrium as a side-effect.
I still get various types of weirdness in the E1M1 area with:
DarkPlaces, FitzQuake, aguirRe Quake, QMB and every other GL engine I've ever used and thought to look for the problem.
Qrack side effect, not in ezQuake:
I don't like trading a fix in one area for a problem in another eventually I tried to identify the difference between the Qrack and ezQuake fix.
I've tried the ezQuake fix in 2 engines with the same result of a perfect solution (gl_ztrick 0 is required, some engines don't even support gl_ztrick 1 anymore).
-----
Here is the ezQuake fix:
z-fighting fix step 1: in gl_vidnt.c .. or sometimes vid_wgl.c or vid_commongl.c or vid_gl<operating sys>.c
1. Goto GL_INIT or the equivalent
2. You will see OpenGL code resembling the following ...

Quote:
glClearColor (0.15,0.15,0.15,0); glCullFace(GL_FRONT); glEnable(GL_TEXTURE_2D); glEnable(GL_ALPHA_TEST); glAlphaFunc(GL_GREATER, 0.666);

3. Add after the glAlphaFunc line (although it really doesn't matter)

Quote:
// Get rid of Z-fighting for textures by offsetting the // drawing of entity models compared to normal polygons. // (Only works if gl_ztrick is turned off) glPolygonOffset(0.05, 0);

z-fighting fix step 2: in gl_rmain.c
1. Find void R_DrawEntitiesOnList (void)
2. Locate " case mod_brush:"
3. After that, but before the "break;", insert:

Code:
// Get rid of Z-fighting for textures by offsetting the // drawing of entity models compared to normal polygons. // (Only works if gl_ztrick is turned off) if(!gl_ztrick.value) {
glEnable(GL_POLYGON_OFFSET_FILL);
}
R_DrawBrushModel (currententity);
if(!gl_ztrick.value)
{
glDisable(GL_POLYGON_OFFSET_FILL);
}
break;

I'm rather weak in a lot of the OpenGL calls and the .bsp stuff to quite understand why Qrack's method produces the start map line and ezQuake's only slightly different method doesn't.
I'm guessing that Qrack's use of 1 vs. 0.05 makes the difference in seeing the line, but I'm not 100% certain?

Back to top |

r00k Joined: 13 Nov 2004 Posts: 483 |

Posted: Sat Oct 25, 2008 7:28 pm Post subject: |

Quote:
NAME glPolygonOffset - set the scale and units used to calculate depth values C SPECIFICATION void glPolygonOffset( GLfloat factor,
GLfloat units )
PARAMETERS
factor Specifies a scale factor that is used to create a
variable depth offset for each polygon. The initial
value is 0.
units Is multiplied by an implementation-specific value to
create a constant depth offset. The initial value is
0.
DESCRIPTION
When GL_POLYGON_OFFSET is enabled, each fragment's depth
value will be offset after it is interpolated from the depth
values of the appropriate vertices. The value of the offset
is factor * DZ + r * units, where DZ is a measurement of
the change in depth relative to the screen area of the
polygon, and r is the smallest value that is guaranteed to
produce a resolvable offset for a given implementation. The
offset is added before the depth test is performed and
before the value is written into the depth buffer.
glPolygonOffset is useful for rendering hidden-line images,
for applying decals to surfaces, and for rendering solids
with highlighted edges.

0.05 seems to me its rounding to the nearest unit down.
I chose not to use a blanket value for all brushes as there were conflicts with other textures. Decals need to be pushed out a bit since the texture chain is offset. Also dynamic team skins need to be offset from the base skin as certain animation frames cause the z-fighting. The slight outline in the start map could be rectified by tweaking the value a bit.

Back to top |

Baker Joined: 14 Mar 2006 Posts: 1538 |

Posted: Sat Oct 25, 2008 8:15 pm Post subject: |

I'm still learning what half of the OpenGL calls do. I played Quake all the way through with god mode on the Mac and there is some REALLY annoying z-fighting on maybe 1/3 of the id1 maps. Ever since, was it Lightning Hunter?, brought "mainstream" attention to the z-fighting thing, I just don't enjoy seeing the flickering in E1M1 type areas that are scattered about especially in the id1 maps and just about every engine does it in some shape or form.
And at the same time, knowing that the start map tends to get played heavily on a certain servers, I was concerned about the outline and getting the inevitable question or complaint (or worse --- not getting it).
I considered adding "if map !=start" code as a solution. I didn't think about decals or other special effects.

Back to top |

Wazat Joined: 15 Oct 2004 Posts: 732 Location: Middle 'o the desert, USA |

Posted: Sun Oct 26, 2008 4:31 am Post subject: |

This looks like a well-made tutorial. I like the way you've outlined areas in the picture to illustrate the problem. I've noticed z-fighting a lot and it would be nice to get rid of it in some of the mainstream engines... the question is what method is best for dealing with all cases.
Glad I'm not an engine programmer. Can't blame me for not doing it myself.
(though watch LH come in and blame me, hehe)
_________________
When my computer inevitably explodes and kills me, my cat inherits everything I own. He may be the only one capable of continuing my work.

Back to top |

LordHavoc Joined: 05 Nov 2004 Posts: 243 Location: western Oregon, USA |

Posted: Sun Oct 26, 2008 4:52 am Post subject: |

I disagree with the use of the first parameter in glPolygonOffset, that pushes the polygon along its normal, which can easily cause artifacts when the bmodel is not a simple flat plane, furthermore it can cause artifacts where it meets the world geometry - for example that line you cited in Qrack can result from use of the first parameter in glPolygonOffset.
DarkPlaces and Quake3 use the second parameter, which pushes it only a tiny amount without moving the polygon at all.
I've heard of better results in DarkPlaces when using r_polygonoffset_submodel_offset 14 (default is 2), but 2 works fine on nvidia, perhaps 14 is needed on ATI?
You can experiment with different values for both parameters in the DarkPlaces console.
r_polygonoffset_submodel_factor - first parameter (default 0)
r_polygonoffset_submodel_offset - second parameter (default 2)

Back to top |

Baker Joined: 14 Mar 2006 Posts: 1538 |

Posted: Sun Oct 26, 2008 5:01 am Post subject: |

LordHavoc wrote:
r_polygonoffset_submodel_factor - first parameter (default 0)

If I set that cvar's value to 1, the z-fighting in e1m1 disappears.
I played with r_polygonoffset_submodel_offset values from 1 to 25 and although it was less distinct, the z-fighting never totally went away for me without setting the former parameter. (GeForce 5200fx, not ATI)

Back to top |

LordHavoc Joined: 05 Nov 2004 Posts: 243 Location: western Oregon, USA |

Posted: Sun Oct 26, 2008 11:26 am Post subject: |

Baker wrote:
I played with r_polygonoffset_submodel_offset values from 1 to 25 and although it was less distinct, the z-fighting never totally went away for me without setting the former parameter. (GeForce 5200fx, not ATI)

This concerns me, because factor causes artifacts (polygon gaps, or overlap) AND is less effective in the distance (the z-fighting returns if you get far enough away), offset does not suffer either problem, so I really can't accept factor as a solution, but if offset isn't working either then we have a problem...
Note: to make matters worse, in OpenGL 3.0 the glPolygonOffset feature is deprecated (meaning should not be used in 3.0 and can't be used in apps that want to make use of OpenGL 3.1 and later features), and it never existed in Direct3D at all (to give you an idea of how discouraged it is).
Note2: ATI performance suffers on regions of the screen that were affected by glPolygonOffset (because the hierarchical polygon depth culling does not support the offset features) - I don't think it accelerates glDepthRange either for that matter, which is the other way to do an offset.

Back to top |

Baker Joined: 14 Mar 2006 Posts: 1538 |

Posted: Sun Oct 26, 2008 11:51 am Post subject: |

LordHavoc wrote:

Baker wrote:
I played with r_polygonoffset_submodel_offset values from 1 to 25 and although it was less distinct, the z-fighting never totally went away for me without setting the former parameter. (GeForce 5200fx, not ATI)

This concerns me, because factor causes artifacts (polygon gaps, or overlap) AND is less effective in the distance (the z-fighting returns if you get far enough away), offset does not suffer either problem, so I really can't accept factor as a solution, but if offset isn't working either then we have a problem...
Note: to make matters worse, in OpenGL 3.0 the glPolygonOffset feature is deprecated (meaning should not be used in 3.0 and can't be used in apps that want to make use of OpenGL 3.1 and later features), and it never existed in Direct3D at all (to give you an idea of how discouraged it is).
Note2: ATI performance suffers on regions of the screen that were affected by glPolygonOffset (because the hierarchical polygon depth culling does not support the offset features) - I don't think it accelerates glDepthRange either for that matter, which is the other way to do an offset.

I'll make some screenshots with the console down in that area to verify:
a. I made no mistakes
b. show how it renders with these different cvar settings

Back to top |

Baker Joined: 14 Mar 2006 Posts: 1538 |

Posted: Sun Oct 26, 2008 12:46 pm Post subject: |

LordHavoc wrote:

Baker wrote:
I played with r_polygonoffset_submodel_offset values from 1 to 25 and although it was less distinct, the z-fighting never totally went away for me without setting the former parameter. (GeForce 5200fx, not ATI)

This concerns me, because factor causes artifacts (polygon gaps, or overlap) AND is less effective in the distance (the z-fighting returns if you get far enough away), offset does not suffer either problem, so I really can't accept factor as a solution, but if offset isn't working either then we have a problem...
Note: to make matters worse, in OpenGL 3.0 the glPolygonOffset feature is deprecated (meaning should not be used in 3.0 and can't be used in apps that want to make use of OpenGL 3.1 and later features), and it never existed in Direct3D at all (to give you an idea of how discouraged it is).
Note2: ATI performance suffers on regions of the screen that were affected by glPolygonOffset (because the hierarchical polygon depth culling does not support the offset features) - I don't think it accelerates glDepthRange either for that matter, which is the other way to do an offset.

Did some more testing and this time took screenshots.
r_polygonoffset_submodel_offset 2 (default), fairly noticeable z-fighting.
r_polygonoffset_submodel_offset 14; 99.8% solved but some z-fighting did occur if was running around the area and very carefully looking around to try to get an angle that would cause a little flickering.
r_polygonoffset_submodel_offset 25; 100% solved; try as I might, I couldn't locate anywhere to stand or look that would do any z-fighting.
/Yeah, that r_polygonoffset_submodel_factor cvar had an undesireable side effect in the start map atrium.

Back to top |

r00k Joined: 13 Nov 2004 Posts: 483 |

Posted: Mon Oct 27, 2008 3:38 pm Post subject: |

Code:
void GL_PolygonOffset (int offset) { if (offset > 0) { glEnable (GL_POLYGON_OFFSET_FILL);
glEnable (GL_POLYGON_OFFSET_LINE);
glPolygonOffset(0.0559, offset);
}
else if (offset < 0)
{
glEnable (GL_POLYGON_OFFSET_FILL);
glEnable (GL_POLYGON_OFFSET_LINE);
glPolygonOffset(-0.0559, offset);
}
else
{
glDisable (GL_POLYGON_OFFSET_FILL);
glDisable (GL_POLYGON_OFFSET_LINE);
}
}

seems to work better on my end. only the start map shows VERY faint offset outline now.

Back to top |

Baker Joined: 14 Mar 2006 Posts: 1538 |

Posted: Mon Oct 27, 2008 4:44 pm Post subject: |

r00k wrote:

Code:
void GL_PolygonOffset (int offset) { if (offset > 0) { glEnable (GL_POLYGON_OFFSET_FILL);
glEnable (GL_POLYGON_OFFSET_LINE);
glPolygonOffset(0.0559, offset);
}
else if (offset < 0)
{
glEnable (GL_POLYGON_OFFSET_FILL);
glEnable (GL_POLYGON_OFFSET_LINE);
glPolygonOffset(-0.0559, offset);
}
else
{
glDisable (GL_POLYGON_OFFSET_FILL);
glDisable (GL_POLYGON_OFFSET_LINE);
}
}

seems to work better on my end. only the start map shows VERY faint offset outline now.

There is always the old fashioned way ...

Quote:

Code:
if (map != MAP_START) { ... }

Back to top |

Baker Joined: 14 Mar 2006 Posts: 1538 |

Posted: Tue Oct 28, 2008 12:23 am Post subject: |

LordHavoc wrote:
because factor causes artifacts (polygon gaps, or overlap) AND is less effective in the distance (the z-fighting returns if you get far enough away), offset does not suffer either problem, so I really can't accept factor as a solution, but if offset isn't working either then we have a problem...

I've noticed some undesireable side effects of the ezQuake "factor" method when testing out some of the maps in my engine using the ezQuake code.
I guess I'll play around with DarkPlaces and Qrack some more and maybe add r_submodel_polygon_offset and r_submodel_polygon_factor and let the user decide.

r00k wrote:

Code:
void GL_PolygonOffset (int offset) { if (offset > 0) { glEnable (GL_POLYGON_OFFSET_FILL);
glEnable (GL_POLYGON_OFFSET_LINE);
glPolygonOffset(0.0559, offset);
}
else if (offset < 0)
{
glEnable (GL_POLYGON_OFFSET_FILL);
glEnable (GL_POLYGON_OFFSET_LINE);
glPolygonOffset(-0.0559, offset);
}
else
{
glDisable (GL_POLYGON_OFFSET_FILL);
glDisable (GL_POLYGON_OFFSET_LINE);
}
}

seems to work better on my end. only the start map shows VERY faint offset outline now.

Rook, in my head ... and this is just how I think ...
The 2 most frequently played maps are start and e1m1.
If the outline in the start map wasn't there and was instead on E3M3 near the exit, who knows if I would ever notice or even care?
I think I got preoccupied with e1m1 because that area's flickering always irritates me. But if that didn't happen on e1m1 and instead happened near the exit on Ziggurat Vertigo, who knows if I'd even be aware of it.
----
I think of "start" as the cover, "e1m1" as the first page inside the cover and maybe e1m3 as the first chapter just because it plays in the starting demos (except in engines like Qrack).
So for me, I think I'll try to "solve" the problem by any means necessary in ProQuake even with an evil (map == start) hack.
My logic is that the "standard issue" interpolation code makes exceptions for torches and I use a shotgun box skin "corrector" found in aguirRe's engine. My understanding is that the muzzleflash code in Qrack and ezQuake selectively removes the muzzleflash stuff off the v_weaps.
To the unknowing reader: shotgun shell "evil fix hack" fixes this:
DarkPlaces is clean with no evilness. No other engine is ... not even glquake.
I guess I'll solve this somehow using an evil method!

Back to top |

reckless Joined: 24 Jan 2008 Posts: 390 Location: inside tha debugger |

Posted: Tue Oct 28, 2008 3:21 pm Post subject: |

thats one thing that also allways bugged the crap out of me in some engines with zfighting. tenebrae was notorious for that but well that was most likely because of the shadow volume code. mh's engine i work with atm doesnt show any flickering as far as i can notice but im old so my eyes might not be the best .
one thing i found out that can really take a punch at zfighting and hold on this is mundo weird. if you got a replace texenv at the end of
drawtexturechains delete it and put a blendfunction with the value
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
instead.
it seems for some reason the blendfunction gets modified comming out of there especially visible on engines using multitexture "all newer engines".
cant say what modifies it but this drastically reduces zfighting even more if you do the same at the end of the brushmodel code.

Back to top |

Display posts from previous:

| Inside3d Forums Forum Index -> Programming Tutorials | All times are GMT
Page 1 of 1

Jump to:

You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum

Powered by phpBB © 2004 phpBB Group