Three.js入門——畫星空(star field)


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值越大,粒子移動速度越快。

最后的效果如圖,上下移動鼠標,粒子移動速度會發生變化。

原文鏈接:http://www.wukai.me/2015/11/15/star-field/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM