首页 > 解决方案 > 为什么three.module.js的AnimationMixer与three.min.js的工作方式不同

问题描述

当我使用来自three.module.js 的AnimationMixer 时,我注意到了一个令人恼火的系统反应:我的代码旨在改变立方体在VectorKeyframeTrack 中给定的时间轴上的位置。基本上它可以工作,但是当我使用mixer.stopAllAction()停止动画时,立方体并没有在停止的那一刻停留在该位置,而是下降到它的起始位置。同样,当动画剪辑结束并且立方体定位在目标位置时(我使用了clampWhenFinished = true),使用stopAllAction() 时位置更改为起始位置。在我看来,动画并没有真正改变立方体的位置值。原点被保留,一旦动画停止,该原点将再次应用。

现在我发现,在使用three.min.js库时,并没有出现这种现象。然后可以在中间停止动画移动,并且立方体保持其停止点的位置值。换句话说,使用 three.min.js 它可以按预期工作。尽管如此,我还是想使用three.module.js,因为它提供了我以后需要的其他功能。

所以我的问题是:three.module.js 中的 AnimationMixer 行为是错误还是功能?如果是一个功能,有人可以解释为什么这是有意义的吗?

我当前的解决方案是一个混合代码:我使用了 three.module.js 中的所有内容,但我还必须加载 three.min.js 才能将它用于“旧但工作”的 AnimationMixer。

为了解决这个问题,我制作了三个示例代码:a)基于three.min.js(有效)b)基于three.module.js(显示奇怪的行为)c)具有两个库的混合(有效)

我在这里添加 b) 的代码以防有人感兴趣。此代码仅用于演示问题,并且某些值是硬编码的。我正在使用两个可以通过页面上的按钮启动的混音器。x、y 和 z 位置在对象移动时填充。使用 Stop All Animations 按钮,立方体的移动应该停止。但在这个版本 b) 中,您会看到它会退回到原来的位置。

索引.html:

    <html>
    <head>
        <title>Demo 1 based on three.module.js</title>
        <style>
            body { margin: 0; }
            canvas { width: 100%; height: 100% }
        </style>
    </head>

    <div>
        <label for="PositionX">X-Position:</label>
        <input type="text" id="PositionX"  size="2" value="0" onchange="game.changeXPos.call(game, this.value)" />
    
        <label for="PositionY">Y-Position:</label>
        <input type="text" id="PositionY"  size="2" value="0" onchange="game.changeYPos.call(game, this.value)" />

        <label for="PositionZ">Z-Position:</label>
        <input type="text" id="PositionZ"  size="2" value="0" onchange="game.changeZPos.call(game, this.value)" />

        <button onclick="game.stopAnimation.call(game);">Stop All Animations</button>
        <button onclick="game.playAnimationCube1.call(game);">Move Cube1</button>
        <button onclick="game.playAnimationCube2.call(game);">Move Cube2</button>

    </div>
    <body>
        <script type="module" src="main.js"></script>

    </body>
</html>

主.js:

import { Game } from './game.js';

async function main() {
    

  // Get a reference to the container element
  const container = document.querySelector('#scene-container');

var game;
            
document.addEventListener("DOMContentLoaded", function(){
    game = new Game(container); 
    console.log("demo1modular: In mainjs game", game);  
    
    window.game = game;
});

}


main().catch((err) => {
  console.error(err);
});

带有动画逻辑的game.js:

import { Clock, Color, Scene, PerspectiveCamera, WebGLRenderer, BoxGeometry, 
    DirectionalLight, AmbientLight, MeshPhongMaterial, 
    Mesh,  AnimationMixer, AnimationClip, LoopOnce, VectorKeyframeTrack 
    } from 'https://unpkg.com/three@0.117.0/build/three.module.js';

    let camera;
    let clock;
    let renderer;
    let scene;
    let mode;
    let modes;
    let cube;
    let mixer1;
    let mixer2;
    let action1;
    let action2;
    
