Graphics glossary 24 terms mentioned in this lesson
Select any term for a clear definition. The return button brings you back to the exact term link you used.
A surface does not become bright merely because a light exists somewhere in the scene. The light has a direction and distance from the hit point; the surface has a normal; the camera supplies a viewing direction. Local illumination is a calculation over those relationships. We shall use a deliberately compact point-light model so each term can be inspected before more complete light transport is attempted.
The model is not a claim that real surfaces consist of one diffuse term and one artificial highlight. It is a teaching instrument. It lets us separate broad orientation-dependent response from a narrower view-dependent response, then prepares the same directions used by shadow, reflection and transmission rays.
What you should be able to account for
- Construct unit light and view directions at a hit point.
- Calculate a clamped Lambertian diffuse term and a half-vector specular term.
- Explain what a locally lit pixel proves and why it does not yet prove that the light is visible.
Construct the directions at the surface
Let P be the hit position and Lpos the point-light position. The displacement to the light gives both distance and direction. These must be obtained before normalisation because normalisation deliberately removes the magnitude.
const toLight = subtract(light.position, hit.position);
const lightDistance = length(toLight);
const L = scale(toLight, 1 / lightDistance);
const V = normalise(scale(ray.direction, -1));
const N = hit.normal;
V points from the surface back towards the camera ray origin. N already opposes the incoming ray because Lesson 6 oriented the record. L points from the surface to the light. Giving all three names prevents a common error in which a vector points in the opposite direction from the formula that consumes it.
Diffuse response measures projected orientation
An ideal Lambertian diffuse term is proportional to the cosine between the normal and light direction. For unit vectors that cosine is their dot product. Negative values mean the light lies behind the oriented surface and must not subtract colour, so the value is clamped to zero.
diffuse = max(0, N · L)
const diffuse = Math.max(0, dot(N, L));
const diffuseColour = scale(hit.material.albedo, diffuse);
When the light is directly along the normal, the term is one. At a grazing angle it approaches zero. This produces the smooth variation that made the unlit sphere appear flat in Lesson 4. The gradient is not painted onto the circle. It comes from a different surface normal at each hit position.
A compact specular term uses the viewer
Diffuse appearance in this ideal model does not depend on the view direction. A specular highlight does. We shall use the normalised half vector between L and V, then raise its alignment with the normal to a material exponent.
H = normalise(L + V)
specular = max(0, N · H)shininess
const H = normalise(add(L, V));
const specular = Math.pow(
Math.max(0, dot(N, H)),
hit.material.shininess
) * hit.material.specular;
A larger exponent narrows the highlight around strong alignment. It does not make a material physically correct merely by looking glossy. The value is a parameter in this local model. Its purpose here is to make the view-light-normal relationship visible and to distinguish a broad diffuse response from a concentrated one.
Local-lighting laboratory
Separate Diffuse from Specular
Move the light to change its direction, then change the exponent separately and account for the diffuse and specular calculations at one surface point.
Change this, then watch this: Move the light to change L and the dot products. Change only the exponent to alter the final specular term while N · H stays fixed.
- Unit light direction L
- Diffuse N · L
- Specular N · H
- Specular term
diffuse = max(0, N · L)
specular = max(0, N · H)^s
What this establishes:
Distance is another part of the question
The light displacement had a length before we normalised it. A point source's irradiance falls with the square of distance in an unobstructed setting, so a simple attenuation uses intensity / distance². Our laboratory clamps the result to keep a small teaching scene displayable when the light moves close to a surface.
const attenuation = Math.min(
1.45,
light.intensity / (lightDistance * lightDistance)
);
const direct = add(
scale(diffuseColour, attenuation),
scale(light.colour, specular * attenuation)
);
The clamp is an explicit display policy, not part of the inverse-square relationship. A more complete renderer would define units, exposure, source extent and a tone-mapping process rather than protecting the display at this point. We keep the compromise visible because unlabelled convenience quickly becomes false theory.
Compare three orientations
If N · L = 1, the diffuse factor is one. If the angle is 60 degrees, the factor is 0.5. If the light direction lies behind the surface and the dot product is -0.3, clamping gives zero. The last surface receives no direct diffuse contribution from this light under the model. It must not become negative or borrow light from the other side of the normal.
The missing visibility test
Move the point light in the laboratory. The diffuse response moves and the highlight changes. Now place another sphere between the hit and the light. The current calculation still illuminates the surface because it considers direction and distance but never asks whether that route is blocked.
This is the tempting success to challenge. A correctly shaped highlight demonstrates that several vectors and dot products are plausible. It does not demonstrate light visibility. Local illumination without a shadow query behaves as though every point light can see through every object. Lesson 8 repairs exactly that missing criterion with another ray.
Do the directional test
N = (0, 1, 0). One unit light direction is (0, 1, 0); another is (1, 0, 0); a third is (0, -1, 0). What diffuse factor does each produce?
Reveal the calculation
The dot products are 1, 0 and -1. After clamping, the diffuse factors are 1, 0 and 0. The perpendicular light is at a grazing angle; the final light lies behind the oriented surface.
Separate the terms
Add diagnostic modes that display diffuse response alone, specular response alone and their combination. Move the light and camera separately. Identify one change that affects both terms and one that affects only the specular term in this model. Record the vectors and dot products for the centre of one sphere rather than relying on the picture.
Keep this model for Vulkan
The dot products and half vector map directly to shader operations. Vulkan will require us to decide where camera, light and material data live and how shader invocations read them. Before those resource decisions, the values must agree on coordinate space and direction convention. A fast dot product between unrelated spaces remains wrong.
We can calculate how a visible light would affect a surface, but we have not established that it is visible. Lesson 8 sends a bounded shadow ray from the hit point towards the light and confronts the zero-distance surface from which that ray begins.