Introduction

Every surface you see in a real-time game — the gleam on a helmet, the dull matte of concrete, the bright spot on a billiard ball — is the result of a lighting model. The most influential one in history fits in a single line of arithmetic.

In 1975 Bui-Tuong Phong published his doctoral dissertation at the University of Utah. His insight was to split the light arriving at a surface point into three independent terms that together produce a convincing, if physically approximate, shading:

  • Ambient: a constant base glow that stops surfaces from going completely black in shadow.
  • Diffuse: light scattered equally in all directions from a rough surface, controlled by the angle between the surface normal and the light direction.
  • Specular: a tight, shiny highlight whose position depends on how closely the viewing direction aligns with the reflected light ray.

The beauty of the model is that each term costs almost nothing to evaluate. All three are summed point by point across the surface, giving the smooth gradient that distinguishes Phong shading from flat or Gouraud shading.

Drag the Light

Click or drag anywhere on the canvas to move the light source. The sphere is rendered pixel by pixel using the Phong equation, so you can watch each of the three terms change as the light moves.

<!-- {{c_canvas_comment}} -->
<canvas id="sphere" width="300" height="300" title="{{canvas_title}}"></canvas>
<div class="controls">
  <div class="toggle-row">
    <button id="btnA" class="tog active" type="button">{{btn_ambient}}</button>
    <button id="btnD" class="tog active" type="button">{{btn_diffuse}}</button>
    <button id="btnS" class="tog active" type="button">{{btn_specular}}</button>
  </div>
  <label class="slider-label">
    {{label_shininess}}
    <input id="shine" type="range" min="2" max="128" value="32">
    <span id="shineVal">32</span>
  </label>
</div>
<p class="hint">{{hint_drag}}</p>
/* {{c_layout_comment}} */
* { box-sizing: border-box; }
body { font-family: system-ui, sans-serif; margin: 0; display: flex;
       flex-direction: column; align-items: center; gap: .6rem; }
canvas { border-radius: 50%; cursor: crosshair;
         box-shadow: 0 2px 12px rgba(0,0,0,.25); display: block; }
.controls { display: flex; flex-direction: column; gap: .5rem; width: 300px; }
.toggle-row { display: flex; gap: .5rem; }
.tog { flex: 1; padding: .4rem .5rem; border: 1.5px solid #1d3557;
       border-radius: 8px; cursor: pointer; font: 600 13px system-ui;
       background: #1d3557; color: #fff; transition: background .15s; }
.tog:not(.active) { background: #fff; color: #1d3557; }
.slider-label { display: flex; align-items: center; gap: .5rem;
                font: 14px system-ui; color: #333; }
input[type=range] { flex: 1; accent-color: #1d3557; }
#shineVal { font: 700 14px ui-monospace, monospace; width: 2.5rem; text-align: right; }
.hint { font-size: .85rem; color: #555; margin: 0; text-align: center; }
// Code not found

Toggle the Ambient, Diffuse and Specular buttons to isolate each term. Notice that ambient alone is a flat disk, diffuse alone gives soft roundness, and specular alone is a sharp bright spot. Only together do they produce a convincingly lit surface. The shininess slider controls the exponent nn in the specular term — higher values shrink the highlight to a pinpoint.

The Math

The full Phong illumination at a surface point is:

I=kaIa+kd(N^L^)Id+ks(R^V^)nIsI = k_a I_a + k_d (\hat{N} \cdot \hat{L}) I_d + k_s (\hat{R} \cdot \hat{V})^n I_s

where:

  • N^\hat{N} is the unit surface normal at the point being shaded.
  • L^\hat{L} is the unit vector toward the light source.
  • V^\hat{V} is the unit vector toward the viewer (camera).
  • R^=2(N^L^)N^L^\hat{R} = 2(\hat{N} \cdot \hat{L})\hat{N} - \hat{L} is the reflection of the light direction about N^\hat{N}.
  • ka,kd,ksk_a, k_d, k_s are the ambient, diffuse and specular material coefficients.
  • nn is the shininess exponent — larger nn means a smaller, harder highlight.

The two key dot products each have a physical interpretation. N^L^\hat{N} \cdot \hat{L} is Lambert's cosine law: a surface patch at a glancing angle to the light receives less flux per unit area, so it looks dimmer. (R^V^)n(\hat{R} \cdot \hat{V})^n captures how directly the eye looks into the mirror-reflected ray — a perfectly aligned eye sees the full highlight; rotate it away and intensity drops as the nn-th power.

What makes it "Phong shading" rather than just "Phong lighting" is the normal interpolation trick. Instead of computing one normal per triangle and shading the whole face uniformly (Flat shading) or computing one colour per vertex and interpolating colours (Gouraud shading), Phong shading interpolates the normals across the triangle first, then evaluates the full lighting equation at every pixel. This catches highlights that fall inside a triangle, which Gouraud shading misses entirely.

The model is not physically accurate — energy is not conserved, and real specular reflections are far more complex — but it is fast, intuitive to tweak, and still the backbone of the rasterization pipeline in many real-time engines.

Where It Matters

Phong shading solved a specific, hard problem: making surfaces look round and shiny at interactive speed, before hardware could simulate anything physically correct. Its legacy is everywhere:

  • Real-time game rendering: Phong (and its close variant Blinn-Phong, which replaces R^V^\hat{R} \cdot \hat{V} with the half-vector dot product) is the default lighting model in OpenGL fixed-function and in countless custom GLSL/HLSL shaders.
  • Education: the three-term decomposition is the first lighting model taught in every computer graphics course because it maps directly to physical intuition.
  • Material systems: even modern physically-based rendering (PBR) materials describe themselves in terms inherited from Phong — roughness controls the effective shininess exponent, and metalness adjusts specular colour.
  • Non-photorealistic rendering: toon shaders threshold the Phong terms to create cel-shaded cartoon looks.

Understanding Phong gives you the vocabulary for all subsequent shading work. If you enjoyed the dot-product geometry here, the same ideas extend to ray tracing and more sophisticated global illumination methods.

Conclusion

Phong shading is the art of convincing the eye with the least possible arithmetic. Three terms, two dot products, one shininess exponent — and suddenly a flat triangle looks like a polished sphere.

The model is approximate, not physical. Light in Phong's world does not bounce between surfaces, does not travel, does not obey conservation of energy. But it is fast, predictable, and tunable — which is exactly what a 1975 graphics system needed, and exactly why the formula survived into the era of programmable GPUs. The next time you adjust a "shininess" or "roughness" slider anywhere in a graphics tool, you are still tweaking Bui-Tuong Phong's exponent nn.

Share this article

Pick a channel — or use your device's native share sheet.

Comments

Loading comments...

https://www.kipuhub.com/en/article/phong-shading/Content licensed under CC BY-NC 4.0.