场景动起来有两种方式:第一种方法是让物体在坐标系里面移动,摄像机不动。第二种方法是让摄像机在坐标系里面移动,物体不动。这样场景就能够动起来了。
一、渲染循环
如果想要将场景绘制到浏览器中,就需要调用渲染器的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()完成了让动画动起来到目标。如果不调用这个函数场景就不能动起来了。