Three.js场景运动

时间:2022-01-01 04:17:15

  场景动起来有两种方式:第一种方法是让物体在坐标系里面移动,摄像机不动。第二种方法是让摄像机在坐标系里面移动,物体不动。这样场景就能够动起来了。

一、渲染循环

  如果想要将场景绘制到浏览器中,就需要调用渲染器的render()函数。代码如下:

renderer.render( scene, camera );

  所以在物体运动过程中,如果场景发生改变,就需要重新调用render()函数重新渲染场景到浏览器,所以,我们需要一个渲染循环。

  为了实现循环,我们需要javascript的一个特殊函数,这个函数是requestAnimationFrame。

  调用requestAnimationFrame函数,传递一个callback参数,则在下一个动画帧时,会调用callback这个函数。

  于是,我们的游戏循环会这样写。

function animate() {
render();
requestAnimationFrame( animate );
}

  这样就会不断的执行animate这个函数。也就是不断的执行render()函数。在render()函数中不断的改变物体或者摄像机的位置,并渲染它们,就能够实现动画了。

二、改变相机位置,让物体移动

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>Three框架</title>
        <script src="js/Three.js"></script>
        <style type="text/css">
            div#canvas-frame {
                border: none;
                cursor: pointer;
                width: 100%;
                height: 600px;
                background-color: #EEEEEE;
            }

        </style>
        <script>
            var renderer;
            function initThree() {
                width = document.getElementById('canvas-frame').clientWidth;
                height = document.getElementById('canvas-frame').clientHeight;
                renderer = new THREE.WebGLRenderer({
                    antialias : true
                });
                renderer.setSize(width, height);
                document.getElementById('canvas-frame').appendChild(renderer.domElement);
                renderer.setClearColor(0xFFFFFF, 1.0);
            }

            var camera;
            function initCamera() {
                camera = new THREE.PerspectiveCamera(45, width / height, 1, 10000);
                camera.position.x = 0;
                camera.position.y = 0;
                camera.position.z = 600;
                camera.up.x = 0;
                camera.up.y = 1;
                camera.up.z = 0;
                camera.lookAt({
                    x : 0,
                    y : 0,
                    z : 0
                });
            }

            var scene;
            function initScene() {
                scene = new THREE.Scene();
            }

            var light;
            function initLight() {
                light = new THREE.AmbientLight(0xFFFFFF);
                light.position.set(100, 100, 200);
                scene.add(light);
                light = new THREE.PointLight(0x00FF00);
                light.position.set(0, 0,300);
                scene.add(light);
            }

            var cube;
            function initObject() {
                var geometry = new THREE.CylinderGeometry( 100,150,400);
                var material = new THREE.MeshLambertMaterial( { color:0xFFFF00} );
                var mesh = new THREE.Mesh( geometry,material);
                mesh.position = new THREE.Vector3(0,0,0);
                scene.add(mesh);
            }

            function threeStart() {
                initThree();
                initCamera();
                initScene();
                initLight();
                initObject();
                animation();

            }
            function animation()
            {
                //renderer.clear();
                camera.position.x =camera.position.x +1;
                renderer.render(scene, camera);
                requestAnimationFrame(animation);
            }

        </script>
    </head>

    <body onload="threeStart();">
        <div id="canvas-frame"></div>
    </body>
</html>      

  通过下面的代码改变相机的位置:

camera.position.x =camera.position.x +1;

  将相机不断的沿着x轴移动1个单位,也就是相机向右移动。相机向右移动,相机中的物体看起来像是向左移动。

  设置完相机的位置后,调用requestAnimationFrame(animation)函数,这个函数又会在下一个动画帧出发animation()函数,这样就不断改变了相机的位置,从而物体看上去在移动了。

  另外,必须要重视render函数,这个函数是重新绘制渲染结果,如果不调用这个函数,那么即使相机的位置变化了,但是没有重新绘制,仍然显示的是上一帧的动画。Render函数调用如下:

renderer.render(scene, camera);

