Skip to content

<InstancedMeshes>

The component <InstancedMeshes> takes existing THREE.Mesh instances and creates a THREE.InstancedMesh per THREE.Mesh. This is especially useful if you want to instantiate a lot of meshes that have been loaded with hooks like useGltf.

It takes the same arguments as <InstancedMesh>.

<script lang="ts">
import { Canvas } from '@threlte/core'
import Scene from './Scene.svelte'
</script>
<div>
<Canvas>
<Scene />
</Canvas>
</div>
<style>
div {
height: 100%;
}
</style>
<script lang="ts">
import type { Snippet } from 'svelte'
import { T, type Props } from '@threlte/core'
import { type Group, MathUtils } from 'three'
interface GroupProps extends Props<Group> {
children?: Snippet
}
let { children, ...rest }: GroupProps = $props()
</script>
<T.Group {...rest}>
<!-- Correct rotation -->
<T.Group rotation.x={MathUtils.DEG2RAD * 90}>
{@render children?.()}
</T.Group>
</T.Group>
<script lang="ts">
import { T } from '@threlte/core'
import { InstancedMeshes, OrbitControls, useGltf } from '@threlte/extras'
import { DoubleSide, Mesh } from 'three'
import { DEG2RAD } from 'three/src/math/MathUtils.js'
import Flower from './Flower.svelte'
const gltf = useGltf<{
nodes: {
Blossom: Mesh
Stem: Mesh
}
materials: {}
}>('/models/Flower.glb')
// make an array of random x-z coordinates in the range of -20 to 20 with 200 elements
const items = Array.from({ length: 1000 }, () => ({
x: Math.random() * 5 - 2.5,
z: Math.random() * 5 - 2.5,
scale: Math.random() * 0.5 + 0.5,
rotation: {
x: Math.random() * 8,
y: Math.random() * 360,
z: Math.random() * 8
}
}))
</script>
{#if $gltf}
<InstancedMeshes
castShadow
meshes={$gltf.nodes}
>
{#snippet children({ components: { Blossom, Stem } })}
{#each items as item}
<Flower
position.x={item.x}
position.z={item.z}
scale={item.scale}
rotation.y={(item.rotation.y * Math.PI) / 180}
rotation.x={(item.rotation.x * Math.PI) / 180}
rotation.z={(item.rotation.z * Math.PI) / 180}
>
<Blossom />
<Stem />
</Flower>
{/each}
{/snippet}
</InstancedMeshes>
{/if}
<T.DirectionalLight
position.y={10}
position.z={5}
castShadow
shadow.camera.left={-2.5}
shadow.camera.right={2.5}
shadow.camera.top={2.5}
shadow.camera.bottom={-2.5}
shadow.mapSize.width={1024}
shadow.mapSize.height={1024}
/>
<T.Mesh
receiveShadow
rotation.x={-90 * DEG2RAD}
>
<T.PlaneGeometry args={[5, 5]} />
<T.MeshStandardMaterial
color="#288278"
side={DoubleSide}
/>
</T.Mesh>
<T.AmbientLight intensity={0.1} />
<T.PerspectiveCamera
position={[3, 0.5, 3]}
makeDefault
fov={20}
>
<OrbitControls
autoRotate
enableZoom={false}
enableDamping
autoRotateSpeed={0.1}
enablePan={false}
/>
</T.PerspectiveCamera>

Load a gltf file with the useGltf hook and pass the result to the <InstancedMeshes> component. The slot prop components can be used to instantiate a mesh multiple times.

<script lang="ts">
import { useGltf, InstancedMeshes } from '@threlte/extras'
// Let's say the file contains a mesh named "Cube".
// The hook `useGltf` will automatically provide a map with
// all nodes of the gltf file at the key `nodes`. When
// passing that map to the `<InstancedMeshes>` component, it will
// automatically filter out all nodes that are not
// `THREE.Mesh` instances.
const gltf = useGltf('path/to/file.gltf')
</script>
{#if $gltf}
<!--
You can use object destructuring
to access the component <Cube>
-->
<InstancedMeshes meshes={$gltf.nodes}>
{#snippet children({ components: { Cube } })}
<Cube position.y={2} position.x={-1}>
{/snippet}
</InstancedMeshes>
{/if}

When using <InstancedMeshes> with a large gltf file, be aware that <InstancedMeshes> will create a new <InstancedMesh> for each <Mesh> in the gltf file. This can lead to a lot of <InstancedMesh> components, which can have a negative impact on performance. You might want to filter out the meshes you want to instantiate beforehand.

If you don’t want to use the useGltf hook, you can also pass an array of THREE.Mesh instances to the <InstancedMeshes> component.

<script lang="ts">
import { InstancedMeshes } from '@threlte/extras'
import { Mesh, BoxGeometry, MeshStandardMaterial } from 'three'
const meshes = [
new Mesh(new BoxGeometry(), new MeshStandardMaterial()), // MeshA
new Mesh(new SphereGeometry(), new MeshStandardMaterial()), // MeshB
new Mesh(new PlaneGeometry(), new MeshStandardMaterial()) // MeshC
]
</script>
<!--
You can use array destructuring
to access the components <MeshA>,
<MeshB> and <MeshC>
-->
<InstancedMeshes meshes={meshes}>
{#snippet children({ components: [MeshA, MeshB, MeshC] })}
<MeshA position.y={2} position.x={-1}>
<MeshB position.y={-2}>
<MeshC position.y={0} position.x={1}>
{/snippet}
</InstancedMeshes>

<InstancedMeshes> extends < T . InstancedMesh > and supports all its props, snippets, bindings and events.

Props

name
type
required
default
description

meshes
THREE.Mesh[] | Record<string, THREE.Mesh>
yes

limit
number
no
1000
Limits the amount of possible <Instance> components.

range
number
no
1000
Limits the amount of drawn <Instance> components.

update
boolean
no
true
Whether the THREE.InstancedMesh should be updated.