Three.js是一个很流行的3D JavaScript库。这里有一个three.js的入门教程,在浏览器窗口中画出星空。我按照教程重新实现了一遍,这里的这篇博客把教程大致翻译了一遍。我的demo。
变量
定义全局变量:
1 2 3 4 5 6 7 8 9 10 11
| var camera, scene, renderer,
mouseX = 0, mouseY = 0,
particles = [];
init();
|
初始化three.js
为了使用three.js,我们需要在init()
函数中设置三个主要的对象:
- scene(场景): 场景中包含了所有的3D对象数据
- camera(相机):
相机有位置(position),旋转(rotation)和视野属性(field of view)
- renderer(渲染器):
决定场景中的一个物体在照相机的视角看来是什么样子
照相机(Camera)
1 2 3 4 5 6
| function init() { camera = new THREE.PerspectiveCamera(80, window.innerWidth/window.innerHeight, 1, 4000);
camera.position.z = 1000;
|
Camera
构造器的第一个参数是视野(field of
view)。这是一个角度,越大,则表示虚拟的相机镜片越宽。
第二个参数是输出的宽和高之比。这个值必须与CanvasRenderer相一致。
相机只能看见一定范围之内的物体,这个范围是由near和far来确定的,在这里分别为1和4000。因而任何比1近的物体或者比4000远的物体是不会被渲染的。
在默认情况下相机位于3D世界的起始位置(origin)0,0,0(我的上一篇博客用CSS3绘制一个旋转的立方体中有关于origin的介绍)。但是你创建的3D物体也会放置在这一点,因而默认值用处并不大。我们需要将相机向后移动一点,即给其一个正的z值(由屏幕内指向外侧)。在这里将其移动1000。
场景(Scene)
1 2 3
| scene = new THREE.Scene(); scene.add(camera);
|
注意必须将相机加入到场景中。
渲染器(Renderer)
1 2 3 4 5 6
| renderer = new THREE.CanvasRenderer(); renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
|
这里的CanvasRenderer创建了它自己的DOM元素,这是一个普通的2D
canvas对象,我们需要把它加入到文件的body部分才能看见它。我们想让它充满整个浏览器窗口,所以将它的大小设置为window.innerWidth
和window.innerHeight
。
渲染循环
接下来我们需要做的是产生粒子,加入鼠标移动监听器(mousemove
listener)来追踪鼠标位置,最后设定间隔每秒调用update
函数30次。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
| makeParticles();
document.addEventListener('mousemove', onMouseMove, false);
setInterval(update, 1000/30);
其中的`update`函数如下:
function update() { updateParticles(); renderer.render(scene, camera); } ```
`updateParticles`函数会在后面加以解释,它的作用是将粒子向前移动。
直到`renderer.render()`方法调用之前,你是不会看见任何3D物体的。渲染器(renderer)会把所有的东西画到canvas上,它决定了场景中的物体在相机的视角看来是什么样子的。
## 粒子(Particles)
Three.js有三种主要类型的3D对象:三角形(triangles),直线(lines)和粒子(particles)。粒子表示的是3D空间中的一个点,因而最容易使用。它们可以被渲染成2D的图片,比如一个简单的圆或矩形,或是位图图片。关于粒子有一点很重要,它们从任何角度看起来都是一样的,当然根据距离的远近大小会发生变化。
## 创建粒子 ```javascript function makeParticles() { var particle, material; for (var zpos = -1000; zpos < 1000; zpos += 20) {
material = new THREE.ParticleCanvasMaterial( { color: getRandomColor(), program: particleRender });
particle = new THREE.Particle(material); particle.position.x = Math.random() * 1000 - 500; particle.position.y = Math.random() * 1000 - 500; particle.position.z = zpos; particle.scale.x = particle.scale.y = 10; scene.add(particle);
particles.push(particle); } }
|
在for循环中zpos
以20为步长从-1000增加至1000。
在循环中,我们创建一个新的材质(material)然后新建一个粒子。粒子有一个position属性,它有x,
y, z三个值。
我们给每一个粒子一个随机的x和y位置,将它的z位置设置为zpos
。
接着将粒子加入到particles数组中,保证能够跟踪所有的粒子并在update循环中对它们进行操作。
创建粒子材质(particle
material)
所有的3D对象都有材质对象,材质定义了它们是如何画出来的,颜色及透明度之类的属性。我们是这样定义的每个粒子的材质对象:
1 2 3 4
| material = new THREE.ParticleCanvasMaterial( { color: 0xffffff, program: particleRender });
|
three.js并没有内置圆形粒子材质,所以需要告诉它如何去画一个圆。我们是通过给particleRender
传递必要的canvas绘图API来做到这一点的。
1 2 3 4 5
| function particleRender(context) { context.beginPath(); context.arc(0, 0, 1, 0, 2*Math.PI, true); context.fill(); }
|
把一个函数传递给材质(material)似乎有点奇怪,但这实际上是一个非常灵活的系统。它获得了canvas上下文的引用,所以我们可以画出任何想要的形状。同时canvas的坐标系统将会根据粒子进行缩放和平移,因此我们只需要以起点(origin)为中心画图即可。
对于粒子的颜色,可以选取一个固定的颜色,也可以选取随机的颜色。
1 2 3 4 5 6 7
| function getRandomColor() { var r = 255*Math.random()|0, g = 255*Math.random()|0, b = 255*Math.random()|0; return '0x' + parseInt(r, 16) + parseInt(g, 16) + parseInt( b, 16); }
|
移动粒子
现在来看一下updateParticles
函数,它将会在我们每个的更新周期中调用,就在我们进行渲染之前。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| function updateParticles() { for (var i = 0; i < particles.length; i++) { particle = particles[i];
particle.position.z += mouseY * 0.1;
if (particle.position.z > 1000) particle.position.z -= 2000; } }
|
鼠标越低,mouseY值越大,粒子移动速度越快。
最后的效果如图,上下移动鼠标,粒子移动速度会发生变化。