To understand both concepts, we must first know how Z-Buffer (also known as Depth Buffer) and Depth Testing work.
Before starting we must consider that the pixels have depth values.
These values are stored in the Depth Buffer which determines if an object goes in front of or behind another on the screen.
On the other hand, Depth Testing is a conditional that determines whether a pixel will be updated or not in the Depth Buffer.
As we already know, a pixel has an assigned value that is measured in RGB color and stored in the Color Buffer. The Z-Buffer adds an extra value that measures the depth of a pixel in terms of distance to the camera, but only for those surfaces that are within its frustum, this permits two pixels to be the same in color, but different in depth.
The closer the object is to the camera, the lower the Z-Buffer value and pixels with lower buffer values overwrite pixels with higher values.
To understand the concept, let’s assume that we have a camera and some primitives in our scene, all positioned on the “Z” space axis. Now, why on the z-axis? The “Z” in Z-Buffer comes from the fact that the Z value measures the distance between the camera and an object on the “Z” axis of space, while the “X and Y” values measure horizontal and vertical displacement on the screen.
The word “Buffer” refers to a “memory space” in which data will be temporarily stored, therefore, Z-Buffer refers to the depth values between the objects in our scene and the camera, which are assigned to each pixel.
For example, we are going to draw a screen with a total of 36 pixels.
Every time we position an object in our scene, that object occupies a certain pixel area on the screen. So, let’s assume that we want to position a green square in the scene. Given its nature, it will occupy from pixel 8 to 29, therefore, all the pixels inside this area are activated and painted green, likewise, this information will be sent to both the Z-Buffer and the Color Buffer.
The Z-Buffer stores the depth of the object in the scene, and the Color Buffer stores the RGBA colour information.
We position a new square in the scene, this time in red and closer to the camera. To differentiate it from the previous one, we will make this square smaller, occupying from pixel 15 to 29. As we can see, this area is already occupied by the information from the initial square, so what happens here? Since the red square is at a shorter distance from the camera, this overwrites the values of both the Z-Buffer and the Color Buffer, activating the pixels in this area, replacing the previous color.
In the case of adding a new element to the scene that is even closer to the camera, this process will be repeated in the same way. In conclusion, the values of the Z-Buffer and Color Buffer will be overwritten by the object that is closest to the camera.
One way to generate attractive visual effects is by modifying the Z-Buffer values. For this, we will talk about three options that are included in Unity: Cull, ZWrite, and ZTest.
Like Tags, culling and depth testing options can be written in different fields: within the SubShader field or the Pass field. The position will depend on the result we want to achieve and the number of passes we want to work with.
To understand this concept, let’s assume that we want to create a shader to represent the surface of a diamond. For this, we will need two passes: The first we will use for the background color of the diamond, and the second for the shine of its surface. In this hypothetical case, since we need two passes that fulfil different functions, it will be necessary to configure the Culling options within each pass independently.