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¶
Experiment with Light Attenuation
Virtual World Ambient, Diffuse, Specular w/ Attenuationcamera 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. |
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.