Three.js
简介
Three.js是众多WebGL三维引擎框架其中之一,源自github的一个开源项目,项目地址:https://github.com/mrdoob/three.js 。可以利用three.js进行网页上的三维场景(机械、建筑、游戏等)创建,能写出在浏览器上流畅运行的3D程序。如果没有前端基础,最好预先学习一点HTML/JavaScript方面的知识。
官方文档:https://threejs.org/docs/index.html#manual/en/introduction/Creating-a-scene
一、基本概念篇:第一个three.js三维场景
在Three.js中,要渲染物体到网页中,需要3个基本对象:
- 场景(scene)
- 相机(camera)
- 渲染器(renderer)
场景对应于整个布景空间,相机是拍摄镜头,渲染器用来把拍摄好的场景转换成胶卷。
1 | var scene = new THREE.Scene(); |
1、场景(scene)
1 | var scene = new THREE.Scene(); |
场景对应于整个布景空间,在Threejs中场景就只有一种,用THREE.Scene来表示。
2、相机(camera)
在Threejs中最常用的相机有两种
- 正投影相机THREE.OrthographicCamera
- 透视投影相机THREE.PerspectiveCamera
(1) 正投影相机THREE.OrthographicCamera
1 | var camera = new THREE.OrthographicCamera( width / - 2, width / 2, height / 2, height / - 2, 1, 1000 ); |
函数构造:OrthographicCamera( left : Number, right : Number, top : Number, bottom : Number, near : Number, far : Number )
参考:https://threejs.org/docs/index.html#api/zh/cameras/OrthographicCamera
正交投影相机示意图如下:
(2) 透视投影相机THREE.PerspectiveCamera
1 | var camera = new THREE.PerspectiveCamera( 45, width / height, 1, 1000 ); |
函数构造:PerspectiveCamera( fov : Number, aspect : Number, near : Number, far : Number )
参考:https://threejs.org/docs/index.html#api/zh/cameras/PerspectiveCamera
透视投影相机示意图如下:
3、 渲染器(renderer)
1 | var renderer = new THREE.WebGLRenderer(); |
除了创建renderer实例,还需要设置渲染空间的尺寸,一般使用目标屏幕的宽高(window.innerWidth和window.innerHeight),也可以给定一个尺寸。
渲染器renderer的domElement元素,表示渲染器中的画布,所有的渲染都是画在domElement上的,所以这里的appendChild表示将这个domElement挂接在body下面,这样渲染的结果就能够在页面中显示了。
4、 添加对象
现在的场景中是空的,我们向场景中加入最简单的立方体。
1 | var geometry = new THREE.BoxGeometry( 1, 1, 1 ); |
创建几何体,创建材质,利用几何体和材质创建对象,将对象加入场景scene中。
默认情况下,当我们调用scene.add()的时候,物体将会被添加到坐标为(0,0,0)的位置。但这可能会使得摄像机的位置和立方体相互重叠(摄像机位于立方体中)。为了防止这种情况的发生,需要将摄像机稍微向外移动一些。
5、 渲染场景
1 | function animate() { |
在这里我们创建了一个循环——这使得渲染器能够在每次屏幕刷新时对场景进行绘制(在大多数屏幕上,刷新率一般是60次/秒)。
requestAnimationFrame函数就是让浏览器去执行一次参数中的函数,这样通过上面render中调用requestAnimationFrame()函数,requestAnimationFrame()函数又让rander()再执行一次,就形成了我们通常所说的游戏循环了。
6、使立方体动起来
在animate()函数中添加
1 | cube.rotation.x += 0.01; |
这一段代码将在每一帧时被渲染时调用(正常情况下是60次/秒),这就让立方体有了一个看起来很不错的旋转动画。
除了改变立方体的旋转角度、位置,也可以通过改变相机位置角度达到同样动起来的效果。
完整代码(附详细备注)
1 | <html> |
在浏览器中的效果:
二、实际应用篇:跳一跳(You_Jump_I_Jump)
有了基本概念后,我们来一步步实现跳一跳的代码复原,GitHub地址:https://github.com/zj19941113/You_Jump_I_Jump
最终效果图:
1、创建场景与第一个盒子
(1)基本元素
场景:设置背景颜色
1 | scene = new THREE.Scene(); |
渲染器:渲染空间尺寸设置为屏幕的宽高
1 | renderer = new THREE.WebGLRenderer({ antialias: true } ); |
相机:选择正交投影相机,设置相机位置与朝向
1 | camera = new THREE.OrthographicCamera( window.innerWidth / - 2, window.innerWidth / 2, window.innerHeight / 2, window.innerHeight / - 2, -1000, 2000 ); |
光源:添加平行光与环境光,平行光让几何体更层次分明,环境光提升整体亮度
1 | light = new THREE.AmbientLight( 0xFFFFFF,0.4 ); |
环境光 函数构造:AmbientLight( color : Integer, intensity : Float )
color - (参数可选)颜色的rgb数值。缺省值为 0xffffff(白色)。
intensity - (参数可选)光照的强度。缺省值为 1。
参考:https://threejs.org/docs/index.html#api/zh/lights/AmbientLight
平行光 函数构造:DirectionalLight( color : Integer, intensity : Float )
参考:https://threejs.org/docs/index.html#api/zh/lights/DirectionalLight
(2)创建地面与盒子
1 | ground = creatGround(0,0,0x8797a4) |
函数 creatGround(),创建5000*5000大小,颜色为#8797a4的地面
1
2
3
4
5
6
7
8
9 function creatGround(x,z,color){
var geometry = new THREE.PlaneGeometry( 5000, 5000, 1, 1 );
var material = new THREE.MeshLambertMaterial({ color:color});
mesh = new THREE.Mesh( geometry,material );
mesh.rotation.x = -Math.PI / 2;
mesh.position.set(x,-0.01,z);
scene.add(mesh);
return mesh;
}
函数 creatcube01(),创建一个其中一面有纹理的盒子
1 | function creatcube01(x,z) { |
效果:
因为之后要创建各种盒子,所以这里用了函数,方便之后调用。用画布绘制右侧面的纹理,创建橙色的纯色盒子,将纹理贴在平面上覆盖在盒子侧面,最后再创建阴影,同样是创建平面贴上阴影图片作为纹理。
画布作为纹理:
1
2
3
4
5
6
7
8
9
10var canvas = document.createElement('canvas');
canvas.width=100;
canvas.height=50;
var ctx = canvas.getContext('2d');
// 画布的绘制
// ……
// 画布的绘制
var texture = new THREE.Texture(canvas);
var material = new THREE.MeshLambertMaterial({map:texture});
texture.needsUpdate = true;
png图片作为纹理:
1
2
3 var texture = new THREE.TextureLoader().load( "source/shadow.png" );
var material = new THREE.MeshBasicMaterial({map:texture});
material.transparent = true; // 材质透明
注:尽量重用geometry,material,使性能优化。
(3)窗口自适应
1 | window.addEventListener( 'resize', onWindowResize, false ); |
当窗口大小改变时,触发函数 onWindowResize(),实时改变相机参数。
1 | function onWindowResize() { |
效果:
完整代码:
1 | <!DOCTYPE html> |
2、更多盒子的生成
所有盒子的生成函数,见 https://github.com/zj19941113/You_Jump_I_Jump/blob/master/zjFirstStep.html
boxs大合照:
3、性能与调试
创建stats对象进行性能监控
帧数:图形处理器每秒钟能够刷新几次,通常用fps(Frames Per Second)来表示。帧数越高,画面的感觉就会越好。所以大多数游戏都会有超过30的FPS。我们设置性能监视器来监视FPS。
(1)引入Stats.js文件,官方文档:https://github.com/mrdoob/stats.js
1 | <script src="js/Stats.js"></script> |
(2)将stats对象加入到html网页中
1 | var stats; |
1 | stats = new Stats(); |
(3)在 animate() 中调用stats.update()统计时间和帧数
1 | function animate() { |
其中FPS表示:上一秒的帧数,这个值越大越好,一般都为60左右。点击后变成另一个视图。MS表示渲染一帧需要的毫秒数,这个数字是越小越好,再次点击又可以回到FPS视图中。
效果:
OrbitControls控制器辅助调试
(1)引入controls/OrbitControls.js文件,官方文档:https://github.com/mrdoob/three.js/blob/017f2a9eb17820772359b1e1dbca2b626c9f32b1/examples/jsm/controls/OrbitControls.js
1 | <script src="js/controls/OrbitControls.js"></script> |
(2)controls控制器设置
1 | var controls; |
1 | controls = new THREE.OrbitControls( camera, renderer.domElement ); |
(3)在 animate() 中调用controls.update()
1 | function animate() { |
OrbitControls控制器的作用是,鼠标左键进行视角的旋转,右键控制平移,滚轮控制缩放。
效果:
完整代码:
1 | <!DOCTYPE html> |
有效利用Controls和Helper能使视图展示更加出色,从而方便代码的编写。
这里有官方提供的一些实例(包括模型加载、控制器、动画等相关内容):
https://github.com/mrdoob/three.js/tree/017f2a9eb17820772359b1e1dbca2b626c9f32b1/examples
下一篇:Three.js+tween.js 基础(二) 将介绍tween.js 相关知识,完成player的跳动动画,盒子的随机生成,分数统计等功能。