Three.JS学习 4:循环渲染与动画

时间:2021-11-09 06:33:46

本文学习内容来源:
http://www.hewebgl.com/article/getarticle/58

渲染

renderer.render(scence,camera);

当改变了物体的属性时,需要重新调用render()函数,浏览器才会自动刷新场景。
为了循环渲染,要使用requestAnimationFrame函数,传递一个callback参数。

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

移动摄像机让物体动起来

移动一个物体的源代码:


<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Three框架</title>
<script src="js/three.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,width,height;
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);
}

function initObject() {
var geometry = new THREE.CylinderGeometry(100, 150, 400);
var material = new THREE.MeshLambertMaterial({ color: 0x33FF33 });
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() {
camera.position.x = camera.position.x + 1;
if (camera.position.x > width-400) camera.position.x = 0;
renderer.render(scene, camera);
requestAnimationFrame(animation);
}
</script>
</head>

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

Three.JS学习 4:循环渲染与动画

CylinderGeometry函数说明

  • radiusTop: 柱体顶部半径
  • radiusBottom:柱体底部半径
  • height:柱体高度
  • radiusSegments:圆周分段,数字越高柱体越圆滑
  • heightSegments:高度分段,与上类似
  • openEnded:是否显示顶盖和底板
  • theraStart, thetaLength:暂不清楚

改变物体坐标,让物体动起来

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Three框架</title>
<script src="js/three.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,width,height;
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 mesh; //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;
console.log(mesh.position.x);
if (mesh.position.x < -(width - 400)) mesh.position.x = 0;
renderer.render(scene, camera);
requestAnimationFrame(animation);
}

</script>
</head>

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

Three.JS学习 4:循环渲染与动画

评估程序性能

帧数

定义:图形处理器每秒能刷新多少次
单位:fps(Frames Per Second)

当物体在快速运动时,当人眼所看到影像消失后,人眼仍能继续保留其影像1/24左右的图像,称为视觉暂留现象。一帧一帧的图像进入人脑,人脑将会将这些图像连接起来,形成动画。
帧数越高,画面感觉越流畅。大多数游戏FPS超过30.

添加性能监视器Stats

https://github.com/mrdoob/stats.js
可以看到Three.js的性能监视器。
性能监视器:

FPS监视器

Three.JS学习 4:循环渲染与动画
FPS : 上一秒的帧数,越大越好,一般为60左右

点击它,会显示:

MS监视器

Three.JS学习 4:循环渲染与动画

MS 表示渲染一帧需要的毫秒数,越小越好。

MB监视器

Three.JS学习 4:循环渲染与动画
占用内存多少M字节。启动谷歌浏览器时,使用

--enable-precise-memory-info

CUSTOM监视器

Three.JS学习 4:循环渲染与动画
支持用户自定义的panel

使用Stats

var stats = new Stats();
stats.showPanel( 1 ); // 0: fps, 1: ms, 2: mb, 3+: custom
document.body.appendChild( stats.dom );

function animate() {
stats.begin();
// monitored code goes here
stats.end();
requestAnimationFrame( animate );
}

requestAnimationFrame( animate );

完整示例代码:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Three框架</title>
<script src="js/three.min.js"></script>
<script src="js/stats.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, width, height;
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.showPanel(1); // 0: fps, 1: ms, 2: mb, 3+: custom
document.body.appendChild(stats.dom);
}

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 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() {
stats.begin();
mesh.position.x -= 1;
console.log(mesh.position.x);
if (mesh.position.x < -(width - 400)) mesh.position.x = 0;
renderer.render(scene, camera);
stats.end();
requestAnimationFrame(animation);
}

</script>
</head>

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

结果:
Three.JS学习 4:循环渲染与动画

上面代码里的stats.begin和stats.end可以再次封装:

            function animation() {
mesh.position.x -= 1;
console.log(mesh.position.x);
if (mesh.position.x < -(width - 400)) mesh.position.x = 0;
renderer.render(scene, camera);
requestAnimationFrame(animation);
stats.update();
}

stats.update封装了stats.begin/stats.end

使用Tween.js创建动画

https://github.com/sole 下载库文件
使用方法:

构建Tween对象并初始化

function initTween()
{

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

构造函数:要改变的值。
to():接受两个参数,1:集合,存放键值对,x表示mesh.position的x属性, 2:完成动画需要的时间
repeat():重复几次,Infinity是无穷次
start():开始动画

实现动画

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

完整示例:

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


</style>
<script>
var renderer, width, height;
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.showPanel(1); // 0: fps, 1: ms, 2: mb, 3+: custom
document.body.appendChild(stats.dom);
}

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 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 initTween() {
new TWEEN.Tween(mesh.position).to({ x: -400 }, 3000).repeat(Infinity).start();
}
function threeStart() {
initThree();
initCamera();
initScene();
initLight();
initObject();
initTween();
animation();

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

</script>
</head>

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