Three.js入門——畫星空(star field)
http://www.wukai.me/2015/11/15/star-field/
Three.js是一個很流行的3D JavaScript庫。這裡有一個three.js的入門教程,在瀏覽器視窗中畫出星空。我按照教程重新實現了一遍,這裡的這篇部落格把教程大致翻譯了一遍。我的demo。
變數
定義全域性變數:
1 2 3 4 5 6 7 8 9 10 11 |
// 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)
1 2 3 4 5 6 |
function init() { // 照相機引數 camera = new THREE.PerspectiveCamera(80, window.innerWidth/window |
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 |
// the scene contains all the 3D object data scene = new THREE.Scene(); scene.add(camera); |
注意必須將相機加入到場景中。
渲染器(Renderer)
1 2 3 4 5 6 |
// 加入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次。
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(); // 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的圖片,比如一個簡單的圓或矩形,或是點陣圖圖片。關於粒子有一點很重要,它們從任何角度看起來都是一樣的,當然根據距離的遠近大小會發生變化。 ## 建立粒子 ```javascript // 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物件都有材質物件,材質定義了它們是如何畫出來的,顏色及透明度之類的屬性。我們是這樣定義的每個粒子的材質物件:
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 |
|