In 3D graphics “Z-Fighting” is an artifact of the depth buffer.
Here’s a quick rundown of the basic 3D pipeline to give some context:
-
Shapes are represented in 3D euclidean space (X = forward/back, Y = left/right, Z = up/down) as a bunch of dots connected by triangles.
-
These shapes are projected into camera / screen space (This converts the X,Y,Z coordinates into screen coordinates [X = Left/Right, Y = Up/Down]).
-
Shapes are then rasterized (filled in) on the screen.
A problem arises when you have shapes that overlap.
Like when you’re rendering a player model.
If you were to draw the player in profile view on paper, you’d probably draw the furthest arm first, then the body, then the nearest arm such that things that were occluded would naturally get drawn over.
Now, this can be done by sorting all the triangles and shapes by distance, but that’s expensive to do. So here’s how it really works.
During the rasterization (fill-in) phase, the graphics card puts the colors of the texture on the screen pixel by pixel.
But before doing that we draw the depth (distance from camera) pixel by pixel.
As the graphics card goes to fill in a pixel, it checks the depth-buffer to see what the last written depth at that pixel is.
If the previously written value is greater than the value we want to add (far), we update it and fill in a color.
If the previously written value is less than the value we want to add (near), we discard the pixel (don’t draw it), thus preserving the previously written color.
This has the effect of sorting elements by depth because we can write over pixels that are further away, but preserve pixels that are closer.
NOW, here’s where Z-Fighting comes in.
The depth buffer uses values known as floating-point numbers.
These numbers are great because they can represent fractional amounts and performing mathematical operations on them is very fast (graphics cards are specifically optimized to do floating-point operations, G-FLOPS / T-FLOPS of speed).
However, one of the side-effects of floating-point numbers is that once you get to working with really small fractional differences (0.001 - 0.0005 for instance), the numerical accuracy starts to deteriorate. Soon numbers that shouldn’t be equal, are equal. or are greater / less than they should be.
This is the Z-Fighting, numbers that are really really close such that it because difficult to determine which pixels to discard or keep, thus the shapes fight each other to get into the frame-buffer.