Get an 20% OFF using the RELEASE code on your book purchase. For a limited time.

Introduction to the shader programming language

3.2.0. SubShader Culling and Depth Testing

This post is also available in…

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.

(Fig. 028. The Z-Buffer stores the depth of the object in the scene, and the Color Buffer stores the RGBA color information). 

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.

(Fig. 029)

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.

Follow us to stay informed about all the latest news, updates, and more.

Join the group to share your experiences with other developers.

Subscribe to our channel and keep learning game dev!


Jettelly Team

We are a team of indie developers with more than 9 years of experience in video games. As an independent studio, we have developed Nom Noms in which we published with Hyperbeard in 2019. We are currently developing The Unity Shader Bible.

Follow us on our social networks.