FOPENP

Three.js: complex animations

On three.js you can use complex animations regulating weights. In this code example I show a character with 3 animations: one for walking, one for moving the head and one for moving the arms.

    1 <!DOCTYPE html>
    2 <html>
    3     <head>
    4         <meta charset="utf-8">
    5         <title>Test Three.js</title>
    6         <style>
    7             body {
    8                 background-color: #888;
    9             }
   10         </style>
   11     </head>
   12     <body>
   13         <script type="importmap">
   14             {
   15               "imports": {
   16                 "three": "./three.module.js",
   17                 "three/addons/": "./addons/"
   18               }
   19             }
   20         </script>
   21         <script type="module">
   22             import * as THREE from './three.module.js';
   23             import { GLTFLoader } from './addons/GLTFLoader.js';
   24             import { OrbitControls } from './addons/OrbitControls.js';
   25             import Stats from './libs/stats.module.js';
   26             import { GUI } from './libs/lil-gui.module.min.js';
   27 
   28             let stats = new Stats();
   29             document.body.appendChild(stats.dom);
   30 
   31             const panel = new GUI({ width: 300 });
   32             const panelc1 = panel.addFolder("Character");
   33             let panelsettings = {
   34                 'walking_loop': 1.0,
   35                 'look_loop': 1.0,
   36                 'moveArms_loop': 1.0
   37             }
   38 
   39             function setWeight(animName) {
   40                 clips.forEach((clip) => { if (clip.name === animName) { mixer.clipAction(clip).setEffectiveWeight(panelsettings[animName]); } });
   41             }
   42             
   43             panelc1.add(panelsettings, "walking_loop", 0.0, 1.0, 0.01).onChange(function () { setWeight('walking_loop'); });
   44             panelc1.add(panelsettings, "look_loop", 0.0, 1.0, 0.01).onChange(function () { setWeight('look_loop'); });
   45             panelc1.add(panelsettings, "moveArms_loop", 0.0, 1.0, 0.01).onChange(function () { setWeight('moveArms_loop'); });
   46 
   47             const renderer = new THREE.WebGLRenderer();
   48             renderer.setPixelRatio(window.devicePixelRatio);
   49             renderer.setSize(window.innerWidth, window.innerHeight);
   50             document.body.appendChild(renderer.domElement);
   51 
   52             const scene = new THREE.Scene();
   53             scene.background = new THREE.Color(0x888888);
   54 
   55             const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
   56             camera.position.set(0, 0, 1);
   57             camera.lookAt(0, 0, 0);
   58             scene.add(camera);
   59 
   60             const light = new THREE.PointLight(0xffffff, 10.0);
   61             camera.add(light);
   62 
   63             const controls = new OrbitControls(camera, renderer.domElement);
   64             controls.target.set(0, 0.5, 0);
   65             controls.update();
   66             controls.enablePan = false;
   67             controls.enableDamping = true;
   68 
   69             const loader = new GLTFLoader();
   70             let mixer = null;
   71             let clips = [];
   72             loader.load(
   73                 "omino-01.en.gltf",
   74                 function (gltf) {
   75                     // Resource has been loaded.
   76 
   77                     mixer = new THREE.AnimationMixer(gltf.scene);
   78                     gltf.animations.forEach((clip) => {
   79                         clips.push(clip);
   80                         console.log("Clip name: " + clip.name);
   81                         mixer.clipAction(clip).play();
   82                     });
   83 
   84                     scene.add(gltf.scene);
   85                 },
   86                 function (xhr) {
   87                     // Resource is loading
   88                     console.log("Loading... " + (xhr.loaded / xhr.total * 100) + "%");
   89                 },
   90                 function (error) {
   91                     // Error during loading
   92                     console.error("Error during the asset loading: " + error);
   93                 }
   94             );
   95 
   96             let clock = new THREE.Clock();
   97 
   98             function animate() {
   99                 const delta = clock.getDelta();
  100                 requestAnimationFrame(animate);
  101                 if (stats)
  102                     stats.update();
  103                 controls.update();
  104                 if (mixer)
  105                     mixer.update(delta);
  106                 renderer.render(scene, camera);
  107             }
  108             animate();
  109         </script>
  110     </body>
  111 </html>

Click here to see the running script.

At line 40 a setEffectiveWeight() function is used to indicate how much weight needs to be used to the current animations. Weights are regulated acting on the configuration panel's sliders.

2023
Dec, 26