ThreeJS 旋转动画

5
我在ThreeJS中有一个立方体,我希望每次按下按钮时将其顺时针旋转90度。我认为我已经有了基本的思路:创建一个Three.Animation实例,将其绑定到立方体上,然后每次按下正确的按钮时开始动画。但是,我很难理解ThreeJS的API,因为它似乎没有包含任何方法的示例。
这是THREE.js的Animation构造函数:(root,data,interpolationType,JITCompile)我不明白这些字段应该填什么。我猜root应该是我放置立方体的地方,但其他字段呢?
另外,我能否只调用animation.play()以在需要时启动动画?动画处理程序(animationHandler)又是如何工作的?
1个回答

12

我认为对于将物体顺时针旋转90度,使用TWEEN类会有所帮助。对于更复杂的内容(如骨骼/皮肤变形等),我认为Animation类会更方便。

要使用TWEEN类,有三个基本步骤:

  1. 在文件中包含该类 (<script src="js/Tween.js"></script>)
  2. 为所需事件添加tween (new TWEEN.Tween( cube.rotation ).to( { y:Math.random()}, 1000 ).easing( TWEEN.Easing.Quadratic.EaseOut).start();)
  3. 在渲染循环中更新tween (TWEEN.update();)

您可以参考cubes tween example 开始尝试。

我已经修改了默认的立方体示例,加入了tween效果:

three.js cube tween

<!doctype html>
<html lang="en">
    <head>
        <title>three.js canvas - geometry - cube</title>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
        <style>
            body {
                font-family: Monospace;
                background-color: #f0f0f0;
                margin: 0px;
                overflow: hidden;
            }
        </style>
    </head>
    <body>

        <script src="../build/Three.js"></script>
        <script src="js/Tween.js"></script>
        <script src="js/RequestAnimationFrame.js"></script>
        <script src="js/Stats.js"></script>

        <script>

            var container, stats;

            var camera, scene, renderer;

            var cube, plane;

            var windowHalfX = window.innerWidth / 2;
            var windowHalfY = window.innerHeight / 2;

            var rad90 = Math.PI * .5;

            init();
            animate();

            function init() {

                container = document.createElement( 'div' );
                document.body.appendChild( container );

                var info = document.createElement( 'div' );
                info.style.position = 'absolute';
                info.style.top = '10px';
                info.style.width = '100%';
                info.style.textAlign = 'center';
                info.innerHTML = 'click to tween';
                container.appendChild( info );

                camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 1000 );
                camera.position.y = 150;
                camera.position.z = 500;

                scene = new THREE.Scene();

                // Cube

                var materials = [];

                for ( var i = 0; i < 6; i ++ ) {

                    materials.push( [ new THREE.MeshBasicMaterial( { color: Math.random() * 0xffffff } ) ] );

                }

                cube = new THREE.Mesh( new THREE.CubeGeometry( 200, 200, 200, 1, 1, 1, materials ), new THREE.MeshFaceMaterial() );
                cube.position.y = 150;
                cube.overdraw = true;
                scene.add( cube );

                // Plane

                plane = new THREE.Mesh( new THREE.PlaneGeometry( 200, 200 ), new THREE.MeshBasicMaterial( { color: 0xe0e0e0 } ) );
                plane.rotation.x = - 90 * ( Math.PI / 180 );
                plane.overdraw = true;
                scene.add( plane );

                renderer = new THREE.CanvasRenderer();
                renderer.setSize( window.innerWidth, window.innerHeight );

                container.appendChild( renderer.domElement );

                stats = new Stats();
                stats.domElement.style.position = 'absolute';
                stats.domElement.style.top = '0px';
                container.appendChild( stats.domElement );

                document.addEventListener( 'mousedown', onDocumentMouseDown, false );
            }

            //

            function onDocumentMouseDown( event ) {

                event.preventDefault();
                new TWEEN.Tween( cube.rotation ).to( {  y:  cube.rotation.y + rad90}, 1000 ).easing( TWEEN.Easing.Quadratic.EaseOut).start();
                new TWEEN.Tween( plane.rotation ).to( { z:  plane.rotation.z + rad90}, 1000 ).easing( TWEEN.Easing.Quadratic.EaseOut).start();

                console.log("click");
            }

            //

            function animate() {

                requestAnimationFrame( animate );

                render();
                stats.update();

            }

            function render() {
                TWEEN.update();
                renderer.render( scene, camera );

            }

        </script>

    </body>
</html>

谢谢你的帮助!我们最终使用了Tween.js,一切都很顺利。 - Catherine Hwang
我是否错了,这将插值欧拉角(这通常是您不想做的事情)?如果您想要插值四元数怎么办?特别是,您通常希望在四元数之间进行球形插值。有没有简单的方法来调整此代码以实现这一点?或者我们被困在检索自缓动开始以来经过的时间(如果可能)并手动使用正确的时间调用quaternion.slerp吗? - Bakuriu
@Bakuriu 我没有在原始问题中发现关于欧拉旋转的问题。我理解的问题是使用正确的类来使用three.js库动画化属性(在这种情况下是旋转):主要是一个语法/ API问题,而不是线性代数问题。你是对的,在三维空间中应该避免使用欧拉角进行旋转,但在这个简单的示例场景中,实际上并没有什么区别。您应该能够使用Tween类来动画化Object3Dquaternion属性,只需确保在启动tween之前将useQuaternion设置为true即可。 - George Profenza
1
谢谢分享!我曾经遇到一个问题,因为我使用了 TWEEN.Easing.Sinusoidal.EaseInOut 而不是 TWEEN.Easing.Sinusoidal.InOut。出现了错误 "TypeError: this._easingFunction is not a function"。可能缓动函数的名称在最近版本中有所更改。 - Maxime Pacary
1
@FrostyZ 我完全明白你的意思。最好双重检查你正在使用的库版本的参考资料(值得注意的是,这个答案现在已经有6年了)。根据你想要的运动方式,你可能可以简单地使用二次函数,如果是这样,它也会稍微更有效率,因为它不会在后台使用 Math.sin()/Math.cos() - George Profenza
感谢您的有用评论和性能提示。非常感激 :) - Maxime Pacary

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接