Skip to content

Model materials ​

A model you import (a GLB or glTF file) brings its own materials. Each part of the model is drawn with one of them, the way the file was made: a knight might have one material for armour, one for skin and one for the tabard. The object's Mesh Renderer decides what happens to those materials.

Use Model Texture ​

The checkbox under Geometry, shown for a model.

  • On (the default): the model keeps its own materials.
  • Off: the Mesh Renderer's own Color, Texture or Material replaces all of them at once.

Material slots ​

Each material in the model file is a slot, numbered in the order the file lists them. The Mesh Renderer lists them under Materials: Element 0, Element 1, … with each material's name from the file.

For each slot you can pick:

  • a Material asset: that part of the model shows the material's look instead of its own;
  • a colour: it replaces the slot's own colour and keeps everything else about it, including its texture, its shine, and the colours painted on the model's vertices, which the colour multiplies. A part painted in light and dark greys, recoloured blue, comes out in light and dark blues.

✕ removes the override, and the slot shows the model's own material again. Only the parts drawn with that material change.

This is how one model can serve several teams. Give the model a material for its team-coloured parts, painted in neutral greys, and recolour that slot on each object: one model file instead of one per team, and less for every player to download.

Every change is one undo step, and dragging the colour picker is one step too.

From a script ​

js
// Colour material 1 of this model, and leave its other materials as they are.
this.entity.setComponent('meshRenderer', { materialSlots: { 1: { color: '#3b82f6' } } })
  • A key is the material's number, the Element number in the Inspector.

  • Without a Material asset, a slot can set color, emissive, emissiveIntensity, metalness, roughness, opacity, transparent and customTextureAssetId. Anything it does not set stays the model's own.

  • To give a slot a Material asset, pass its id. Look it up by name:

    js
    const gold = this.game.getAssetId('Gold', 'material')
    this.entity.setComponent('meshRenderer', { materialSlots: { 2: { materialAssetId: gold } } })

    Fields written next to it apply on top: { materialAssetId: gold, color: '#ff0000' } is that material in red. An id that is not a material in the project throws.

  • Writes merge slot by slot. Writing slot 1 leaves the override on slot 0 alone, and the slot you write replaces what that slot had. null for one slot removes its override; materialSlots: null removes them all.

  • Changing a colour every frame is cheap: the same material is updated in place.

  • A client script can do this too. As with any client script write, the change shows on that player's screen only.

From the editor's Terminal or the CLI, inspect Troop lists the model's materials by number, and set Troop.meshRenderer.materialSlots.1.color = "#3b82f6" recolours one of them.

Worth knowing ​

  • While a model that keeps its own materials has slot overrides, the Mesh Renderer's own Color no longer tints it, and neither does entity.color. Recolour it through its slots.
  • With Use Model Texture off, the Mesh Renderer's material is where every slot starts, and a slot's override changes it from there.
  • Switching the object to another model keeps its overrides. A slot the new model does not have is ignored; the Inspector lists it as "not in this model" so you can remove it.
  • A Material asset used by a slot is shared like any other: editing the material updates every slot and object in the map that uses it.
  • A texture on a slot is laid out by the model's own UVs, as the model's own texture was, and the slot keeps the model's transparency unless the new image has transparent pixels of its own.

Opacity 0 is not drawn ​

A material at opacity 0 is skipped: it costs no draw call and casts no shadow, and it is drawn again as soon as its opacity rises above 0. This holds for a slot, for the whole object's Mesh Renderer, for a material the model file itself leaves at alpha 0, and for a fade from a script or an animation clip.

So hiding parts of a model through its slots is free. A figure with armour pieces it is not wearing, a saddle not on, a coat taken off: write { opacity: 0 } on those slots and they cost nothing until they are shown.

js
// Take the helmet (material 1) off, and put it back on later.
this.entity.setComponent('meshRenderer', { materialSlots: { 1: { opacity: 0 } } })
this.entity.setComponent('meshRenderer', { materialSlots: { 1: { opacity: 1 } } })

The object itself is still there: raycasts hit it, its collider is unchanged, and it can still be selected in the editor. A custom shader decides its own transparency, so it is drawn at any opacity.