[譯] THREE.JS入門教程-4.創建粒子系統


譯序

Three.js是一個偉大的開源WebGL庫,WebGL允許JavaScript操作GPU,在瀏覽器端實現真正意義的3D。但是目前這項技術還處在發展階段,資料極為匱乏,愛好者學習基本要通過Demo源碼和Three.js本身的源碼來學習。

國外網站 aerotwist.com 有六篇較為簡單的入門教程,我嘗試着將其翻譯過來,與大家分享。  

0.簡介

嗨,又見面了。這么說我們已經開始學習Three.js了,如果你還沒有看過之前三篇教程,建議你先讀完。如果你已經讀完前面的教程了,你可能會想做一些關於粒子的東西。讓我們直面這個話題吧,每個人都愛粒子效果。不管你是否知道,你可以很輕易地創建它們。

1.創建一個粒子系統

Three.js將粒子系統視為一個基本的幾何體,因為它就像基本幾何體一樣,即有形狀,又有位置、縮放因子、旋轉屬性。粒子系統將geometry對象里的每一個點視為一個單獨的粒子。為什么這樣做?我想基於以下的原因:首先,整個粒子系統地繪制只需要調用一次某個繪制函數,而不是調用上千次;其次,這允許你設定一些全局的參數來影響你的粒子系統內的所有粒子。

即使是粒子系統被視為一個整體的對象,我們仍然可以為每個粒子單獨地着色,因為在繪制粒子系統的過程中,Three.js通過attribute變量colour向着色器傳遞了每一個頂點的顏色。我在本篇教程里並不准備這樣做,如果你想知道這是怎樣完成的,你可以去GitHub上看Three.js的例程。

粒子系統可能還有一種特殊效果需要引起你的注意:Three.js在粒子系統第一次被渲染的時候,會將其數據緩存下來,之后你無法增加或減少系統中的粒子。如果你不希望看到某個粒子,你可以將它的顏色中的alpha值設置為0,但你無法刪除它。所以你應當在創建粒子系統的時候,就將所有可能需要顯示的粒子考慮進來。

開始創建一個粒子系統,只需要這么多:

// 創建粒子geometry
var particleCount = 1800,
    particles = new THREE.Geometry(),
    pMaterial =
      new THREE.ParticleBasicMaterial({
        color: 0xFFFFFF,
        size: 20
      });
// 依次創建單個粒子
for(var p = 0; p < particleCount; p++) {
  // 粒子范圍在-250到250之間
  var pX = Math.random() * 500 - 250,
      pY = Math.random() * 500 - 250,
      pZ = Math.random() * 500 - 250,
      particle = new THREE.Vertex(
        new THREE.Vector3(pX, pY, pZ)
      );
  // 將粒子加入粒子geometry
  particles.vertices.push(particle);
}
// 創建粒子系統
var particleSystem =
  new THREE.ParticleSystem(
    particles,
    pMaterial);
// 將粒子系統加入場景
scene.addChild(particleSystem); 

如果你運行:

  1. 你會發現粒子都是方的
  2. 粒子都不動

我們一個一個來修復。

2.風格

我們創建一個粒子基本材質時傳入了顏色和尺寸。我們可能想做的是傳入一張紋理圖片用來顯示粒子,而這樣就可以很好地控制粒子看上去的樣式了。

你也看到,粒子是以方塊形狀繪制的,所以我們也應當使用一張方形的紋理圖片。為了看上去效果更好,我還會使用加法混合,但是這樣做必須保證紋理圖片的背景是黑色的而不是透明的。我理解的原因是:現在加法混合和透明材質之間不兼容。但是沒關系,最后看上去會很棒。

我們來更新一下粒子基本材質和粒子系統,加入一些加法混合下透明的粒子。如果你喜歡,你也可以用我的粒子圖片。

// 創建粒子基本材質
var pMaterial =
  new THREE.ParticleBasicMaterial({
    color: 0xFFFFFF,
    size: 20,
    map: THREE.ImageUtils.loadTexture(
      "images/particle.png"
    ),
    blending: THREE.AdditiveBlending,
    transparent: true
  });
// 允許粒子系統對粒子排序,以達到我們想要的效果
particleSystem.sortParticles = true;

這看上去已經好多了。現在來引入一點物理,讓粒子們動起來。

3.引入物理

默認情況下,粒子系統在三維空間中不運動,這很好。但我想讓他們動起來,而且我要讓粒子系統這樣運動:讓粒子繞着y軸旋轉。而且粒子在每個軸的范圍都在-250到250之間,所以繞着y軸旋轉以為這它們繞着系統地中心旋轉。

我還假定,你已經在某個地方有了幀循環的代碼,和我在上一篇關於着色器中的教程中類似。所以這里我們只需這樣:

// 幀循環
function update() {
  // 增加一點旋轉量
  particleSystem.rotation.y += 0.01;
  // 繪制粒子系統
  renderer.render(scene, camera);
  // 設置下一次刷新幀時對update的調用
  requestAnimFrame(update);
} 

現在我們開始定義單個粒子的運動(譯者注:之前的旋轉是整個粒子系統的運動)。我們來做個簡單的雨點效果,這包含一下幾步:

  1. 給每一個粒子賦一個初始為0的速度
  2. 在每一幀中,為每一個粒子賦一個隨機的重力加速度
  3. 在每一幀中,通過通過加速度更新速度,通過速度更新位置
  4. 當一個粒子運動出了視線,重新設置初始位置和速度

聽上去很多,其實代碼寫起來很少。首先,在創建粒子的過程中,我們為每個粒子增加一個水平速度:

// 為每個粒子創建一個水平運動速度
particle.velocity = new THREE.Vector3(
  0, // x
  -Math.random(), // y: 隨機數
  0); // z 

接下來,在幀緩沖中我們傳遞每個粒子,並且,當粒子離開屏幕底部需要重置時,重置其位置和速度。

// 幀循環
function update() {
  // 增加旋轉量
  particleSystem.rotation.y += 0.01;
  var pCount = particleCount;
  while(pCount--) {
    // 獲取單個粒子
    var particle = particles.vertices[pCount];
    // 檢查是否需要重置
    if(particle.position.y < -200) {
      particle.position.y = 200;
      particle.velocity.y = 0;
    }
    // 用隨機數更新水平速度分量,並根據速度更新位置
    particle.velocity.y -= Math.random() * .1;
    particle.position.addSelf(
      particle.velocity);
  }
  // 告訴粒子系統我們改變了粒子位置
  particleSystem.geometry.__dirtyVertices = true;
  //
  renderer.render(scene, camera);
  // 設置下一次調用
  requestAnimFrame(update);
} 

看看效果(譯者注:原網站好像出問題了,我這里看不到)

雖然不夠震撼,但這個粒子至少展示了如何做。你完全應該自己創建一些美妙的粒子效果,然后讓我知道。

這里有個警告你應該知道,在幀循環中,我越雷池了:我在一次循環中遍歷了所有粒子,這實際上是種很粗放的方式。如果你的幀循環中做了太多的工作(譯者注:注意幀循環的js代碼是在cpu中運行的,它不像gpu,能一下子並發出成千上萬個簡單進程),瀏覽器就會卡頓,事實上如果你用了requestAnimationFrame,它視圖每秒刷新60次。所以還是優化你的代碼,在幀循環中做盡量少的事情。

4.小結

粒子效果太棒了,是個人都愛粒子效果,而現在你知道如何在Three.js中加入粒子效果了。我希望你能用得順手,就跟前面一樣!

同樣,這里有源碼下載,而且,讓我知道你喜歡它!


免責聲明!

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



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