Skip to main content

Material graphs

The standard material types cover most of what a project needs. When they do not, you can build a material as a graph instead: connect nodes, and the editor compiles them into a real shader.

Reach for one when you want something a fixed material cannot express — a scrolling texture, a dissolve, a hologram, water, a colour that changes with viewing angle, a flag that ripples.

Every node with its ports: shader node reference — 95 nodes.

Every material is already a graph

The built-in types are not a separate system with a graph bolted on — standard, physical, toon and the rest are themselves points inside this same space. So a graph material is not a second-class citizen: it goes through the same path, gets the same lighting, and works on mobile.

How a graph is shaped

A graph runs from inputs, through maths, into outputs.

CategoryWhat lives there
inputUVs, the surface normal, time, position, textures, which instance is drawing
constfixed numbers and colours you type in
matharithmetic and curves on single numbers
vectorbuilding, splitting, mixing and transforming vectors and colours
lightlighting terms you shape yourself
postnodes that sample the rendered frame — see screen effects
outputwhat the surface actually looks like

The surface outputs

The output node is where your graph ends, and its inputs are the physical description of the surface:

OutputMeans
baseColorthe colour of the surface
metallic0 for a dielectric, 1 for bare metal — rarely anything between
roughness0 mirror-smooth, 1 completely matte
normalfeed your own normal to add surface detail
emissivelight the surface gives off by itself
alphatransparency
clearcoat · clearcoatRoughnessa lacquer layer over the top
ior · transmission · thicknessrefraction, for glass and liquids

Anything you leave unconnected keeps its default, and the compiler folds it away — an output you do not use costs nothing.

Working with instances

Two input nodes exist specifically for instanced objects: instanceId gives you which copy is being drawn, and instanceColor gives you that copy's tint.

This is what makes a thousand objects stop looking like one object

Feed instanceId into a hash and every copy gets its own tint, size or animation phase — from a single draw call. A field of grass where every blade sways slightly differently costs the same as a field where they all sway together.

Both read sensible defaults on an ordinary mesh, so a graph using them never breaks by being used somewhere uninstanced.

Screen effects

A graph that samples the rendered frame is not a surface material at all — it is a full-screen effect applied over the whole scene. Colour grading, vignettes, blurs, scanlines.

The engine notices this by itself: use a node that reads the frame and the graph becomes an effect rather than something you put on an object. Several effects on a scene run in the order you give them.

Textures and colour space

A texture node samples an image resource. Colour images are decoded for you so the maths works on real colour values.

Mark data textures as data

A texture that carries numbers rather than colour — a roughness map, a mask, a height map — must be marked as such, or it will be colour-corrected and your values will be subtly wrong. This is the single most common cause of "my roughness map looks nothing like it should".

A script cannot reach into a graph

Scripts have no access to the graph component, so you cannot set a graph parameter from code.

That is less limiting than it sounds, because the two things people want are both covered:

You wantDo it
Something that animates by itselfuse the time input inside the graph — pulsing, scrolling, shimmering all belong there
Something driven by game statedrive an ordinary material slot instead: a script can write emissiveIntensity, color, opacity, roughness

So a beacon that pulses forever is a graph reading time; a beacon that brightens when the player scores is a script writing emissiveIntensity on a standard material.

Practical advice

Start from a preset. Duplicating a standard material as a graph gives you a correct, complete starting point. Building from an empty canvas means re-deriving lighting you did not need to.

Watch what you add. A graph runs for every pixel, every frame. A texture lookup is cheap; a loop is not. If the frame rate drops after an edit, the last node you added is the suspect.

Save it as a resource and every object using it updates at once — which also means one place to fix when the look is wrong.


Next: Particles — fire, smoke, sparks and dust.