Lighting Basics
How lighting works in shaders — from simple diffuse to specular highlights, and the math behind each model.
Turn the guide into code
Take the key idea from this page into the playground and validate it in a real shader instead of leaving it as theory.
Open PlaygroundLighting is where shaders go from "colored shapes" to "things that look real." All lighting models boil down to the same question: how much light reaches the camera from this surface point?
The Three Ingredients
Every lighting calculation needs three vectors at the fragment being shaded:
- N — the surface normal (which way the surface faces)
- L — the light direction (from surface toward the light)
- V — the view direction (from surface toward the camera)
fragment {
float3 N = normalize(input.normal);
float3 L = normalize(resources.lightPos - input.worldPos);
float3 V = normalize(resources.cameraPos - input.worldPos);
}
All three must be normalized (unit length) for the math to work correctly.
Ambient
The simplest lighting — a constant amount of light everywhere. Prevents surfaces facing away from the light from being pure black.
Ambient is a rough approximation of indirect light (light bouncing off other surfaces). It's fake but cheap. On its own it looks flat — there's no sense of shape because there's no variation across the surface.
Diffuse (Lambertian)
Diffuse lighting simulates rough surfaces that scatter light equally in all directions. The brightness depends only on the angle between the surface normal and the light direction:
The max(..., 0.0) clamps negative values — surfaces facing away from the light don't receive negative light.
This single dot product is the most important equation in real-time lighting. A surface facing the light head-on (NdotL = 1.0) is fully lit. A surface at 90 degrees (NdotL = 0.0) receives no direct light.
Specular (Blinn-Phong)
Specular lighting creates the bright highlight you see on shiny surfaces. It depends on the half vector — the direction halfway between the light and view directions:
The shininess exponent controls how tight the highlight is:
- Low values (8–16): wide, soft highlight (plastic, rubber)
- High values (64–256): tight, sharp highlight (metal, glass)
Putting It Together
A complete Blinn-Phong lighting model with ambient + diffuse + specular:
Hemisphere Lighting
A better ambient that varies between a sky color (up) and a ground color (down), based on the normal direction. Much more convincing than flat ambient:
Rim Lighting
Bright edge glow when the surface faces away from the camera. Common for character highlights and sci-fi effects:
The rim effect works because 1.0 - dot(N, V) is highest at glancing angles where the surface curves away from the viewer. The pow tightens the falloff.
Fresnel
Surfaces become more reflective at glancing angles — this is the Fresnel effect. It's what makes water, glass, and car paint look reflective at the edges:
The Schlick approximation (f0 + (1-f0) * (1-NdotV)^5) is used in virtually every modern renderer. f0 is the reflectivity at head-on viewing — 0.04 for dielectrics (plastic, skin), higher for metals.
Beyond Blinn-Phong
Blinn-Phong is a good starting point but has limitations — it can't represent metallic surfaces, energy conservation, or physically accurate Fresnel. For more realistic materials, see Physically Based Rendering, which uses the Cook-Torrance model with:
- Roughness instead of shininess
- Metallic parameter for metal vs dielectric surfaces
- Energy conservation (a surface can't reflect more light than it receives)
See Also
- PBR — Physically based materials with interactive demos
- dot — The dot product intrinsic
- normalize — Making vectors unit-length
- Vectors and Matrices — The math fundamentals