10.10 - Fragment Shader Debugging

A fragment shader program performs calculations to assign a color to a pixel in a rendering. 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. The following are several suggestions for developing and debugging fragment shader programs.

Do Your Homework!

The easiest way to minimize debugging is to write a correct shader program. 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. You can substitute various values into this color variable and visualize the values of intermediate calculations by examining the rendering output. 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 88 of the fragment shader.

Experiment #1

gl_FragColor = vec4(fragment_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 fragment_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(fragment_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
../_static/10_light_attenuation/light_attenuation.html

Experiment with Light Attenuation

Virtual World  Ambient, Diffuse, Specular w/ Attenuation
Please use a browser that supports "canvas"   Please use a browser that supports "canvas"
camera eye (0.0, 0.0, 5.0) camera center (0.0, 0.0, 0.0)
X: -5.0 +5.0 X: -5.0 +5.0
Y: -5.0 +5.0 Y: -5.0 +5.0
Z: -5.0 +5.0 Z: -5.0 +5.0
light position(3.0, 0.0, 5.0) light color (1.00, 1.00, 1.00)
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
ambient intensities
(0.30, 0.30, 0.30)
attenuation
1.0/(1.0 + 0.10*d + 0.00*d^2)
Red: 0.0 1.0 c1: 0.0 3.0
Green: 0.0 1.0 c2: 0.0 3.0
Blue: 0.0 1.0
Change all intensities at once.
shininess = 30.0
0.1 128.0
Red Cube
Red X
Green Cube
Green Y
Blue Cube
Blue Z
White Cube
Change the shininess of all models.

Show: Process information    Warnings    Errors
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, so do your best to write them bug free from the very beginning.

Glossary

debugging
The art and science of finding mistakes in a computer program.
Next Section - 11.1 - Introduction to Surface Properties