Skip to content

Overview

InstancedSpriteMesh was created to enabled high performant instancing of animated sprites in threejs. Current solutions do not fare well with very high instance counts. This package aims to resolve that, boasting the capability to render tens of thousands individually animated sprites even on low/medium power devices.

Example Scene: Live Code

Bunny-mark: Live Code

Threlte component: InstancedSprite docs

Installation

Package is published as @threejs-kit/instanced-sprite-mesh and you can add it to your project by installing it as such:

npm i @threejs-kit/instanced-sprite-mesh

Getting started

At it’s core InstancedSpriteMesh is built on top of, and extends InstancedUniformsMesh so any of their documentation might be helpful to you - it’s recommended to get familiar with it as well.

Basic example

InstancedSpriteMesh needs spritesheet texture and spritesheet metadata provided to it (imported from Aseprite, others or generated on the fly)

  • load texture
  • create a base material
  • make instanced sprite mesh
  • add spritesheet to mesh
const texture = new THREE.TextureLoader().load('/spritesheet.png');
texture.minFilter = THREE.NearestFilter;
texture.magFilter = THREE.NearestFilter;

const baseMaterial = new THREE.MeshBasicMaterial({
  transparent: true,
  alphaTest: 0.01,
  side: THREE.DoubleSide,
  map: texture
});

const mesh = new InstancedSpriteMesh(baseMaterial, INSTANCE_COUNT);

mesh.fps = 15

const spritesheet = parseAseprite(JSON.parse(rawSpritesheet));
mesh.spritesheet = spritesheet;

Quick api preview

  // set global FPS for updating
  mesh.fps = 15

  // play animation on instance id 0 - loops by defualt
  mesh.play('IdleBackward').at(0)
  // play animation without looping
  mesh.play('RunLeft', false).at(1);
  // play animation backwards with looping
  mesh.play('RunLeft', true, 'REVERSE').at(2);


  // mesh.play is a utility that combines the use of these functions:

  // animation by name
  mesh.animation.setAt(0, 'RunBackward');
  // looping y/n
  mesh.loop.setAt(0, false);
  // animation direction - FORWARD (default) / REVERSE / PAUSE
  mesh.playmode.setAt(0, 'REVERSE')

  // billboarding
  mesh.billboarding.setAll(true);
  mesh.billboarding.setAt(0, true);

Updating sprite animations

Currently the sprites are only animated based on provided FPS and a timer. mesh.update(); has to be called to update the animations.

Support for animations independent on time and fps will be coming soon

Typescript support

Yes, wip.

type SpriteAnimations =
		| 'RunRight'
		| 'RunLeft'
		| 'RunForward'
		| 'IdleRight'
		| 'IdleLeft'
		| 'IdleForward'
		| 'RunBackward'
		| 'IdleBackward';

const mesh: InstancedSpriteMesh<MeshBasicMaterial, SpriteAnimations> = new InstancedSpriteMesh(
  baseMaterial,
  count,
  renderer,
  {
    triGeometry: true,
    spritesheet
  }
);

for example, the above will allow for autocompletion of animation names

shows how glint material looks like