@threlte/extras
<InstancedMesh>
The component <InstancedMesh>
is wrapping the Three.js object InstancedMesh and provides instanced rendering support. Use <InstancedMesh>
if you have to render a large number of objects with the same geometry and material but with different world transformations and colors. The usage of <InstancedMesh>
will help you to reduce the number of draw calls and thus improve the overall rendering performance in your application.
<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 { T, useTask } from '@threlte/core'
import { Instance, InstancedMesh } from '@threlte/extras'
let dn = Date.now()
useTask(() => (dn = Date.now()))
</script>
<InstancedMesh>
<T.SphereGeometry args={[0.5]} />
<T.MeshStandardMaterial color="white" />
<Instance
position.x={-2}
position.y={Math.sin(dn / 1000 + 40)}
/>
<Instance
position.x={-1}
position.y={Math.sin(dn / 1000 + 10)}
/>
<Instance
position.x={0}
position.y={Math.sin(dn / 1000 + 5)}
/>
<Instance
position.x={1}
position.y={Math.sin(dn / 1000 + 200)}
/>
<Instance
position.x={2}
position.y={Math.sin(dn / 1000 + 550)}
/>
</InstancedMesh>
<T.DirectionalLight
position.y={10}
position.z={5}
/>
<T.AmbientLight intensity={0.1} />
Usage
An <InstancedMesh>
is used in conjunction with the <Instance>
component:
<InstancedMesh>
<T.BoxGeometry />
<T.MeshStandardMaterial />
<Instance />
<Instance />
</InstancedMesh>
It’s also possible to nest other objects in an <InstancedMesh>
component:
<InstancedMesh>
<T.BoxGeometry />
<T.MeshStandardMaterial />
<Instance />
<Instance />
<GLTF />
</InstancedMesh>
Provide an id
to use multiple <InstancedMesh>
components:
<InstancedMesh id="tree">
<T is={treeGeometry} />
<T.MeshStandardMaterial map={treeTexture} />
<InstancedMesh id="leaf">
<T is={leafGeometry} />
<T.MeshStandardMaterial map={leafTexture} />
<T.Group position.x={1}>
<Instance id="tree" /> // Instance of InstancedMesh with id="tree"
<Instance id="leaf" /> // Instance of InstancedMesh with id="leaf"
</T.Group>
<T.Group position.x={-2}>
<Instance id="tree" />
<Instance id="leaf" />
</T.Group>
</InstancedMesh>
</InstancedMesh>
Instance count
Use the property limit
to set the maximum amount of <Instance>
components (defaults to 1000). The property limit
will be used to initialize the internally used Float32Array. Use the property range
to optionally limit the amount of drawn instances.
<InstancedMesh
limit={10000}
range={100}
>
<T.BoxGeometry />
<T.MeshStandardMaterial />
<Instance />
<Instance />
</InstancedMesh>
Events
<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 { T, useThrelte } from '@threlte/core'
import { InstancedMesh, interactivity } from '@threlte/extras'
import Sphere from './Sphere.svelte'
const count = 20
const gap = 1.5
const offset = (count * gap) / 2
const positions: [number, number][] = []
const colors: [number, number, number][] = []
for (let i = 0; i < count; i++) {
for (let j = 0; j < count; j++) {
positions.push([i * gap - offset, j * gap - offset])
colors.push([Math.random(), Math.random(), Math.random()])
}
}
const { size } = useThrelte()
let zoom = $size.width / 50
$: zoom = $size.width / 50
interactivity()
</script>
<T.OrthographicCamera
position={[50, 50, 50]}
{zoom}
makeDefault
on:create={({ ref }) => {
ref.lookAt(0, 0, 0)
}}
/>
<InstancedMesh>
<T.SphereGeometry args={[0.5]} />
<T.MeshStandardMaterial color="white" />
{#each positions as position}
<Sphere {position} />
{/each}
</InstancedMesh>
<T.DirectionalLight
position.y={10}
position.z={5}
/>
<T.AmbientLight />
<script lang="ts">
import { cubicIn, cubicOut } from 'svelte/easing'
import { tweened } from 'svelte/motion'
import { derived } from 'svelte/store'
import { Instance } from '@threlte/extras'
export let position: [x: number, z: number]
let hovering = false
const scale = tweened(1)
const r = tweened(255)
const g = tweened(255)
const b = tweened(255)
$: if (hovering) {
scale.set(2, {
duration: 0,
easing: cubicIn
})
r.set(254, { duration: 0 })
g.set(61, { duration: 0 })
b.set(0, { duration: 0 })
} else {
scale.set(1, {
duration: 5e3,
easing: cubicOut
})
r.set(255, { duration: 5e3 })
g.set(255, { duration: 5e3 })
b.set(255, { duration: 5e3 })
}
const color = derived([r, g, b], ([r, g, b]) => {
return `rgb(${Math.floor(r)},${Math.floor(g)},${Math.floor(b)})`
})
</script>
<Instance
position.x={position[0]}
position.z={position[1]}
position.y={$scale * 4}
scale={$scale}
color={$color}
on:pointerenter={() => (hovering = true)}
on:pointerleave={() => (hovering = false)}
/>
Instances also support interactivity events.
<InstancedMesh>
<T.BoxGeometry />
<T.MeshStandardMaterial />
<Instance on:click={onClick} />
</InstancedMesh>
Nesting
Instances can be nested in other objects and all parent transformations apply as usual:
<InstancedMesh>
<T.BoxGeometry />
<T.MeshStandardMaterial />
<T.Group rotation.z={DEG2RAD * 180}>
<Instance />
<T.Group position.y={2}>
<Instance />
</T.Group>
</T.Group>
</InstancedMesh>
Component Signature
<InstancedMesh>
extends
<T.InstancedMesh>
and supports all its props, slot props, bindings and events.