Terrain z-fighting issues.

In my game, I have train track laid out over a height-mapped terrain. The problem is the train track is so close to the terrain that it causes z-fighting issues. Now, this isn’t such a big deal because I can move the tracks slightly above the terrain so they do not occupy the same space.

However, I also have rocks, mountains, trees, and other props scattered on the terrain. For some models, like the tracks, I can elevate slightly above the terrain. But for other models, like the rocks, I can’t simply elevate them because the rocks are placed on many differently shaped surfaces, there is no way to make a clear cut-off. (Tracks are always placed on only the flat parts of the terrain, where as the other props may not be).

Is there some way to give certain polygons a z-preference so the video card doesn’t have to “guess” which is on top?

I read somewhere that I should use a depth-map, but they didn’t explain how it would work. The only thing I can think of would be to render the scene into 2 separate depth buffers: once for the terrain and once for everything else. I would then have to compare the depth values and while rendering the scene for the final time, take preference on the non-terrain depth buffer. But this sounds grossly inefficient.

In my game, I have train track laid out over a height-mapped terrain.

You may want to consider moving the Z-near plane farther from 0. What is your current z-near value?

My current z-near is 1 and my z-far is 26,000

Might it be that 26,000 is just too far?

I read somewhere that making the near/far plane at a 1:1000 ratio will yield best results. Is there any truth to this?

You will have a better gain in precision if you can push your near plane from 1 to 2.

EDIT: 1 To 26000 should be pretty good anyway, are you sure you ask and get a 24 bits depth (instead of 16bits) ? At what distance is your train ?

Some links :
http://www.sjbaker.org/steve/omniv/love_your_z_buffer.html
http://www.codermind.com/articles/Depth-buffer-tutorial.html

My current z-near is 1 and my z-far is 26,000

To position your near and far planes correctly, you need to know two things:

1: What is the smallest resolution you need for objects that are reasonably far from the camera? That is, for any two triangles in your scene, what is the smallest Z-distance between them?

2: At what distance from the camera is it OK to lose this resolution? That is, pick the farthest distance at which it is now OK for them to Z-fight.

For example, let’s say your units are in inches. And you feel it would be acceptable to have Z-fighting for objects that are closer than 1/4th of an inch, at a distance of 10,000.

For a 24-bit Z-buffer, this would require a Z-near of about 23 inches. If you want to keep 1/4th inch resolution out to the full 26,000 unit range, you need to push the Z-near out to 160 inches.

Pulling the Z-far in isn’t going to help very much.

There are a number of ways to deal with this, including:

  1. [li] Cut your train tracks into the terrain so there is no Z contention[] glPolygonOffset[] Offset projection matrix

Don’t think so.

With a perspective projection, it’s almost all about the near. Push it out as far as you reasonably can.

In practice the far doesn’t matter much at all. Yeah, you can get a little more precision by pulling it in, but nothing like pushing out the near. You can push the far plane way, way out there and see almost no difference. In fact, there is such a thing as a “infinite distance far clip” perspective projection matrix, and no you don’t lose that much Z precision, because there’s very little precision used way out in the far distance (where you can’t see it very well anyway).

Note that none of this discussion applies to an orthographic projection. Only a perspective projection.

Don’t use polygon offset, whatever else you do. Polygon offset sucks because (1) the Z-buffer is non-linear so polygon offset will have different results at different depths, and (2) it can give different results with different implementations too (the spec is actually pretty explicit that the factor param is implementation-dependent: http://www.opengl.org/sdk/docs/man/xhtml/glPolygonOffset.xml).

Double-check your Z-buffer resolution. If you are requesting a 32-bit depth buffer for example, you will need to be aware that such a thing does not actually exist on the vast majority of modern consumer hardware. So you may be getting a 24-bit depth buffer or even a 16-bit one instead. Better to request 24-bit Z explicitly to ensure that you definitely get the higher resolution (also check if you’re getting stencil if you do this, and remember to clear stencil as well as depth at the same time, even if you’re not using stencil).

Like others have said, pushing out your zNear is the only real way to do it. 1 is probably too close, so I’d start at maybe 4 and adjust up or down until you find a value that works well.

Thanks guys for all your help.

I’ve been playing around with the z-near value and it’s improved things substantially.

The links were awesome as well.