Home / Materials
Materials
A material describes how a surface looks: its colour, its shininess, its
metal/roughness, its reflection and its transparency. The engine offers two illumination models —
PHONG and PBR — and a common set of fields
serialized identically in scene files and in the personal library. Everything on this page comes
from srcs/common/Material.hpp and the SceneParser::parseMaterial
function.
Illumination models
Each material carries a model field that selects the shading model. Two values are
recognized by the parser (case-insensitive); any other value raises a loading error.
model | Model | When to use it |
|---|---|---|
"phong" | PHONG (default) | Simple, fast materials: plastics, matte or painted surfaces, prototyping. Direct control through base_color, specular and shininess. |
"pbr" | PBR | Physically plausible rendering: metals, dielectrics, clearcoat, sheen. Control through metallic, roughness, ao and the advanced parameters. |
The default model is PHONG (MaterialModel::PHONG).
Fields for both models live in the same Material struct: a PBR material ignores
shininess/specular when shading, and a PHONG material ignores the PBR
parameters — but every field is still present and serialized.
{
"name": "Matte red",
"model": "phong",
"base_color": [200, 40, 40]
}
PHONG model
The PHONG model combines three classic terms. The final colour of a lit point is the sum of an
ambient component, a diffuse component (Lambert's law,
proportional to N·L) and a specular component (glossy highlight).
| Term | Fields involved | Role |
|---|---|---|
| Ambient | base_color, scene ambient coefficient | Uniform base lighting, independent of direct lights. |
| Diffuse | base_color | Matte scattering: depends on the angle between the normal and the light. |
| Specular | specular, shininess | Glossy highlight toward the viewer; shininess is the exponent that tightens the highlight (larger = smaller, sharper spot). |
By default specular is [0,0,0] (no highlight) and shininess
is 32. For glossy plastic, give a non-zero specular colour (for example a light grey)
and raise shininess.
PBR model
The PBR model follows a metallic-roughness workflow: the base colour is the albedo of a dielectric and the reflection colour of a metal, while roughness controls the sharpness of reflections. Advanced parameters add clearcoat, sheen and transmission.
| Field | Range | Role |
|---|---|---|
base_color | RGB 0–255 | Albedo (dielectric) or metallic reflection colour. |
metallic | 0–1 | Metalness: 0 = dielectric, 1 = pure metal. |
roughness | 0–1 | Micro-surface roughness: 0 = sharp mirror, 1 = very diffuse. |
ao | 0–1 | Ambient occlusion: attenuates ambient lighting. |
specular_level | 0–1 | Strength of the dielectric specular highlight. |
specular_tint | 0–1 | Tints the highlight toward the base colour instead of white. |
clearcoat | 0–1 | Clearcoat: strength of a thin extra clear layer. |
clearcoat_roughness | 0–1 | Roughness of the clearcoat layer. |
sheen | 0–1 | Velvet-like effect at grazing angles (fabrics). |
sheen_tint | 0–1 | Tints the sheen toward the base colour. |
transmission | 0–1 | Fraction of light transmitted through the surface (translucent materials). |
When shading in PBR, a metallic material (metallic close to 1) reduces
its diffuse ambient component: the colour comes mostly from reflections. Remember to provide
geometry and lights around a metal (see Tips).
Reflection and transparency
Four fields, shared by both models, drive secondary rays and opacity:
| Field | Range / type | Role |
|---|---|---|
reflectivity | 0–1 | Mirror reflection amount (reflected ray from the hit point). |
transparency | 0–1 | Transparency: fraction of the ray transmitted through the surface. |
ior | number (default 1.5) | Index of refraction: bending of the transmitted ray at the interface (1.0 = air, ~1.33 = water, ~1.5 = glass). |
alpha | 0–1 | Overall surface opacity (1 = opaque). |
Without a skybox, highly reflective or transparent surfaces can appear dark where the secondary ray hits no lit geometry. See the Tips section.
All fields
The table below lists every field of the Material struct, with its
JSON name, type, range, real default value and role. The "Alias" column shows the extra keys the
parser accepts (camelCase variants).
| JSON key | Recognized alias | Type | Range | Default | Role |
|---|---|---|---|---|---|
name | — | string | — | "material" | Material name (referenced by scene objects). |
model | — | "phong"/"pbr" | — | "phong" | Illumination model. |
base_color | — | RGB | 0–255 | [229,229,229] | Base colour (albedo). |
specular | — | RGB | 0–255 | [0,0,0] | Specular colour (PHONG). |
shininess | — | number | > 0 | 32 | Phong specular exponent. |
reflectivity | — | number | 0–1 | 0 | Mirror reflection amount. |
transparency | — | number | 0–1 | 0 | Transparency. |
ior | — | number | ≥ 1 | 1.5 | Index of refraction. |
metallic | — | number | 0–1 | 0 | Metalness (PBR). |
roughness | — | number | 0–1 | 0.5 | Roughness (PBR). |
ao | — | number | 0–1 | 1 | Ambient occlusion (PBR). |
specular_level | specularLevel | number | 0–1 | 0.5 | Specular level (PBR). |
specular_tint | specularTint | number | 0–1 | 0 | Specular tint. |
clearcoat | — | number | 0–1 | 0 | Clearcoat strength. |
clearcoat_roughness | clearcoatRoughness | number | 0–1 | 0.03 | Clearcoat roughness. |
sheen | — | number | 0–1 | 0 | Sheen effect. |
sheen_tint | sheenTint | number | 0–1 | 0.5 | Sheen tint. |
transmission | — | number | 0–1 | 0 | Light transmission. |
alpha | — | number | 0–1 | 1 | Opacity. |
normal_map | — | path | — | "" | Path to a normal map. |
normal_map_enabled | — | boolean | — | false | Enables the normal effect (also accepts a non-zero number). |
normal_scale | — | number | 0–1 | 1 | Strength of the normal effect. |
normal_noise_frequency | — | number | > 0 | 1 | Frequency of the procedural normal noise. |
texture_map | — | path | — | "" | Colour texture (PNG/JPG) sampled as base colour. |
texture_map_enabled | — | boolean | — | false | Enables the colour texture (also accepts a non-zero number). |
texture_uv_scale | — | number | > 0 | 1 | UV tiling factor. |
Default colours are stored as floats in the struct
(base_color = {0.9, 0.9, 0.9}) but are written as integer RGB on 0–255 in JSON, hence
[229,229,229]. Unknown keys are simply ignored by the parser.
Textures and normal maps
A material can sample a colour texture and apply a normal
perturbation. Images are loaded through stb_image (common formats: PNG, JPG,
etc.), converted to RGB and cached by path (TextureCache), then sampled bilinearly with
UV wrapping (repeat).
Colour texture
If texture_map_enabled is true and texture_map is non-empty, the point's
base colour is read from the texture at the hit's uv coordinates, multiplied by
texture_uv_scale (tiling factor). Raising texture_uv_scale repeats the
pattern more often across the surface.
{
"name": "Tiled floor",
"model": "pbr",
"roughness": 0.7,
"texture_map": "tests/textures/tiles.png",
"texture_map_enabled": true,
"texture_uv_scale": 4.0
}
Normal maps
The normal_map field stores a path, and normal_map_enabled turns the
effect on. The engine applies a procedural normal perturbation based on Perlin
noise when the effect is enabled and no image path is given: normal_noise_frequency
sets the scale of the relief and normal_scale (clamped to 0–1) how strongly it blends
with the geometric normal.
The normal_map path and the normal_map_enabled state are
kept and serialized identically, but the procedural relief in the render kernel kicks in
when normal_map_enabled is true and normal_map is empty (Perlin noise).
The colour texture, on the other hand, is genuinely sampled from the texture_map
file.
Material library
Materials can be saved into a personal library (MaterialLibrary)
located in ~/.raytracer/materials/. Each material is stored in a
<name>.json file. The name is sanitized to form the filename: any
non-alphanumeric character (other than - and _) becomes _,
and an empty name becomes material.
| Operation | Effect |
|---|---|
directory() | Returns (creating if needed) ~/.raytracer/materials; empty if HOME is unset. |
save(material) | Writes <sanitized-name>.json (JSON indented with 4 spaces). |
remove(name) | Deletes the matching file. |
loadAll() | Loads every .json in the folder and sorts them by name; invalid files are skipped. |
Serialization (MaterialLibrary::toJson / fromJson) is
shared with the scene loader/saver: a material round-trips identically whether it
lives in the library or is embedded in a scene file. Colours (base_color,
specular) are written as integer RGB [r,g,b] on 0–255.
Material market
The graphical interface provides a Material Market window
(MarketWindow) with two tabs:
| Tab | Source | How it works |
|---|---|---|
| Local | Library ~/.raytracer/materials | Lists saved materials (via loadAll()), with name search, a detailed preview and an Add button to inject them into the current scene. |
| Online | Poly Haven catalogue (CC0) | Fetches the texture list from api.polyhaven.com (via curl), showing thumbnails, author, categories and resolution. Add downloads the diffuse texture into ~/.raytracer/textures and creates a PBR material using it as texture_map. |
Materials added from the Online tab are created as PBR
(roughness ≈ 0.6, non-metallic), their base colour seeded from the thumbnail's average colour, then
saved into the local library. The online tab needs a connection and the curl
tool.
Examples
Three typical materials, in the format accepted by the scene parser and the library.
Matte plastic (PHONG)
{
"name": "Red plastic",
"model": "phong",
"base_color": [200, 40, 40],
"specular": [60, 60, 60],
"shininess": 24.0,
"reflectivity": 0.05
}
Brushed metal (PBR)
{
"name": "Gold metal",
"model": "pbr",
"base_color": [212, 175, 55],
"metallic": 1.0,
"roughness": 0.25,
"ao": 1.0,
"specular_level": 0.5,
"reflectivity": 0.4
}
Transparent glass (PBR)
{
"name": "Glass",
"model": "pbr",
"base_color": [230, 240, 245],
"roughness": 0.02,
"transparency": 0.9,
"transmission": 1.0,
"ior": 1.5,
"reflectivity": 0.1,
"alpha": 0.2
}
Tips
The engine has no skybox: a secondary ray (reflection or refraction) that heads into the void returns no light. Metals and glass then appear dark. A few reflexes:
- Surround reflective/transparent surfaces with lit geometry (a floor, walls, other objects) so reflections and refraction catch something.
- Add lights visible from those surfaces (see Lights).
- If a metal or glass stays too dark, lower
reflectivityandtransparencyand raise the diffuse share (lighterbase_color, lowermetallic) to keep the surface readable. - For a sharp reflection, keep
roughnesslow (PBR) orshininesshigh (PHONG); for a satin look, raiseroughnessgradually.