Skip to main content

ThreeJS Blendshapes

There is 52 blendshapes scores representing the facial expressions of the detected face. This example shows how you can control a avatar head with the detected blendshapes.

Try it out

Live Demo

img

Credit: the racoon avatar 3D model used in this example comes from mediapipe


<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script type="importmap">
{
"imports": {
"three": "https://unpkg.com/three@0.160.0/build/three.module.js",
"three/addons/": "https://unpkg.com/three@0.160.0/examples/jsm/",
"mindar-face-three":"https://cdn.jsdelivr.net/npm/mind-ar@1.2.5/dist/mindar-face-three.prod.js"
}
}
</script>
<script type="module">
import * as THREE from 'three';
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
import { MindARThree } from 'mindar-face-three';
class Avatar {
constructor() {
this.gltf = null;
this.morphTargetMeshes = [];
}
async init() {
const url = "https://assets.codepen.io/9177687/raccoon_head.glb";
const gltf = await new Promise((resolve) => {
const loader = new GLTFLoader();
loader.load(url, (gltf) => {
resolve(gltf);
});
});
gltf.scene.traverse((object) => {
if ((object).isBone && !this.root) {
this.root = object; // as THREE.Bone;
}
if (!(object).isMesh) return
const mesh = object;
if (!mesh.morphTargetDictionary || !mesh.morphTargetInfluences) return
this.morphTargetMeshes.push(mesh);
});
this.gltf = gltf;
}
updateBlendshapes(blendshapes) {
const categories = blendshapes.categories;
let coefsMap = new Map();
for (let i = 0; i < categories.length; ++i) {
coefsMap.set(categories[i].categoryName, categories[i].score);
}
for (const mesh of this.morphTargetMeshes) {
if (!mesh.morphTargetDictionary || !mesh.morphTargetInfluences) {
continue;
}
for (const [name, value] of coefsMap) {
if (!Object.keys(mesh.morphTargetDictionary).includes(name)) {
continue;
}
const idx = mesh.morphTargetDictionary[name];
mesh.morphTargetInfluences[idx] = value;
}
}
}
}
let mindarThree = null;
let avatar = null;
const setup = async () => {
mindarThree = new MindARThree({
container: document.querySelector("#container"),
});
const { renderer, scene, camera } = mindarThree;
const light = new THREE.HemisphereLight(0xffffff, 0xbbbbff, 1);
scene.add(light);
const anchor = mindarThree.addAnchor(1);
await avatar.init();
avatar.gltf.scene.scale.set(2, 2, 2);
anchor.group.add(avatar.gltf.scene);
}
const start = async () => {
if (!mindarThree) {
await setup();
}
await mindarThree.start();
const { renderer, scene, camera } = mindarThree;
const feedVideo = document.querySelector("#video-feed");
feedVideo.srcObject = mindarThree.video.srcObject.clone();
feedVideo.play();
renderer.setAnimationLoop(() => {
const estimate = mindarThree.getLatestEstimate();
if (estimate && estimate.blendshapes) {
avatar.updateBlendshapes(estimate.blendshapes);
}
renderer.render(scene, camera);
});
}
start();
</script>
<style>
body {
margin: 0;
}
#container {
width: 100vw;
height: 100vh;
position: relative;
overflow: hidden;
}
#video-feed {
position: fixed;
bottom: 0;
left: 0;
width: 50vw;
z-index: 9999999;
transform: scaleX(-1);
}
</style>
</head>
<body>
<div id="container">
</div>
<video id="video-feed">
</video>
</body>
</html>

List of blendshapes

  1. browDownLeft
  2. browDownRight
  3. browInnerUp
  4. browOuterUpLeft
  5. browOuterUpRight
  6. cheekPuff
  7. cheekSquintLeft
  8. cheekSquintRight
  9. eyeBlinkLeft
  10. eyeBlinkRight
  11. eyeLookDownLeft
  12. eyeLookDownRight
  13. eyeLookInLeft
  14. eyeLookInRight
  15. eyeLookOutLeft
  16. eyeLookOutRight
  17. eyeLookUpLeft
  18. eyeLookUpRight
  19. eyeSquintLeft
  20. eyeSquintRight
  21. eyeWideLeft
  22. eyeWideRight
  23. jawForward
  24. jawLeft
  25. jawOpen
  26. jawRight
  27. mouthClose
  28. mouthDimpleLeft
  29. mouthDimpleRight
  30. mouthFrownLeft
  31. mouthFrownRight
  32. mouthFunnel
  33. mouthLeft
  34. mouthLowerDownLeft
  35. mouthLowerDownRight
  36. mouthPressLeft
  37. mouthPressRight
  38. mouthPucker
  39. mouthRight
  40. mouthRollLower
  41. mouthRollUpper
  42. mouthShrugLower
  43. mouthShrugUpper
  44. mouthSmileLeft
  45. mouthSmileRight
  46. mouthStretchLeft
  47. mouthStretchRight
  48. mouthUpperUpLeft
  49. mouthUpperUpRight
  50. noseSneerLeft
  51. noseSneerRight
  52. tongueOut