/three-avatar

Avatar system for three.js

Primary LanguageTypeScriptMIT LicenseMIT

three-avatar · GitHub license npm version PRs Welcome

Avatar system for three.js.

Features

  • Loads VRM/VRoid, Ready Player Me
  • Play mixamo animation
  • Head sync for VR
  • Replaceable collision detection
  • Replaceable lip sync
  • Replaceable IK (Inverse Kinematics)
  • Show hand mirror

preview

Example

npm run example

Installation

npm

npm install @verseengine/three-move-controller @verseengine/three-touch-controller @verseengine/three-xr-controller @verseengine/three-avatar

CDN (ES Mobules)

<script
      async
      src="https://cdn.jsdelivr.net/npm/es-module-shims@1.6.2/dist/es-module-shims.min.js"
    ></script>
<script type="importmap">
  {
    "imports": {
      "three": "https://cdn.jsdelivr.net/npm/three@0.153.0/build/three.module.js",
      "three-avatar": "https://cdn.jsdelivr.net/npm/@verseengine/three-avatar/dist/esm/index.js",
      "@pixiv/three-vrm": "https://cdn.jsdelivr.net/npm/@pixiv/three-vrm@2/lib/three-vrm.module.min.js",
      "@verseengine/three-touch-controller": "https://cdn.jsdelivr.net/npm/@verseengine/three-touch-controller/dist/esm/index.js",
      "@verseengine/three-move-controller": "https://cdn.jsdelivr.net/npm/@verseengine/three-move-controller/dist/esm/index.js",
      "@verseengine/three-xr-controller": "https://cdn.jsdelivr.net/npm/@verseengine/three-xr-controller/dist/esm/index.js"
    }
  }
</script>

Usage

import * as THREE from "three";
import * as THREE_VRM from "@pixiv/three-vrm";
import {
  createAvatarIK,
  isAnimationDataLoaded,
  preLoadAnimationData,
  createAvatar,
  Lipsync,
} from "three-avatar";

// Animation fbx files downloaded from mixamo.com
const ANIMATION_MAP = {
  idle: "path/to/idle.fbx",
  walk: "path/to/walk.fbx",
  dance: "path/to/dance.fbx",
};

async function loadAvatar(avatarURL) {
  ...
  if (!isAnimationDataLoaded()) {
    await preLoadAnimationData(ANIMATION_MAP);
  }

  const collisionObjects:THREE.Object3D[] = [wall0, wall1, ...];
  const teleportTargetObjects:THREE.Object3D[] = [ground0, ...];
  const collisionBoxes = [];
  [...collisionObjects, ...teleportTargetObjects].map((el) => {
    el.traverse((c) => {
      if (!c.isMesh) {
        return;
      }
      collisionBoxes.push(new THREE.Box3().setFromObject(c));
    });
  });

  let resp = await fetch(avatarURL);
  const avatarData = new Uint8Array(await resp.arrayBuffer());
  const avatar = await createAvatar(
    avatarData,
    renderer,
    false,
    avatarContainer,
    {
      getCollisionBoxes: () => collisionBoxes,
      isInvisibleFirstPerson: true,
    }
  );
  avatarContainer.add(avatar.object3D);

  const touchController = new TouchController(avatarContainer);
}

const clock = new THREE.Clock();
function animate() {
  _avatar?.tick(clock.getDelta());
  renderer.render(scene, camera);
}
renderer.setAnimationLoop(animate);

Reference

API Reference

Link