三、改变物体自身位置,让物体移动

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>Three框架</title>
        <script src="js/Three.js"></script>
        <style type="text/css">
            div#canvas-frame {
                border: none;
                cursor: pointer;
                width: 100%;
                height: 600px;
                background-color: #EEEEEE;
            }

        </style>
        <script>
            var renderer;
            function initThree() {
                width = document.getElementById('canvas-frame').clientWidth;
                height = document.getElementById('canvas-frame').clientHeight;
                renderer = new THREE.WebGLRenderer({
                    antialias : true
                });
                renderer.setSize(width, height);
                document.getElementById('canvas-frame').appendChild(renderer.domElement);
                renderer.setClearColor(0xFFFFFF, 1.0);
            }

            var camera;
            function initCamera() {
                camera = new THREE.PerspectiveCamera(45, width / height, 1, 10000);
                camera.position.x = 0;
                camera.position.y = 0;
                camera.position.z = 600;
                camera.up.x = 0;
                camera.up.y = 1;
                camera.up.z = 0;
                camera.lookAt({
                    x : 0,
                    y : 0,
                    z : 0
                });
            }

            var scene;
            function initScene() {
                scene = new THREE.Scene();
            }

            var light;
            function initLight() {
                light = new THREE.AmbientLight(0xFF0000);
                light.position.set(100, 100, 200);
                scene.add(light);
                light = new THREE.PointLight(0x00FF00);
                light.position.set(0, 0,300);
                scene.add(light);
            }

            var cube;
            var mesh;
            function initObject() {
                var geometry = new THREE.CylinderGeometry( 100,150,400);
                var material = new THREE.MeshLambertMaterial( { color:0xFFFFFF} );
                mesh = new THREE.Mesh( geometry,material);
                mesh.position = new THREE.Vector3(0,0,0);
                scene.add(mesh);
            }

            function threeStart() {
                initThree();
                initCamera();
                initScene();
                initLight();
                initObject();
                animation();

            }
            function animation()
            {
                mesh.position.x-=1;
                renderer.render(scene, camera);
                requestAnimationFrame(animation);
            }

        </script>
    </head>

    <body onload="threeStart();">
        <div id="canvas-frame"></div>
    </body>
</html>

  通过移动物体本身的位置来让物体运动,代码如下:

mesh.position.x-=1;

  其中mesh就是指的物体,它有一个位置属性position,这个position是一个THREE.Vector3类型变量,所以你要把它向左移动,只需要将x的值不断的减少就可以了。这里我们减去的是1个单位。

四、性能监视器Stats

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>Three框架</title>
        <script src="js/Three.js"></script>
        <script src="js/Stats.js"></script>

        <style type="text/css">
            div#canvas-frame {
                border: none;
                cursor: pointer;
                width: 100%;
                height: 600px;
                background-color: #EEEEEE;
            }

        </style>
        <script>
            var renderer;
            var stats;
            function initThree() {
                width = document.getElementById('canvas-frame').clientWidth;
                height = document.getElementById('canvas-frame').clientHeight;
                renderer = new THREE.WebGLRenderer({
                    antialias : true
                });
                renderer.setSize(width, height);
                document.getElementById('canvas-frame').appendChild(renderer.domElement);
                renderer.setClearColor(0xFFFFFF, 1.0);

                stats = new Stats();
                stats.domElement.style.position = 'absolute';
                stats.domElement.style.left = '0px';
                stats.domElement.style.top = '0px';
                document.getElementById('canvas-frame').appendChild(stats.domElement);
            }

            var camera;
            function initCamera() {
                camera = new THREE.PerspectiveCamera(45, width / height, 1, 10000);
                camera.position.x = 0;
                camera.position.y = 0;
                camera.position.z = 600;
                camera.up.x = 0;
                camera.up.y = 1;
                camera.up.z = 0;
                camera.lookAt({
                    x : 0,
                    y : 0,
                    z : 0
                });
            }

            var scene;
            function initScene() {
                scene = new THREE.Scene();
            }

            var light;
            function initLight() {
                light = new THREE.AmbientLight(0xFF0000);
                light.position.set(100, 100, 200);
                scene.add(light);
                light = new THREE.PointLight(0x00FF00);
                light.position.set(0, 0,300);
                scene.add(light);
            }

            var cube;
            var mesh;
            function initObject() {
                var geometry = new THREE.CylinderGeometry( 100,150,400);
                var material = new THREE.MeshLambertMaterial( { color:0xFFFFFF} );
                mesh = new THREE.Mesh( geometry,material);
                mesh.position = new THREE.Vector3(0,0,0);
                scene.add(mesh);
            }

            function threeStart() {
                initThree();
                initCamera();
                initScene();
                initLight();
                initObject();
                animation();

            }
            function animation()
            {
                renderer.clear();
                //camera.position.x =camera.position.x +1;
                mesh.position.x-=1;
                renderer.render(scene, camera);
                requestAnimationFrame(animation);

                stats.update();
            }

        </script>
    </head>

    <body onload="threeStart();">
        <div id="canvas-frame"></div>
    </body>
