Implementing Shading Models in GLSL

JavaOpenGLsource code

Exploring several canonical shading models in GLSL, once again as a fun demonstration of visual effects, but more importantly, as a way of understanding how different algorithms alter the mapping from geometry to appearance.

The shaders presented here were implemented incrementally, with each model emphasizing a particular aspect of light–surface interaction. This is a study in how differeing shading techniques control how vertices and fragments are processed

Gourand Shading

Gouraud shading interpolates vertex colors across the surface of a polygon. Illumination is computed at the vertices, and the resulting colors are linearly interpolated across fragments..

This approach is computationally efficient, but the approximation is evident in scenes with coarse tessellation. I see some lighting discontinuities, and highlights can appear muted or misplaced. Nonetheless, Gouraud shading remains a historically important model and is impressive in how much visual coherence can be achieved with minimal per-fragment computation.

Checkerboard Texture Mapping

Texture mapping associates surface coordinates with image data. The checkerboard texture is a canonical test case because it emphasizes both the correctness of UV parameterization and the interpolation across curved surfaces.

Here, the shader samples from a procedurally defined checkerboard pattern mapped to a sphere. The result illustrates how texture coordinates, once bound to geometry, allow arbitrary visual detail to be introduced without increasing geometric complexity.

Texture Modulated Smooth Shader

Now we combine both interpolated shading with a texture map. In this implementation, per-fragment illumination is computed and then modulated by a texture. The texture provides high-frequency detail, while the shading model provides low-frequency lighting variation.

This dual contribution mirrors how real-world surfaces behave: the underlying material (texture) interacts with global lighting conditions (shading). Implementing this model deepened my appreciation for how compositional shading techniques allow relatively simple algorithms to achieve rich results.

Normal Mapping

Normal mapping is a powerful technique for adding apparent geometric complexity without modifying the mesh itself. Instead of relying solely on interpolated surface normals, the shader samples a normal vector from a texture (a normal map) and uses it in the lighting calculation.

This one was particularly interesting. A flat plane or cube face can appear to have detailed bumps, grooves, or surface irregularities, and this can be achieved at negligible geometric cost. This study brings light to the importance of tangent space, normal map encoding, and consistent coordinate transforms. Errors in these calculations produce immediately visible artifacts.

Toon Shader

Toon shading (or cel shading) departs from physical realism in favor of stylization. Instead of computing continuous variations in shading, the illumination is quantized into discrete bands. Edges may be emphasized through outline detection or color thresholds.

This is my favorite shader as it illustrates how aesthetic goals can diverge from physical accuracy while still relying on the same underlying data. The fragment shader becomes a site of artistic control: the same inputs that produce photorealism under one algorithm can produce stylized, illustrative results under another.

Some Thoughts

It's interesting to see how both physically inspired models (e.g., normal mapping) and stylized models (e.g., toon shading) shows how flexible GLSL is as a medium that opens up oppurtunities to a wide range of representational goals.

This exploration provided a structured way to connect theoretical models of shading to practical implementation, reinforcing both the mathematical underpinnings of graphics and the expressive potential of shader programming. It's nice to understand the historical context of modern graphics, which have evolved into highly impressive techniques today.