9.6 - Fragment Shader Debugging

A fragment shader performs calculations to assign a color to a pixel in a rendering. For the purposes of these tutorials on lighting, a fragment shader performs the calculations of a lighting model to assign a color to a pixel.

Fragment shaders can be difficult to debug. Debugging a normal computer program is typically done in one of two ways: 1) print intermediate values to a console window, or 2) use an interactive debugger to set breakpoints and step through the code one statement at a time. Neither method works for fragment shaders running on a GPU. So how can you debug a fragment shader if it is not working correctly?

Do Your Homework!

The easiest way to minimize debugging is to write a correct shader program that functions correctly. This might sound silly, but if you create good logic and good equations on paper before you start coding, it can save you the hassle of debugging. Do your homework! Don’t skimp on the design phase. Don’t guess and “hope it works.” Do meticulous design, and sometimes debugging is not required.

Substitute Intermediate Values for Colors

The only output of a fragment shader is the color of the pixel stored in the gl_FragColor output shader variable. We can substitute various values into this color variable and visualize the values of intermediate calculations by examining the output rendering. Experiment with the following WebGL program by reassigning the gl_FragColor value to various values. Note that a color is defined as three distinct values, as is a vertex and a vector. The only difference is the permitted range for each value. A color component is always a value between 0.0 and 1.0. So in some cases you might need to scale or manipulate the intermediate values before putting them into the gl_FragColor variable.

Try these variable substitutions as you experiment with the WebGL program below. You will be changing line 72 of the fragment shader.

Experiment #1

gl_FragColor = vec4(vertex_normal, v_Color.a);

Make sure you click on the “Re-start” button after you make the change. You should see a color in each pixel that represents the normal vector for each pixel. The normal vector was normalized, so each component value is between -1.0 and +1.0. When this is used as a color, the negative values will be clamped to 0.0. If you see red, the vector is pointing along the X axis. If you see green, the vector is pointing along the Y axis. If you see blue, the vector is pointing along the Z axis. Make sure you move the camera so that the vertex normals are changing. If you see only black, then the vertex normals are (0.0, 0.0, 0.0) and there is some error related to retrieving or calculating the normal vector.

Experiment #2

gl_FragColor = vec4(abs(vertex_normal), v_Color.a);

The abs() function will invert any negative values in the normal vector, but you won’t know which values were negative. This output might confuse you more than help you.

Experiment #3

gl_FragColor = vec4(cos_angle, cos_angle, cos_angle, v_Color.a);

This displays the cos(angle) as an intensity value from white (1.0) to black (0.0). This can be very helpful in debugging the angle.

Experiment #4

gl_FragColor = vec4(v_Vertex, v_Color.a);

This displays the 3D location of each vertex as a color. You could use this to “sanity check” your vertex transformations.

Experiment #5

gl_FragColor = vec4(reflection, v_Color.a);

This displays the reflection vector of each fragment (pixel) as a color. You could use this to “sanity check” your reflection vector calculations.

Experiment

Show: Code Canvas Run Info
./light_combined/light_combined.html

Manipulate the properties of a light source and a camera.

The left canvas shows the relative location of the light source, the camera, and an object.
The right canvas shows the scene from the camera's vantage point with the light source used to render the model using ambient, diffuse, and specular lighting combined.
Please use a browser that supports "canvas" Please use a browser that supports "canvas"
Manipulate the camera: Ambient light: Light properties:
eye (0.0, 0.0, 5.0) ambient percentages (0.2, 0.2, 0.2) light location (3.0, 3.0, 3.0)
X: -5.0 +5.0 Red   : 0.0 1.0 X: -5.0 +5.0
Y: -5.0 +5.0 Green: 0.0 1.0 Y: -5.0 +5.0
Z: -5.0 +5.0 Blue  : 0.0 1.0 Z: -5.0 +5.0
center (0.0, 0.0, 0.0) ambient percentage = 0.2
0.0 1.0
light color = (1.0, 1.0, 1.0)
X: -5.0 +5.0 Red: 0.0 1.0
Y: -5.0 +5.0 Green: 0.0 1.0
Z: -5.0 +5.0 Blue: 0.0 1.0
shininess = 30.0
0.1 128.0

Shader errors, Shader warnings, Javascript info
Open this webgl program in a new tab or window

Summary

Putting intermediate calculated values into the gl_FragColor variable is an art more than a science. Be creative! Debugging shader programs can be very challenging.

Glossary

debugging
The art of finding mistakes in a computer program.
Next Section - 9.7 - Light Attenuation