Builtin Library
README.md
materialGraph
Compiles a material node graph into the engine's WGSL surface DSL.
local materialGraph = require("@builtin::systems.materialGraph.materialGraph")
| Call | What it does |
|---|---|
compile(graph, name?) | Pure. Returns { name, wgsl, properties, nodes, unused } — the two files a .shader asset holds, the nodes emitted, and the nodes the terminal could not reach. |
check(graph) | compile with the error handed back: (true, result) or (false, message). |
install(graph, opts?) | Writes the compiled graph out as a real .shader asset. opts.name names it; opts.into places it as it is created, and installing again writes wherever the asset already is. |
material(graph, opts?) | Installs, then makes a material wearing the shader. opts.values sets the material's own property values — on the first call and on every later one, so calling it again is how a graph is iterated on. |
nodeTypes() | Every operation, with the inputs a node of it is written with, which of those it cannot be written without, its result type and a line of prose. |
surfaceChannels() | Every channel of the terminal, and the shading-model field it drives. |
Inputs
A port takes any of:
| Written as | Means |
|---|---|
0.5 | A float constant. |
{ 1, 0.5, 0.25 } | A vector constant, 2 to 4 components. |
"other" | The output of the node named other. |
{ node = "other", swizzle = "rgb" } | Part of that node's output. |
{ op = "fresnel", power = 3 } | A node written where it is used. |
swizzle reads part of whatever the table it is written in resolves to — a node
reference, an inline node, or a constant vector. A table carrying both an op
and a node is refused: a port says where its value comes from once.
Types
float, vec2, vec3, vec4. A node's type is worked out from its inputs. In
an arithmetic node the widest input decides the result and a
float input is broadened to it; two inputs of different vector widths are
refused, naming the node. At the terminal a float broadens into a colour
channel, and a wider value is refused with a note to swizzle it.
Every number a graph carries is written into the shader as an f32, so one past
what an f32 holds is refused where it is written.
Operations
| Group | Ops |
|---|---|
| Sources | uv lightmapUv affineUv worldPosition worldNormal worldTangent viewDirection viewPosition vertexColor time |
| Values | constant property |
| Textures | sampleTexture normalMap |
| Arithmetic | add subtract multiply divide min max pow step mix clamp smoothstep |
| Per-component | abs floor ceil fract sign sin cos sqrt exp log saturate oneMinus negate normalize |
| Vector | length distance dot cross combine |
| Shading | fresnel |
Properties
graph.properties holds the same declarations a hand-written properties.yaml
carries: float, range (with min / max), float2, float3, float4,
color, int, bool and texture. A property node reads one, and
sampleTexture / normalMap sample a texture one through the texture and
sampler pair the engine generates for it. int and bool are converted where
they are read, so they compose with everything else.
A texture declaration becomes a global of its own name in the interface the
engine generates, so s, input and material — the names the generated body
already stands on — and anything starting with mg_ are refused as texture
names.
The terminal
graph.surface names channels of the shading model:
albedo normal metallic roughness emissive occlusion alpha
alphaCutoff ior reflectance clearcoat clearcoatRoughness anisotropy
transmission thickness attenuationColor attenuationDistance sheenColor
sheenRoughness iridescence iridescenceThickness iridescenceIor
subsurfaceColor subsurfaceRadius fibreColor fibreSpecular fibreShift
fibreRoughness
A channel left unset keeps the engine's own neutral default, so a graph names only the channels it has something to say about.