Original Post
Hi, and sorry for this long post, I believe the z-fighting problem can never be totally avoided considering current hardware's architecture. Because of the z-buffer's discrete nature, no matter how many bits of precision it's dedicated and how much its accuracy is increased, one can always reach a threshold where objects of less distance can not be distinguished depth-wise. It's not possible to map an infinite continious space to a finite discrete space such as z buffer. Say, you have a 64-bit z-buffer, a huge z-buffer which by the way is not available on today's hardware, and want to render a scene that is 256 meters long in depth, using orthographic projection. Again, objects that are less distant than 256 meters/ 2^64 == 2^(-56) meters, cause z-fighting problem. Perspective projection also suffers from the same problem, but the calculations are more involved because of depth resolution's non-uniform distribution. Generally, moving zNear and zFar clipping planes has roughly the effect of loosing log2(zFar/zNear) bits of precision. So, as the zNear approaches zero, we loose a GREAT deal of precision as the function approaches infinity. Moving the far plane to infinity loses surprisingly little precision normally, because when the distance to the far plane is significantly greater than the near plane (which is often the case), moving the far plane to infinity has little overall effect on precision. In other words, when the difference between zFar and zNear values is already great, as is the usual case, moving the zFar plane further will not affect the zFar/zNear ratio and hence not much precision will be lost. I've come to the find the following methods useful. I would greatly appreciate your new ideas on how to resolve z-fighting problem or your suggestions on the followings, specially on 4: 1) The best way (though some might argue) to avoid this problem is to totally avoid objects that are very close to each other. This method is specially applicable to static scenes where objects don't move around, so the possibility of them colliding and hence crossing over the threshold is minimal. If the objects don't move, it's possible to find a threshold above which, z-fighting can be avoided, as described above. 2) Another simple but effective method is to move the near plane as far as possible. This will decrease the zFar/zNear ratio and earns us more precision, as discussed above. 3) BSP Trees: BSP trees can be used to render the scene in a back-to-front or a front-to-back order and hence totally eliminate the need for z-buffers. The main problem with rendering in a back-to-front order is the massive overdraw of pixels, where time is wasted drawing objects that will be overdrawn later. PLUS, When using a z-buffer, a pixel can be culled (discarded) as soon as its depth is known, which makes it possible to skip the entire process of lighting and texturing a pixel that would not be visible anyway. This kind of early z rejection in the pipeline can not be utilized when z-buffers are disabled, which is usually the case when using BSP trees. 4) The most general method (meaning that it doesn't need any specific knowledge of the scene) to achieve higher precisions, is to render the scene in several passes. The scene is broken into several, say n, non-overlapping partitions that do not interfere in z. These non-overlapping partitions are then rendered from back to front, each in a distinct rendering pass. The depth buffer is cleared before each rendering pass. This way the precision of the entire depth buffer is made available to each partition. This method sacrifices speed in favour of more precision. 5) The fifth method, which needs specific knowledge of the coplanar objects in the scene, is to use two projection matrices. First, the programmer needs to specify which objects are coplanar and are a candidate for causing z-fighting, then uses one of those projection matrices to render the coplanar object that he wants to put "further", and the other, which is a biased version of the first projection matrix, to render the "closer" one. This method is specially useful for rendering posters, shadows and decals. What makes these examples, all fall in the same group is our knowledge of what objects cause z-fighting. For example, we know which poster belongs to which wall. So, we render all those walls first, switch to the biased projection matrix, and render all those posters in front of them. 6) One other method is to calculate the nearest and farthest vertices to the camera position each frame, and set the near and far planes to these points. This method needs manipulating the projection matrix each iteration of the rendering loop and may not the best option performance-wise. Any ideas/suggestions are welcome. Thanks for investing the time and reading this long post.