class Game{
    constructor(){
        modes = Object.freeze({
            NONE:   Symbol("none"),
            ANIMATION_ACTIVE: Symbol("active"),
            ANIMATION_OFF:  Symbol("off")
        });
        mode = modes.NONE; 

        clock = new Clock();
        scene = new Scene();
        camera = new PerspectiveCamera( 75, window.innerWidth/window.innerHeight, 0.1, 1000 );

        renderer = new WebGLRenderer();
        renderer.setSize( window.innerWidth, window.innerHeight );
        document.body.appendChild( renderer.domElement );

        const geometry = new BoxGeometry( 1, 1, 1 );
        const light = new DirectionalLight( 0xffffff );
        light.position.set( 0, 20, 10 );
        const ambient = new AmbientLight( 0x707070 ); // soft white light

        const material = new MeshPhongMaterial( { color: 0x00aaff } );
        
        cube = new Mesh( geometry, material );

  
        scene.add( light );
        scene.add( ambient );

        camera.position.z = 5;
        
        mixer1 = new THREE.AnimationMixer( cube );
        const times = [0, 2];
        const values1 = [0,0,0,  0,2,0 ];
        const positionKF1 = new VectorKeyframeTrack('.position', times, values1);
        const length = -1;
        const myClipPos1 = new AnimationClip('Position change', length, [positionKF1])
        console.log("demo1modular: myClipPos1:", myClipPos1);
        action1 = mixer1.clipAction( myClipPos1);
        action1.clampWhenFinished = true;
        console.log("demo1modular: In createAnimations action:", action1);
  
        // the second track starts where the first has ended
        mixer2 = new THREE.AnimationMixer( cube );
        const values2 = [0,2,0,  -2,0,0 ];
        const positionKF2 = new VectorKeyframeTrack('.position', times, values2);
        const myClipPos2 = new AnimationClip('Position change', length, [positionKF2])
        console.log("demo1modular: myClipPos2:", myClipPos2);
        action2 = mixer2.clipAction( myClipPos2);
        action2.clampWhenFinished = true;
        console.log("demo1modular: In createAnimations action:", action2);


        scene.add( cube );
   
        this.animate();
        this.positionChange();
    }
    
    animate() {
        const game = this;
        requestAnimationFrame( function(){ game.animate(); } );
        const delta = clock.getDelta();
        cube.rotation.x += 0.01;
        cube.rotation.y += 0.01;

        if (mode == modes.ANIMATION_ACTIVE)
        {
            document.getElementById("PositionX").value = cube.position.x;
            document.getElementById("PositionY").value = cube.position.y;
            document.getElementById("PositionZ").value = cube.position.z;
  
        }

        mixer1.update( delta )
        mixer2.update( delta )
        renderer.render( scene, camera );
    }

    positionChange() {
        // put it on the bottom
        cube.position.set (0,-2,0);
        // show the actual position in the page
        document.getElementById("PositionX").value = cube.position.x;
        document.getElementById("PositionY").value = cube.position.y;
        document.getElementById("PositionZ").value = cube.position.z;
    }

    changeXPos(value) {cube.position.x = value;}
    changeYPos(value) {cube.position.y = value;}
    changeZPos(value) {cube.position.z = value;}

    stopAnimation(){
        mixer1.stopAllAction();
        mixer2.stopAllAction();
        mode = modes.ANIMATION_OFF;
        document.getElementById("PositionX").value = cube.position.x;
        document.getElementById("PositionY").value = cube.position.y;
        document.getElementById("PositionZ").value = cube.position.z;

    }

    playAnimationCube1(){
            mode = modes.ANIMATION_ACTIVE;
            console.log('demo1modular in playAnimationCube  mixer, action',  mixer1, action1);
            mixer1.stopAllAction();
            action1.weight = 1;
            action1.fadeIn(0.5);
            action1.loop = LoopOnce;
            action1.play();
            mixer1.addEventListener('finished', function(e){ 
                // the following statement I would like to execute but it does not work
                // mode = modes.ANIMATION_OFF;
        })

    }     

    playAnimationCube2(){
        mode = modes.ANIMATION_ACTIVE;
        console.log('demo1modular in playAnimationCube  mixer, action',  mixer2, action2);
        mixer2.stopAllAction();
        action2.weight = 1;
        action2.fadeIn(0.5);
        action2.loop = LoopOnce;
        action2.play();
        mixer2.addEventListener('finished', function(e){ 
            // the following statement I would like to execute but it does not work
            // mode = modes.ANIMATION_OFF;
    })

}    
}
export { Game };

标签: javascriptthree.js

解决方案


推荐阅读