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

Introduction to the shader programming language

4.0.5. Debugging a shader

This post is also available in…

When we write a script in C#, in Unity we can debug our program using the Debug.Log (object message) function. This function allows us to print an operation of our code on the console, however, this function is not available in Cg or HLSL.

So how can we debug a shader? For this, we must consider several factors, including: “the colors”. In a shader, there are three important colors that we see constantly, these are white (1, 1, 1, 1), black (0, 0, 0, 1) and magenta (1, 0, 1, 1). White represents a default value, while black represents an initialized value. Magenta represents a graphics error, in fact, it is very common to import assets to Unity that are magenta into our scene.

(Fig. 039)

To address this concept, let’s recall the Properties declaration in ShaderLab, for this, we will recreate a color property. 

_Color (“Tint”, Color) = (1, 1, 1, 1)

In the example above, the property has been declared with a color “white” by default, we can corroborate this in the four-dimensional vector; at the end of the operation (1, 1, 1, 1). This property as such will generate a “color selector” in the Unity Inspector and its color and/or initialization value will be white. 

Let’s analyze another property.

_MainTex (“Texture”, 2D) = “white”{}

Again, this property as such will generate a “texture selector” in the Unity Inspector, but what will its default color be if we don’t use any texture? Its color will be white, we can confirm this in the declaration “white” found on the property. 

We see the color black frequently in declarations of internal vectors and variables in our code, in fact, it is very common to initialize vectors to “zero” and then add some operation, e.g., the four-dimensional vector “float4 col = 0” has been initialized to “0”, this means that all its channels (RGBA) will have a default value of zero. 

Note that white represents the maximum illumination value of one pixel and black represents its minimum illumination. It is important to remember this since, as we move forward, we will have some operations that will exceed the maximum (x > 1) and minimum (x < 0) values. In these cases, color saturation occurs and for this, we will use some functions like “clamp” that will allow us to limit a value between two numbers (minimum and maximum).

Why do our objects sometimes appear magenta? As we already know, this color represents a “graphical error”. Basically, when the GPU could not carry out the operations found within the shader, it returns a default magenta color. In Unity, the reasons for this color are mainly due to two factors: 1. that the render pipeline has not been configured or 2. that the shader has an error in its code. 

When we import an asset into the software, the first thing we need to know is, which render pipeline are we working in? Remember that in Unity there are three types of render pipeline and each one has a different configuration. 

Suppose we import an asset that includes a material with a Standard Surface shader in Universal RP then our asset will appear in magenta because this type of shader is supported only in Built-in RP. To solve this graphical error, we have to select the material, go to the inspector and change the type of shader to one found in “Shader Graphs”. 

Once we have identified the type of rendering pipeline that we are using we must proceed to shader evaluation. 

The errors in a shader are graphically evident since the objects acquire a magenta color. If we pay attention to the console, we can find its definition. To solve them, we must consider some factors: completing an instruction or function in HLSL and ShaderLab. Most errors are generated by misspelling or syntax. Below we will review a reasonably common one:

// in console
Shader error in “Unlit/ simpleColor”: syntax error: unexpected token '}' at line 60 (on d3d11)

How can we read the above statement? In this case, the shader found in the “Unlit” menu, called “USB_simple_color”, has an error in code line 60 and cannot be compiled in Direct3D 11.

Now, is that a shader problem? To do this, we are going to analyze the line of code that is generating the error.

58    fixed4 frag (v2f i) : SV_TARGET
59    {
60        fixed4 col = tex2D(_MainTex, i.uv); 
61        return col
62    }

According to the console, the error is being generated in code line number 60, As we can see, there is no problem there. We have to ask ourselves then, what is happening? The error is because we forgot to close the operation in code line number 61. If we look at the return we will realize that the col vector is missing a semicolon (;) so the GPU thinks that the operation continues, so it can’t compile it. 

The following is another error that we see frequently:

Shader error in 'Unlit/simpleColor': cannot implicitly convert from 'half2' to 'half4' at line 60 (on d3d11)

half4 frag (v2f i) : SV_TARGET
{
    half4 col = tex2D(_MainTex, i.uv); 
    half2 uv = 0;
    col = uv;
    return col;
}

In this case, the error has been generated because we are trying to convert a four-dimensional vector (col) into a two-dimensional one (uv). The col vector, being four-dimensional, has RGBA or XYZW channels, on the other hand, the uv vector, being two-dimensional, only has the combination of two channels (RG, RB, GB, etc), therefore it cannot be converted from a two-dimensional vector to one of four.

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-logo

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.