</html>

1、new 一个stats对象,代码如下

stats = new Stats();

2、将这个对象加入到html网页中去,代码如下

stats.domElement.style.position = 'absolute';
stats.domElement.style.left = '0px';
stats.domElement.style.top = '0px';

3、调用stats.update()函数来统计时间和帧数。代码如下

stats.update();

 五、创建动画

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>Three框架</title>
        <script src="js/Three.js"></script>
        <script src="js/Stats.js"></script>
        <script src="js/tween.min.js"></script>

        <style type="text/css">
            div#canvas-frame {
                border: none;
                cursor: pointer;
                width: 100%;
                height: 600px;
                background-color: #EEEEEE;
            }

        </style>
        <script>
            var renderer;
            var stats;

            function initThree() {
                width = document.getElementById('canvas-frame').clientWidth;
                height = document.getElementById('canvas-frame').clientHeight;
                renderer = new THREE.WebGLRenderer({
                    antialias : true
                });
                renderer.setSize(width, height);
                document.getElementById('canvas-frame').appendChild(renderer.domElement);
                renderer.setClearColor(0xFFFFFF, 1.0);

                stats = new Stats();
                stats.domElement.style.position = 'absolute';
                stats.domElement.style.left = '0px';
                stats.domElement.style.top = '0px';
                document.getElementById('canvas-frame').appendChild(stats.domElement);
            }

            var camera;
            function initCamera() {
                camera = new THREE.PerspectiveCamera(45, width / height, 1, 10000);
                camera.position.x = 0;
                camera.position.y = 0;
                camera.position.z = 600;
                camera.up.x = 0;
                camera.up.y = 1;
                camera.up.z = 0;
                camera.lookAt({
                    x : 0,
                    y : 0,
                    z : 0
                });
            }

            var scene;
            function initScene() {
                scene = new THREE.Scene();
            }

            var light;
            function initLight() {
                light = new THREE.AmbientLight(0xFF0000);
                light.position.set(100, 100, 200);
                scene.add(light);
                
                light = new THREE.PointLight(0x00FF00);
                light.position.set(0, 0,300);
                scene.add(light);
            }

            var cube;
            var mesh;
            function initObject() {
                var geometry = new THREE.CylinderGeometry( 100,150,400);
                var material = new THREE.MeshLambertMaterial( { color:0xFFFFFF} );
                mesh = new THREE.Mesh( geometry,material);
                mesh.position = new THREE.Vector3(0,0,0);
                scene.add(mesh);
            }

            function threeStart() {
                initThree();
                initCamera();
                initScene();
                initLight();
                initObject();
                initTween();
                animation();

            }
            function initTween()
            {
                new TWEEN.Tween( mesh.position)
                        .to( { x: -400 }, 3000 ).repeat( 1 ).start();
            }
            function animation()
            {
                renderer.render(scene, camera);
                requestAnimationFrame(animation);
                
                stats.update();
                TWEEN.update();
            }

        </script>
    </head>

    <body onload="threeStart();">
        <div></div>
        <div id="canvas-frame"></div>
    </body>
</html>

  为了使程序编写更容易一些,我们可以使用动画引擎来实现动画效果。和three.js紧密结合的动画引擎是Tween.js,Tween.js是一个容易上手的工具。

首先,你需要引用js文件,如下:

<-script src="../js/tween.min.js" data-ke-src="../js/tween.min.js"><-/script>

第二步,就是构件一个Tween对象,对Tween进行初始化,本例的代码是:

function initTween()
{
    new TWEEN.Tween( mesh.position)
            .to( { x: -400 }, 3000 ).repeat( Infinity ).start();
}

第三步是,需要在渲染函数中去不断的更新Tween,这样才能够让mesh.position.x移动位置:(update是为了将动画移动的过程渲染进去)

function animation()
{
    renderer.render(scene, camera);
    requestAnimationFrame(animation);
    stats.update();
    TWEEN.update();
}

其中的TWEEN.update()完成了让动画动起来到目标。如果不调用这个函数场景就不能动起来了。

六、出处

刚接触Three.js,这算是记录网上找资料学习的笔记,主要来源于WebGL中文网,如有侵权,请联系我删除。