FOPENP

Three.js: animazioni complesse

Su three.js si possono usare delle animazioni complesse regolando i pesi. In questo mio esempio di codice mostro un personaggio che ha 3 animazioni: una per camminare, una per muovere la testa e una per muovere le braccia.

    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 pannello = new GUI({ width: 300 });
   32             const pannelloc1 = pannello.addFolder("Personaggio");
   33             let impostazioniPannello = {
   34                 'camminata_loop': 1.0,
   35                 'guardaInAlto1_loop': 1.0,
   36                 'muoviLeBraccia1_loop': 1.0
   37             }
   38 
   39             function settaPeso(nomeAnim) {
   40                 clips.forEach((clip) => { if (clip.name === nomeAnim) { mixer.clipAction(clip).setEffectiveWeight(impostazioniPannello[nomeAnim]); } });
   41             }
   42             
   43             pannelloc1.add(impostazioniPannello, "camminata_loop", 0.0, 1.0, 0.01).onChange(function () { settaPeso('camminata_loop'); });
   44             pannelloc1.add(impostazioniPannello, "guardaInAlto1_loop", 0.0, 1.0, 0.01).onChange(function () { settaPeso('guardaInAlto1_loop'); });
   45             pannelloc1.add(impostazioniPannello, "muoviLeBraccia1_loop", 0.0, 1.0, 0.01).onChange(function () { settaPeso('muoviLeBraccia1_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 luce = new THREE.PointLight(0xffffff, 10.0);
   61             camera.add(luce);
   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.gltf",
   74                 function (gltf) {
   75                     // La risorsa e' stata caricata.
   76 
   77                     mixer = new THREE.AnimationMixer(gltf.scene);
   78                     gltf.animations.forEach((clip) => {
   79                         clips.push(clip);
   80                         console.log("Nome clip: " + clip.name);
   81                         mixer.clipAction(clip).play();
   82                     });
   83 
   84                     scene.add(gltf.scene);
   85                 },
   86                 function (xhr) {
   87                     // La risorsa e' in fase di caricamento.
   88                     console.log("Caricamento in corso... " + (xhr.loaded / xhr.total * 100) + "%");
   89                 },
   90                 function (errore) {
   91                     // Errore durante il caricamento della risorsa.
   92                     console.error("Errore durante il caricamento dell'omino: " + errore);
   93                 }
   94             );
   95 
   96             let clock = new THREE.Clock();
   97 
   98             function anima() {
   99                 const delta = clock.getDelta();
  100                 requestAnimationFrame(anima);
  101                 if (stats)
  102                     stats.update();
  103                 controls.update();
  104                 if (mixer)
  105                     mixer.update(delta);
  106                 renderer.render(scene, camera);
  107             }
  108             anima();
  109         </script>
  110     </body>
  111 </html>

Clicca qui per vedere lo script in esecuzione.

Alla riga n.40 viene utilizzata la funzione setEffectiveWeight() che indica a three.js quanto peso dare alle animazioni correnti. I pesi vengono dati agendo sugli slider del pannello di configurazione.

2023
26 dic