Construct material system
PBR material system for 3D parts
Status: Complete Last Updated: 2026-10-19
Overview
A material in Construct is a definition: a shared recipe with a name, parameters, patterns and channels. An item uses a definition through a binding: the definition's id and the parameter values that differ from its defaults. An item without a binding uses the binding of its nearest parent that has one. So you set a material on a tank, and its hatch and its valve take it.
The channels are the inputs of OpenPBR Surface 1.1.1, the open material model of the Academy Software Foundation. One definition renders the same in the three viewport modes, in an export and in a thumbnail. The path tracer shows all of it: coat, transmission, subsurface and flakes. The raster modes show an approximation.
Definitions
A definition is one YAML record. Its keys:
| Key | What it holds |
|---|---|
id |
A slug, such as rusty-steel: lowercase letters, digits and single hyphens. The same in every run and on every machine |
name, summary, family |
The name in the lists, one line about the material, and its group, such as material/metals |
parameters |
The knobs of the definition, each with a name, a type, a default and a range. A binding sets their values |
patterns |
Named scalar fields that the channels read: a noise, a look or a pattern record, in a space |
channels |
One entry per OpenPBR input that the definition drives. A channel that the record does not name takes the OpenPBR default |
An example, the built-in rusty-steel:
id: rusty-steel
name: Rusty steel
summary: Steel with patches of rust that grow with one knob
family: material/metals
parameters:
- name: rust_amount
type: Float
defaultValue: 0.4
minValue: 0
maxValue: 1
- name: rust_scale
type: Float
unit: mm
defaultValue: 20
- name: steel_color
type: Color
defaultValue: [0.56, 0.57, 0.58]
patterns:
rust:
field: noise_perlin
space: object
scale: =rust_scale
parameters: {octaves: 5, lacunarity: 2.0, gain: 0.5}
pits:
field: noise_worley
space: object
scale: =rust_scale * 0.2
channels:
base_color:
gradient:
pattern: rust
remap: {kind: smoothstep, from: [=1 - rust_amount, =1.1 - rust_amount]}
stops:
- {t: 0.0, color: =steel_color}
- {t: 0.6, color: "#7a3b1c"}
- {t: 1.0, color: "#4a2410"}
base_metalness:
pattern: rust
remap: {kind: smoothstep, from: [=1 - rust_amount, =1.1 - rust_amount], to: [1, 0]}
specular_roughness: =mix(0.25, 0.8, rust) + 0.1 * pits
geometry_normal:
bump: {pattern: pits, strength: 0.3}
The sources of a channel
| Kind | Form | Meaning |
|---|---|---|
| Value | 0.3, "#7a3b1c" |
A fixed value. A color is 8-bit sRGB |
| Parameter | =rust_amount |
The binding's value of a parameter |
| Pattern | {pattern, remap} |
A pattern, mapped to the channel's range |
| Gradient | {gradient: {pattern, remap, stops}} |
A pattern through a color ramp of at most 16 stops, for a color channel |
| Expression | =mix(0.25, 0.8, rust) |
An expression over the parameters, the patterns and the math functions |
| Bump | {bump: {pattern, strength}} |
A normal tilted by the slope of a pattern, for geometry_normal and geometry_coat_normal |
A pattern's value is from 0 to 1. A remap is linear, smoothstep or
gamma, with from, to and clamp (on by default). A bound can be an
expression.
Patterns
A pattern names a field record of the field family: a noise, such as
noise_perlin, a look, such as look_marble, or a structure, such as
pattern_bricks. See Noise and patterns.
| Space | The point the pattern reads |
|---|---|
object |
The surface point in the item's own frame. The pattern moves with the item. The default |
world |
The surface point in world space, for a pattern across many items |
item |
The surface point in the frame of a named field item of the scene, with that item's parameters. A scene field and a material then share one field |
scale and offset are in the document's units. A noise fades its finest
octaves as they get smaller than a pixel, so a pattern does not sparkle when
the camera moves away.
Where definitions live
| Home | Where | Notes |
|---|---|---|
| Built-in | In the application, one record per material | Locked in the editor. "Duplicate" makes an editable copy |
| Library | materials.json in the data directory of Construct |
Your own materials, in every document. A library record with a built-in's id replaces that built-in |
| Scene | The materials: list of the .construct file |
The document's own copies |
A document is complete in itself. When an item in a document uses a built-in or a library material, the document gets a copy of the record. The file then opens the same on a computer that does not have the material.
A library edit does not change an open document. A scene copy remembers the library record that it came from. When that record changes, the document can take the new version with "Update", as one undo step.
A scene edit changes every item of the document that uses the definition. That is the purpose of a shared definition.
The default material
The "Default" in the material list is the default material of the whole application. On a first run it is dark gray: the sRGB color #222222, metalness 0.1 and roughness 0.6. The top of every scene uses it until you choose a material for the scene's root. To change the look of everything that has no material of its own, edit "Default": check "Edit built-in" and change it. The change applies at once.
| What | What it shows |
|---|---|
| An item that has no material of its own | The material of its nearest parent with one. At the top of the scene, the "Default" as it is now |
| A mesh or tet item that has no material of its own | Its type tone, so a mesh and a tet volume look different |
| An item with a library material | The document's copy of that material |
| The thumbnails and the previews | The "Default" as it is now |
An edit of "Default" changes no document. The items that use it show the edit at once, and the document does not ask to be saved.
The Default material is also the clay of the Clay viewport mode: in Clay, every item shows it. An edit of the Default changes Clay at once. See viewport modes.
Bindings and inheritance
- A new item has no binding.
- An item without a binding uses the binding of its nearest parent that has one. A parent's binding goes to its whole subtree.
- A child's binding never changes its parent.
- A child takes the whole binding of its parent: the definition and the values. To change one value for one child, give the child the material that it inherits: choose that material with the child's material button (see below). The child then holds a copy of the binding, values included.
- "No material" in the material list popup removes an item's binding, so the item inherits again.
A CSG operator is an item, and its operands are its children. An operator with a material renders it on its whole result. An operand with its own material keeps it, and the operator's blending decides the surface where the two meet.
The material row
When you open an item that has a material of its own, its box has a material row: the word "Material", the name of the material, and a sphere in that material with the item's values.
[ ] Material Rusty steel ā
Rust amount 0.40
Rust scale 20 mm
Steel color ā
- Click the sphere: opens the material list popup. Choose a different material, or click No material to remove the item's material.
- Double-click the sphere: opens the material editor on this material.
- The parameters of the material are rows under it, as the parameters of an SDF item are. Drag or type to change a value. Each change is one undo step; a drag is one step.
An item that has no material of its own has no material row. It uses the material of its nearest parent that has one, or the material of the scene. Its row in the tree has a small flat material button, directly left of the type:
> [icon] Ball [m] sphere
- The tooltip names the material that the item uses now and where it comes from: "Rusty steel from Tank", or "Default from the scene".
- Click the button: opens the material list popup. The material that you choose becomes the item's own material, in one undo step. The button then goes, and the item has a material row. If you choose the material that the item inherits, the item gets a copy of it, values included.
See Scene Tree Overlay.
Material list popup
Click a material to choose it. The popup closes. Click outside to cancel.
| Button | Action |
|---|---|
| No material | Removes the item's own material, so that the item takes the material of its parent again. The material row goes, and the material button comes back. It is disabled for an item that has no material of its own, and its tooltip then says where the material comes from |
| Edit | Closes the popup and opens the material editor on the material |
The list shows the document's materials first, then your library (most recently changed first), then the built-ins (by family, then by name). Each row shows a rendered sphere. Until the render is ready, the row shows a painted sphere in the material's colors. The list stays fast with any number of materials.
Material editor
Open it with the material editor button on the toolbar, or double-click the sphere on a material row. The editor is a window of its own. It keeps its size and its place on the screen.
Layout
- A wide window: the material list on the left, no wider than its rows, and the preview and the record editor on the right. The record editor scrolls up and down only: the window does not become narrower than the editor.
- A tall window: the preview and the record editor on top, the list below.
The preview renders on a worker thread with the path tracer, so it shows the material as it is: its patterns, gradients and bump, and glass, skin and flakes.
A change applies at once. There is nothing to save. A change goes into the material a moment after your last key or drag. A material of the open document changes in the document; another changes in the library. Undo takes a change back.
The record editor
The editor edits the record's text, so the comments and the key order of the record stay as you wrote them. It has four sections:
| Section | What you edit |
|---|---|
| Header | The name, the family and the summary |
| Parameters | The knobs of the material: their names, types, defaults and ranges. Add parameter adds one; the trash button removes one |
| Patterns | One row per pattern: its field (the definition picker, with the field records), its space, its scale and offset, and the field's own parameters. Add pattern adds one |
| Channels | The OpenPBR inputs, grouped by layer: base, specular, transmission, subsurface, fuzz, coat, thin film, emission, geometry, and each extension, such as flake. A layer that the material does not use is folded; click its name to open it |
Each channel row has its kind (Default, Value, Parameter, Pattern, Gradient,
Expression or Bump) and the editor of that kind. A kind that the channel
cannot take is not offered: a color has Gradient and no Pattern, a normal has
only Bump. A kind that needs a parameter or a pattern that the record lacks is
disabled. A remap bound, a scale, an offset and a bump's strength take a
number or an =expression. Colors and gradient stops take alpha in the color
picker.
Operations
The operations are icon buttons, in one row. Hold the pointer over a button to see its name.
| Button | Action |
|---|---|
| New material | Create a material that starts as a copy of the default material |
| Duplicate | Make a copy of the material that you can edit, and open it (for built-ins too) |
| Delete | Remove a material of your own |
Make an editable copy
The editor of a built-in material is locked. To start from one, make a copy:
- Double-click the sphere on an item's material row. The editor opens on that material.
- Click Duplicate. The copy goes into the library at once, as one step that undo reverses.
- The editor now edits the copy. A change applies at once.
To build a material step by step, with a pattern, a gradient, a remap and a parameter, see Make a procedural material.
CSG material blending
Operators blend the materials of their operands.
| Property | Values | Description |
|---|---|---|
materialMode |
BaseWins, OperandWins, Blend | Which material wins where the operands meet |
blendSharpness |
0.0 - 1.0 | The sharpness of the transition (0 smooth, 1 hard) |
- BaseWins (0): the first operand's material.
- OperandWins (1): the second operand's material.
- Blend (2): the materials blend by the distance to each operand.
File format
A .construct file holds the scene's material records in materials:, each
as its own text with its comments, and each item's binding in material:.
values holds only the values that differ from the definition's defaults. A
value can be an expression, with the = prefix.
construct:
name: "Tank"
material: {use: concrete} # the root's binding; absent: the Default
materials: # the scene's records
# Steel that rusts with one knob.
- id: rusty-steel
from: {library: rusty-steel, fingerprint: 3f9c1a7d}
name: Rusty steel
family: material/metals
# ⦠the rest of the record ā¦
instances:
tank:
type: box
material: {use: rusty-steel, values: {rust_amount: 0.7}}
hatch:
type: cylinder
parent: tank # no material: the tank's
valve:
type: sphere
parent: tank
material: {use: rusty-steel, values: {rust_amount: 0.1}}
An older file with an item map of albedo, metallic and roughness, or a
materials: map, loads with a warning, and its items use the root's
material.
Persistence
- Built-in materials: in the application.
- Library materials:
materials.jsonin the data directory of Construct. - Scene materials: in the
.constructfile.
Components
| Component | Location | Purpose |
|---|---|---|
MaterialDefinition |
construct/model/ |
A definition record: its text, its parameters, patterns and channels |
MaterialBinding |
construct/model/ |
The definition and the values that an item uses |
MaterialLibrary |
construct/model/ |
The built-ins and the library records |
MaterialListModel |
construct/model/ |
The list of the editor and the popup, over any number of records |
MaterialModule |
construct/shader/ |
The GPU code and data of the materials that a scene uses |
MaterialSampler |
construct/shader/ |
The same code on the CPU, for construct.material.sample |
MaterialEditorWindow |
construct/ui/ |
The material editor, a tool window |
MaterialRecordEditor |
construct/ui/ |
The editor's four sections |
MaterialPreviewView |
construct/ui/ |
The editor's live preview, rendered on a worker thread |
MaterialPreviewWidget |
construct/ui/ |
The sphere of a material row |
MaterialListPopup |
construct/ui/ |
The popup of a material row |
Test coverage
testMaterialDefinitionRecord: the record, its channels and its patterns.testMaterialInheritance: bindings and inheritance.testMaterialModule,testTracerMaterials: the materials on the GPU and on the CPU.testMaterialEditor: the editor, its sections and its list.testOverlaySelection: the material row.testSDFParser: the file format.