Three.js進階篇之5 - 粒子系統
Three.js是一個偉大的開源WebGL庫,WebGL允許JavaScript操作GPU,在瀏覽器端實現真正意義的3D。但是目前這項技術還處在發展階段,資料極為匱乏,愛好者學習基本要通過Demo原始碼和Three.js本身的原始碼來學習。
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.小結
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中加入粒子效果了。我希望你能用得順手,就跟前面一樣!
相關文章
- Three.js開發指南(7):粒子和粒子系統JS
- Three.js進階篇之6 - 碰撞檢測JS
- Three.js進階篇之7 - 3D宇宙特效JS3D特效
- Three.js進階篇之9 - 紋理對映和UV對映JS
- Android粒子篇之文字的粒子化運動Android
- JUnit5學習之八:綜合進階(終篇)
- 測開之函式進階· 第5篇《偏函式》函式
- 前端內功修煉:5大主流佈局系統進階,系統進階佈局技術前端
- Asp.NetCore之AutoMapper進階篇ASP.NETNetCoreAPP
- WebGL three.js學習筆記 使用粒子系統模擬時空隧道(蟲洞)WebJS筆記
- Three.js 進階之旅:頁面平滑滾動-王國之淚 ?JS
- Android粒子篇之Bitmap畫素級操作Android
- Java多執行緒之進階篇Java執行緒
- Linux ACL 許可權之進階篇Linux
- 認證系統之登入認證系統的進階使用 (二)
- Java進階篇 設計模式之十四 ----- 總結篇Java設計模式
- 分散式系統訊息中介軟體——RabbitMQ的使用進階篇分散式MQ
- Three.js 進階之旅:新春特典-Rabbit craft go ?JSRaftGo
- Three.js入門篇之1 - WebGL on HTMLJSWebHTML
- 網管平臺(進階篇):網管系統的管理與維護
- Three.js 進階之旅:物理效果-碰撞和聲音 ?JS
- OpenGL Shader例項,OpenGL 粒子系統
- 【webpack 系列】進階篇Web
- React進階篇2React
- React進階篇1React
- Three.js 進階之旅:全景漫遊-高階版線上看房 ?JS
- Three.js 進階之旅:全景漫遊-初階移動相機版JS
- vue2進階篇:vue-router之命名路由Vue路由
- 【進階篇】Redis實戰之Jedis使用技巧詳解Redis
- Java進階篇之十五 ----- JDK1.8的Lambda、StreJavaJDK
- 測開之函式進階· 第6篇《閉包》函式
- python入門與進階篇(七)之原生爬蟲Python爬蟲
- 無線多作業系統啟動之uInitrd階段NFS掛載篇作業系統UINFS
- Simpleperf分析之Android系統篇Android
- AE 3D粒子系統外掛3D
- Unity 2018.2之粒子Unity
- 《MySQL 進階篇》二十:鎖MySql
- 樹莓派-進階篇樹莓派