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

  1. A new item has no binding.
  2. An item without a binding uses the binding of its nearest parent that has one. A parent's binding goes to its whole subtree.
  3. A child's binding never changes its parent.
  4. 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.
  5. "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:

  1. Double-click the sphere on an item's material row. The editor opens on that material.
  2. Click Duplicate. The copy goes into the library at once, as one step that undo reverses.
  3. 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.json in the data directory of Construct.
  • Scene materials: in the .construct file.

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.
Topics
reference construct materials pbr