Three.js是一個很流行的3D JavaScript庫。這里有一個three.js的入門教程,在瀏覽器窗口中畫出星空。我按照教程重新實現了一遍,這里的這篇博客把教程大致翻譯了一遍。我的demo。
變量
定義全局變量:
// three.js的主要部分
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)
``` 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)
``` // the scene contains all the 3D object data scene = new THREE.Scene(); scene.add(camera); 注意必須將相機加入到場景中。 ```渲染器(Renderer)
``` // 加入CanvasRenderer,由渲染器決定場景中的物體看起來如何,並將其畫出 renderer = new THREE.CanvasRenderer(); renderer.setSize(window.innerWidth, window.innerHeight); // 將渲染器的canvas domElement加入到body中 document.body.appendChild(renderer.domElement); ```這里的CanvasRenderer創建了它自己的DOM元素,這是一個普通的2D canvas對象,我們需要把它加入到文件的body部分才能看見它。我們想讓它充滿整個瀏覽器窗口,所以將它的大小設置為window.innerWidth和window.innerHeight。
渲染循環
接下來我們需要做的是產生粒子,加入鼠標移動監聽器(mousemove listener)來追蹤鼠標位置,最后設定間隔每秒調用update函數30次。
makeParticles();
// add the mouse move listener
document.addEventListener('mousemove', onMouseMove, false);
// 每秒渲染30次
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的圖片,比如一個簡單的圓或矩形,或是位圖圖片。關於粒子有一點很重要,它們從任何角度看起來都是一樣的,當然根據距離的遠近大小會發生變化。
創建粒子
// creates a random field of Particle object
function makeParticles() {
var particle, material;
// 將z坐標從-1000(最遠處)逐步增加至1000(相機所在處)
// 每一個位置加入一個隨機的粒子
for (var zpos = -1000; zpos < 1000; zpos += 20) {
// 創建一個粒子材質,向其傳入顏色及我們定義的粒子渲染函數
material = new THREE.ParticleCanvasMaterial( {
// color: 0xffffff,
color: getRandomColor(),
program: particleRender
});
// 創建粒子
particle = new THREE.Particle(material);
// 賦給它一個位於-500至500之間的隨機x和y值
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數組中
particles.push(particle);
}
}
在for循環中zpos以20為步長從-1000增加至1000。
在循環中,我們創建一個新的材質(material)然后新建一個粒子。粒子有一個position屬性,它有x, y, z三個值。
我們給每一個粒子一個隨機的x和y位置,將它的z位置設置為zpos。
接着將粒子加入到particles數組中,保證能夠跟蹤所有的粒子並在update循環中對它們進行操作。
創建粒子材質(particle material)
所有的3D對象都有材質對象,材質定義了它們是如何畫出來的,顏色及透明度之類的屬性。我們是這樣定義的每個粒子的材質對象:
material = new THREE.ParticleCanvasMaterial( {
color: 0xffffff,
program: particleRender
});
three.js並沒有內置圓形粒子材質,所以需要告訴它如何去畫一個圓。我們是通過給particleRender傳遞必要的canvas繪圖API來做到這一點的。
function particleRender(context) {
context.beginPath();
context.arc(0, 0, 1, 0, 2*Math.PI, true);
context.fill();
}
把一個函數傳遞給材質(material)似乎有點奇怪,但這實際上是一個非常靈活的系統。它獲得了canvas上下文的引用,所以我們可以畫出任何想要的形狀。同時canvas的坐標系統將會根據粒子進行縮放和平移,因此我們只需要以起點(origin)為中心畫圖即可。
對於粒子的顏色,可以選取一個固定的顏色,也可以選取隨機的顏色。
function getRandomColor() {
var r = 255*Math.random()|0,
g = 255*Math.random()|0,
b = 255*Math.random()|0;
// return 'rgb(' + r + ',' + g + ',' + b + ')';
return '0x' + parseInt(r, 16) + parseInt(g, 16) + parseInt( b, 16);
}
移動粒子
現在來看一下updateParticles函數,它將會在我們每個的更新周期中調用,就在我們進行渲染之前。
// 根據鼠標位置移動所有的粒子
function updateParticles() {
// 對每個粒子進行迭代處理
for (var i = 0; i < particles.length; i++) {
particle = particles[i];
// 根據mouseY值進行移動
particle.position.z += mouseY * 0.1;
// 如果粒子過近,將其移至后面
if (particle.position.z > 1000)
particle.position.z -= 2000;
}
}
鼠標越低,mouseY值越大,粒子移動速度越快。
最后的效果如圖,上下移動鼠標,粒子移動速度會發生變化。