Light, Materials, and BRDFs

Light, Materials, and BRDFs

Intersection tells you where the ray landed. It does not tell you what number to write into the film. Color begins when a material answers how incident light is scattered toward the camera.

Start with direct lighting only: light to surface to eye. Indirect illumination belongs to path tracing. If you jump there first, you will debug five systems at once and learn none of them.

Diffuse lobe and glossy lobe around a surface

A diffuse lobe spreads energy broadly. A glossy lobe concentrates energy near the mirror direction.

Data required at a hit

  • position p
  • unit normal n
  • outgoing direction wo toward the previous path point or camera
  • material parameters
  • texture coordinates when needed

For a point light at light_pos:

to_light = light_pos - p
distance = |to_light|
wi = to_light / distance
cosθ = max(0, n · wi)

If cosθ = 0, that light contributes nothing on this side of the surface.

Lambertian diffuse

For linear albedo a:

f = a / π

A simple point-light estimate without importance-sampling machinery:

L = (a / π) * I * cosθ / distance²

The factor π is required by energy accounting. Omit it and “white” surfaces invent energy when you move to path tracing. Albedo belongs in linear space. Values above 1 are not a style choice; they are a broken material.

Specular reflection

An ideal mirror uses one direction:

r = reflect(incident, n)

Fix one convention for whether vectors point toward the surface or toward the light, and never mix conventions inside one function. Glossy materials place a lobe around the mirror direction. Blinn-Phong is a teaching model. Microfacet BRDFs are what hold up under path tracing.

If you add diffuse and specular lobes, their combined response must remain plausible under bright lights. Random specular coefficients produce glowing plastic.

The reflection equation

A BRDF f(wi, wo) states how radiance from direction wi contributes to radiance leaving toward wo:

Lo(wo) = ∫ f(wi, wo) Li(wi) (n · wi) dwi

Direct lighting approximates the integral with light samples. Path tracing approximates it with recursive path samples. Same equation. Different estimators.

Shadows are part of lighting

A light sample that fails visibility contributes zero. Hard point-light shadows are one visibility query with t_max set to the light distance. Soft shadows are the same idea with many samples over an area light. Do not treat shadows as a separate decorative pass.

Texture color spaces

Albedo maps are usually stored as sRGB and must be decoded to linear before BRDF evaluation. Roughness and metalness maps are commonly linear already. If the scene looks chalky or lifeless under every material, inspect color transforms before rewriting lobe formulas.

Minimum material interface

sample(wo, n, rng) -> wi, pdf, f, specular_flag
evaluate(wo, wi, n) -> f
emit() -> radiance or black

sample proposes the next path direction. evaluate is required when a light sampler chooses wi and asks what the material does. Ideal mirrors evaluate to zero for almost every direction, which is why pure light sampling never finds them alone.

Common errors

  • Albedo greater than one “because the screenshot looked dark”
  • Feeding sRGB texels straight into Lambert
  • Using n · wi without clamping and leaking light through the back face
  • Mixed incident-direction conventions in reflect and the light loop
  • Adding many material knobs before normals and light vectors are correct

When a single hard-shadowed Lambert light looks right on a trusted normal field, materials have an honest place to stand.