本文学习内容来源:
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>
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>
评估程序性能
帧数
定义:图形处理器每秒能刷新多少次
单位:fps(Frames Per Second)
当物体在快速运动时,当人眼所看到影像消失后,人眼仍能继续保留其影像1/24左右的图像,称为视觉暂留现象。一帧一帧的图像进入人脑,人脑将会将这些图像连接起来,形成动画。
帧数越高,画面感觉越流畅。大多数游戏FPS超过30.
添加性能监视器Stats
https://github.com/mrdoob/stats.js
可以看到Three.js的性能监视器。
性能监视器:
FPS监视器
FPS : 上一秒的帧数,越大越好,一般为60左右
点击它,会显示:
MS监视器
MS 表示渲染一帧需要的毫秒数,越小越好。
MB监视器
占用内存多少M字节。启动谷歌浏览器时,使用
--enable-precise-memory-info
CUSTOM监视器
支持用户自定义的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>
结果:
上面代码里的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>