PAJAMA / RELIGHT

01 / 08 · RELIGHTING

A color is not a material

Separate camera motion, light motion and material changes.

Start with a painted orange

A photo records light that reached the camera. An orange patch may look dark because its paint is dark, its normal faces away, or another object blocks the light. One RGB value cannot tell you which explanation is correct.

Base color is a material parameter in linear RGB. For a dielectric it controls diffuse reflectance; for a metal it sets colored specular reflectance in our metallic workflow. Observed RGB already mixes material, illumination, visibility and camera response.

Why appearance SH cannot simply accept a new light

Ordinary appearance SH stores a function of viewing direction v. Its RGB coefficients were fitted under the capture lighting. Moving the camera changes v; moving a light does not change those stored coefficients. A new light is a new input the original model was never asked to explain.

The current STG-Lite loader uses direct RGB, not a general SH material. Its normal-named slots are not a verified surface-normal field. This lab therefore uses an analytic surface with authored normals and materials. It does not recover materials from that research asset.

c(v)=∑kckYk(v)versusLo=R(geometry,material,light,v)c(\mathbf v)=\sum_k \mathbf c_kY_k(\mathbf v)\qquad\text{versus}\qquad L_o=R(\text{geometry},\text{material},\text{light},\mathbf v)

Try one controlled change

Select Base color in the lab and move the light: the surface color must stay fixed. Switch to Combined: now the lit region moves. Finally rotate the camera: the specular response changes even though the light stays in world space.

Predict it, then run it

Open this experiment →

The formula meets actual code

This excerpt is extracted from the repository during the site build. SH environment lighting and inverse training are future extensions; their chapters point to the current direct-light/data boundary, not an implemented trainer.

src/relight.rs · L19–28
#[repr(C)]
#[derive(Clone, Copy, Pod, Zeroable)]
struct Splat {
    center: [f32; 4],
    u: [f32; 4],
    v: [f32; 4],
    w: [f32; 4],
    normal: [f32; 4],
    base: [f32; 4],
}

Check your understanding

Why is multiplying captured RGB by a new Lambert term usually wrong?

Reveal the reasoning

The old shading is already baked into captured RGB. Multiplication adds new shading without removing old shadows or highlights.