Skip to content

InstancedModel

InstancedModel draws a registered model once for each placement in a list, in one draw call for each mesh in the model. Use it for a forest, a field of coins or a scree of rocks: things that stand many times and do nothing on their own. It spawns no entity, so a copy has no behaviours, no collider and no transform a system moves. A thing that moves, collides or is picked up is an <Entity model>.

A placement is a plain transform, so any code can produce the list:

  • position: the point the model’s lowest point stands on. The model is seated on its own bounds, as the scatter kit is, so a model centred on its origin still stands on the ground.
  • turn: radians about y. It defaults to 0.
  • scale: a multiple of the model’s own size, one number for every axis or one for each. It defaults to 1.
  • tint: a colour the copy is multiplied by. Copies without one keep the model’s own colours.

Its props are in InstancedModelProps and a placement’s fields in InstancePlacement.

Unity’s Graphics.RenderMeshInstanced, Unreal’s Instanced Static Mesh and Godot’s MultiMeshInstance3D take the same input: one mesh and a list of transforms.

The copies are never culled one by one and have no level of detail: the whole batch draws whenever any of it is in view. A headless scene draws nothing and loads no model.

Client. The copies only change how the world looks.

import { InstancedModel, registerModel } from "@daniel-zarinski/engine";
import fir from "./fir.glb?url";
registerModel("fir", fir);
const firs = Array.from({ length: 50 }, (_, index) => ({
position: [index * 3, 0, -10] as [number, number, number],
turn: index,
scale: 1 + (index % 3) * 0.2,
}));
export function Treeline() {
return <InstancedModel model="fir" placements={firs} />;
}