Materials¶
Materials define how surfaces interact with light. In RayON, every material implements two functions: emitted() (returns radiance emitted by the surface) and scatter() (returns a scattered ray direction and an attenuation factor).
Material overview¶
| Type | Enum | Scatters | Emits | Key parameter |
|---|---|---|---|---|
| Lambertian | LAMBERTIAN | ✓ | — | albedo (RGB) |
| Mirror | MIRROR | ✓ | — | — |
| Rough Mirror | ROUGH_MIRROR | ✓ | — | roughness [0–1], tint (RGB) |
| Glass | GLASS | ✓ | — | ior (index of refraction) |
| Area Light | LIGHT | — | ✓ | emission (RGB) |
| Show Normals | SHOW_NORMALS | — | — | debug: normal → RGB |
| Constant | CONSTANT | — | — | debug: solid colour |
Lambertian (diffuse)¶
A perfectly diffuse surface scatters light equally in all directions weighted by the cosine of the angle from the surface normal (Lambert's cosine law):
where \(\rho\) is the albedo — the fraction of light the surface reflects.
Scatter direction: a random point on a unit sphere offset along the surface normal (cosine-weighted hemisphere — see Sampling).
Mirror (perfect specular)¶
A perfect mirror reflects rays using the reflection formula:
where \(\mathbf{d}\) is the incoming direction and \(\hat{n}\) is the surface normal. Attenuation is always 1.0 (no energy loss).
Rough Mirror (microfacet)¶
Extends the perfect mirror with a roughness parameter that adds a random perturbation to the reflected direction:
where \(\xi\) is a random vector in the unit sphere. Rays that scatter back below the surface are absorbed (energy conservation).
A tint (RGB colour) modulates the reflection to produce metallic effects:
Preset tints:
| Metal | Tint RGB |
|---|---|
| Gold | (1.00, 0.85, 0.57) |
| Copper | (0.95, 0.50, 0.30) |
| Steel | (0.80, 0.85, 0.90) |
| Iron | (0.56, 0.57, 0.58) |
| Bronze | (0.80, 0.50, 0.20) |
materials:
- name: gold_sphere
type: rough_mirror
albedo: [1.0, 0.85, 0.57] # tint = gold
roughness: 0.03 # near-perfect reflection
roughness=0.05. The warm tint is visible in highlights.
Glass (dielectric)¶
Glass both reflects and refracts light. The ratio of reflected to transmitted energy is governed by the Fresnel equations, approximated efficiently using Schlick's formula:
Refraction direction follows Snell's law:
When \(n_1 > n_2\) and \(\theta_1\) exceeds the critical angle, total internal reflection occurs and the surface acts as a perfect mirror.
Glass spheres refracting the background. The caustic ring under the sphere is not explicit — it emerges from the path tracing integral.
Area Light¶
Light sources are geometry (rectangles or spheres) with the LIGHT material. The scatter() function returns false (no further bouncing) and emitted() returns the emission colour.
Soft shadows emerge naturally — a larger light source means more rays from the scene "see" the light directly, producing smooth penumbrae.
materials:
- name: warm_white_light
type: light
emission: [5.0, 4.5, 3.5] # HDR — values > 1 are physically valid
geometry:
- type: rectangle
material: warm_white_light
position: [-1.0, 3.0, -2.0]
u_vec: [2.5, 0.0, 0.0]
v_vec: [0.0, 0.0, 1.5]
Cornell box lit by a single rectangular area light on the ceiling. The coloured walls produce visible colour bleeding on the floor and white sphere.
Debug materials¶
Two materials are available for development and debugging:
ShowNormals — maps the surface normal to RGB: [ \text{colour} = 0.5(\hat{n} + \mathbf{1}) ] Red = +X axis, Green = +Y axis, Blue = +Z axis.
Constant — emits a fixed solid colour regardless of lighting. Useful for environment backgrounds.
All surfaces shown with the ShowNormals material. Note how the smooth normal interpolation on the imported mesh makes the face boundaries invisible.
The CRTP material system¶
Both CPU and GPU renderers share the same material dispatch logic. On the CPU, standard C++ virtual functions are used. On the GPU, virtual dispatch is not allowed, so RayON uses a Curiously Recurring Template Pattern (CRTP) with a flat union:
// MaterialParamsUnion — POD struct, GPU safe
union MaterialParamsUnion {
LambertianParams lambertian;
MirrorParams mirror;
RoughMirrorParams rough_mirror;
GlassParams glass;
LightParams light;
};
At runtime the enum tag selects the correct branch — the compiler inlines each case completely, zero virtual-function overhead. See Architecture → Scene System for details about how materials are transferred to the GPU.


