THREE.JS入門教程(4)創(chuàng)建粒子系統(tǒng)
更新時(shí)間:2013年01月24日 11:00:57 作者:
Three.js是一個(gè)偉大的開(kāi)源WebGL庫(kù),WebGL允許JavaScript操作GPU,在瀏覽器端實(shí)現(xiàn)真正意義的3D本文將介紹創(chuàng)建一個(gè)粒子系統(tǒng)/風(fēng)格/引入物理等等,感興趣的朋友可以了解下哦,希望本文對(duì)你有所幫助
譯序
Three.js是一個(gè)偉大的開(kāi)源WebGL庫(kù),WebGL允許JavaScript操作GPU,在瀏覽器端實(shí)現(xiàn)真正意義的3D。但是目前這項(xiàng)技術(shù)還處在發(fā)展階段,資料極為匱乏,愛(ài)好者學(xué)習(xí)基本要通過(guò)Demo源碼和Three.js本身的源碼來(lái)學(xué)習(xí)。
0.簡(jiǎn)介
嗨,又見(jiàn)面了。這么說(shuō)我們已經(jīng)開(kāi)始學(xué)習(xí)Three.js了,如果你還沒(méi)有看過(guò)之前三篇教程,建議你先讀完。如果你已經(jīng)讀完前面的教程了,你可能會(huì)想做一些關(guān)于粒子的東西。讓我們直面這個(gè)話題吧,每個(gè)人都愛(ài)粒子效果。不管你是否知道,你可以很輕易地創(chuàng)建它們。
1.創(chuàng)建一個(gè)粒子系統(tǒng)
Three.js將粒子系統(tǒng)視為一個(gè)基本的幾何體,因?yàn)樗拖窕編缀误w一樣,即有形狀,又有位置、縮放因子、旋轉(zhuǎn)屬性。粒子系統(tǒng)將geometry對(duì)象里的每一個(gè)點(diǎn)視為一個(gè)單獨(dú)的粒子。為什么這樣做?我想基于以下的原因:首先,整個(gè)粒子系統(tǒng)地繪制只需要調(diào)用一次某個(gè)繪制函數(shù),而不是調(diào)用上千次;其次,這允許你設(shè)定一些全局的參數(shù)來(lái)影響你的粒子系統(tǒng)內(nèi)的所有粒子。
即使是粒子系統(tǒng)被視為一個(gè)整體的對(duì)象,我們?nèi)匀豢梢詾槊總€(gè)粒子單獨(dú)地著色,因?yàn)樵诶L制粒子系統(tǒng)的過(guò)程中,Three.js通過(guò)attribute變量colour向著色器傳遞了每一個(gè)頂點(diǎn)的顏色。我在本篇教程里并不準(zhǔn)備這樣做,如果你想知道這是怎樣完成的,你可以去GitHub上看Three.js的例程。
粒子系統(tǒng)可能還有一種特殊效果需要引起你的注意:Three.js在粒子系統(tǒng)第一次被渲染的時(shí)候,會(huì)將其數(shù)據(jù)緩存下來(lái),之后你無(wú)法增加或減少系統(tǒng)中的粒子。如果你不希望看到某個(gè)粒子,你可以將它的顏色中的alpha值設(shè)置為0,但你無(wú)法刪除它。所以你應(yīng)當(dāng)在創(chuàng)建粒子系統(tǒng)的時(shí)候,就將所有可能需要顯示的粒子考慮進(jìn)來(lái)。
開(kāi)始創(chuàng)建一個(gè)粒子系統(tǒng),只需要這么多:
// 創(chuàng)建粒子geometry
var particleCount = 1800,
particles = new THREE.Geometry(),
pMaterial =
new THREE.ParticleBasicMaterial({
color: 0xFFFFFF,
size: 20
});
// 依次創(chuàng)建單個(gè)粒子
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);
}
// 創(chuàng)建粒子系統(tǒng)
var particleSystem =
new THREE.ParticleSystem(
particles,
pMaterial);
// 將粒子系統(tǒng)加入場(chǎng)景
scene.addChild(particleSystem);
如果你運(yùn)行:
1.你會(huì)發(fā)現(xiàn)粒子都是方的
2.粒子都不動(dòng)
我們一個(gè)一個(gè)來(lái)修復(fù)。
2.風(fēng)格
我們創(chuàng)建一個(gè)粒子基本材質(zhì)時(shí)傳入了顏色和尺寸。我們可能想做的是傳入一張紋理圖片用來(lái)顯示粒子,而這樣就可以很好地控制粒子看上去的樣式了。
你也看到,粒子是以方塊形狀繪制的,所以我們也應(yīng)當(dāng)使用一張方形的紋理圖片。為了看上去效果更好,我還會(huì)使用加法混合,但是這樣做必須保證紋理圖片的背景是黑色的而不是透明的。我理解的原因是:現(xiàn)在加法混合和透明材質(zhì)之間不兼容。但是沒(méi)關(guān)系,最后看上去會(huì)很棒。
我們來(lái)更新一下粒子基本材質(zhì)和粒子系統(tǒng),加入一些加法混合下透明的粒子。如果你喜歡,你也可以用我的粒子圖片。
// 創(chuàng)建粒子基本材質(zhì)
var pMaterial =
new THREE.ParticleBasicMaterial({
color: 0xFFFFFF,
size: 20,
map: THREE.ImageUtils.loadTexture(
"images/particle.png"
),
blending: THREE.AdditiveBlending,
transparent: true
});
// 允許粒子系統(tǒng)對(duì)粒子排序,以達(dá)到我們想要的效果
particleSystem.sortParticles = true;
這看上去已經(jīng)好多了?,F(xiàn)在來(lái)引入一點(diǎn)物理,讓粒子們動(dòng)起來(lái)。
3.引入物理
默認(rèn)情況下,粒子系統(tǒng)在三維空間中不運(yùn)動(dòng),這很好。但我想讓他們動(dòng)起來(lái),而且我要讓粒子系統(tǒng)這樣運(yùn)動(dòng):讓粒子繞著y軸旋轉(zhuǎn)。而且粒子在每個(gè)軸的范圍都在-250到250之間,所以繞著y軸旋轉(zhuǎn)以為這它們繞著系統(tǒng)地中心旋轉(zhuǎn)。
我還假定,你已經(jīng)在某個(gè)地方有了幀循環(huán)的代碼,和我在上一篇關(guān)于著色器中的教程中類似。所以這里我們只需這樣:
// 幀循環(huán)
function update() {
// 增加一點(diǎn)旋轉(zhuǎn)量
particleSystem.rotation.y += 0.01;
// 繪制粒子系統(tǒng)
renderer.render(scene, camera);
// 設(shè)置下一次刷新幀時(shí)對(duì)update的調(diào)用
requestAnimFrame(update);
}
現(xiàn)在我們開(kāi)始定義單個(gè)粒子的運(yùn)動(dòng)(譯者注:之前的旋轉(zhuǎn)是整個(gè)粒子系統(tǒng)的運(yùn)動(dòng))。我們來(lái)做個(gè)簡(jiǎn)單的雨點(diǎn)效果,這包含一下幾步:
1.給每一個(gè)粒子賦一個(gè)初始為0的速度
2.在每一幀中,為每一個(gè)粒子賦一個(gè)隨機(jī)的重力加速度
3.在每一幀中,通過(guò)通過(guò)加速度更新速度,通過(guò)速度更新位置
4.當(dāng)一個(gè)粒子運(yùn)動(dòng)出了視線,重新設(shè)置初始位置和速度
聽(tīng)上去很多,其實(shí)代碼寫起來(lái)很少。首先,在創(chuàng)建粒子的過(guò)程中,我們?yōu)槊總€(gè)粒子增加一個(gè)水平速度:
// 為每個(gè)粒子創(chuàng)建一個(gè)水平運(yùn)動(dòng)速度
particle.velocity = new THREE.Vector3(
0, // x
-Math.random(), // y: 隨機(jī)數(shù)
0); // z
接下來(lái),在幀緩沖中我們傳遞每個(gè)粒子,并且,當(dāng)粒子離開(kāi)屏幕底部需要重置時(shí),重置其位置和速度。
// 幀循環(huán)
function update() {
// 增加旋轉(zhuǎn)量
particleSystem.rotation.y += 0.01;
var pCount = particleCount;
while(pCount--) {
// 獲取單個(gè)粒子
var particle = particles.vertices[pCount];
// 檢查是否需要重置
if(particle.position.y < -200) {
particle.position.y = 200;
particle.velocity.y = 0;
}
// 用隨機(jī)數(shù)更新水平速度分量,并根據(jù)速度更新位置
particle.velocity.y -= Math.random() * .1;
particle.position.addSelf(
particle.velocity);
}
// 告訴粒子系統(tǒng)我們改變了粒子位置
particleSystem.geometry.__dirtyVertices = true;
// 畫
renderer.render(scene, camera);
// 設(shè)置下一次調(diào)用
requestAnimFrame(update);
}
雖然不夠震撼,但這個(gè)粒子至少展示了如何做。你完全應(yīng)該自己創(chuàng)建一些美妙的粒子效果,然后讓我知道。
這里有個(gè)警告你應(yīng)該知道,在幀循環(huán)中,我越雷池了:我在一次循環(huán)中遍歷了所有粒子,這實(shí)際上是種很粗放的方式。如果你的幀循環(huán)中做了太多的工作(譯者注:注意幀循環(huán)的js代碼是在cpu中運(yùn)行的,它不像gpu,能一下子并發(fā)出成千上萬(wàn)個(gè)簡(jiǎn)單進(jìn)程),瀏覽器就會(huì)卡頓,事實(shí)上如果你用了requestAnimationFrame,它視圖每秒刷新60次。所以還是優(yōu)化你的代碼,在幀循環(huán)中做盡量少的事情。
4.小結(jié)
粒子效果太棒了,是個(gè)人都愛(ài)粒子效果,而現(xiàn)在你知道如何在Three.js中加入粒子效果了。我希望你能用得順手,就跟前面一樣!
同樣,這里有源碼下載,而且,讓我知道你喜歡它!
Three.js是一個(gè)偉大的開(kāi)源WebGL庫(kù),WebGL允許JavaScript操作GPU,在瀏覽器端實(shí)現(xiàn)真正意義的3D。但是目前這項(xiàng)技術(shù)還處在發(fā)展階段,資料極為匱乏,愛(ài)好者學(xué)習(xí)基本要通過(guò)Demo源碼和Three.js本身的源碼來(lái)學(xué)習(xí)。
0.簡(jiǎn)介
嗨,又見(jiàn)面了。這么說(shuō)我們已經(jīng)開(kāi)始學(xué)習(xí)Three.js了,如果你還沒(méi)有看過(guò)之前三篇教程,建議你先讀完。如果你已經(jīng)讀完前面的教程了,你可能會(huì)想做一些關(guān)于粒子的東西。讓我們直面這個(gè)話題吧,每個(gè)人都愛(ài)粒子效果。不管你是否知道,你可以很輕易地創(chuàng)建它們。
1.創(chuàng)建一個(gè)粒子系統(tǒng)
Three.js將粒子系統(tǒng)視為一個(gè)基本的幾何體,因?yàn)樗拖窕編缀误w一樣,即有形狀,又有位置、縮放因子、旋轉(zhuǎn)屬性。粒子系統(tǒng)將geometry對(duì)象里的每一個(gè)點(diǎn)視為一個(gè)單獨(dú)的粒子。為什么這樣做?我想基于以下的原因:首先,整個(gè)粒子系統(tǒng)地繪制只需要調(diào)用一次某個(gè)繪制函數(shù),而不是調(diào)用上千次;其次,這允許你設(shè)定一些全局的參數(shù)來(lái)影響你的粒子系統(tǒng)內(nèi)的所有粒子。
即使是粒子系統(tǒng)被視為一個(gè)整體的對(duì)象,我們?nèi)匀豢梢詾槊總€(gè)粒子單獨(dú)地著色,因?yàn)樵诶L制粒子系統(tǒng)的過(guò)程中,Three.js通過(guò)attribute變量colour向著色器傳遞了每一個(gè)頂點(diǎn)的顏色。我在本篇教程里并不準(zhǔn)備這樣做,如果你想知道這是怎樣完成的,你可以去GitHub上看Three.js的例程。
粒子系統(tǒng)可能還有一種特殊效果需要引起你的注意:Three.js在粒子系統(tǒng)第一次被渲染的時(shí)候,會(huì)將其數(shù)據(jù)緩存下來(lái),之后你無(wú)法增加或減少系統(tǒng)中的粒子。如果你不希望看到某個(gè)粒子,你可以將它的顏色中的alpha值設(shè)置為0,但你無(wú)法刪除它。所以你應(yīng)當(dāng)在創(chuàng)建粒子系統(tǒng)的時(shí)候,就將所有可能需要顯示的粒子考慮進(jìn)來(lái)。
開(kāi)始創(chuàng)建一個(gè)粒子系統(tǒng),只需要這么多:
復(fù)制代碼 代碼如下:
// 創(chuàng)建粒子geometry
var particleCount = 1800,
particles = new THREE.Geometry(),
pMaterial =
new THREE.ParticleBasicMaterial({
color: 0xFFFFFF,
size: 20
});
// 依次創(chuàng)建單個(gè)粒子
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);
}
// 創(chuàng)建粒子系統(tǒng)
var particleSystem =
new THREE.ParticleSystem(
particles,
pMaterial);
// 將粒子系統(tǒng)加入場(chǎng)景
scene.addChild(particleSystem);
如果你運(yùn)行:
1.你會(huì)發(fā)現(xiàn)粒子都是方的
2.粒子都不動(dòng)
我們一個(gè)一個(gè)來(lái)修復(fù)。
2.風(fēng)格
我們創(chuàng)建一個(gè)粒子基本材質(zhì)時(shí)傳入了顏色和尺寸。我們可能想做的是傳入一張紋理圖片用來(lái)顯示粒子,而這樣就可以很好地控制粒子看上去的樣式了。
你也看到,粒子是以方塊形狀繪制的,所以我們也應(yīng)當(dāng)使用一張方形的紋理圖片。為了看上去效果更好,我還會(huì)使用加法混合,但是這樣做必須保證紋理圖片的背景是黑色的而不是透明的。我理解的原因是:現(xiàn)在加法混合和透明材質(zhì)之間不兼容。但是沒(méi)關(guān)系,最后看上去會(huì)很棒。
我們來(lái)更新一下粒子基本材質(zhì)和粒子系統(tǒng),加入一些加法混合下透明的粒子。如果你喜歡,你也可以用我的粒子圖片。
復(fù)制代碼 代碼如下:
// 創(chuàng)建粒子基本材質(zhì)
var pMaterial =
new THREE.ParticleBasicMaterial({
color: 0xFFFFFF,
size: 20,
map: THREE.ImageUtils.loadTexture(
"images/particle.png"
),
blending: THREE.AdditiveBlending,
transparent: true
});
// 允許粒子系統(tǒng)對(duì)粒子排序,以達(dá)到我們想要的效果
particleSystem.sortParticles = true;
這看上去已經(jīng)好多了?,F(xiàn)在來(lái)引入一點(diǎn)物理,讓粒子們動(dòng)起來(lái)。
3.引入物理
默認(rèn)情況下,粒子系統(tǒng)在三維空間中不運(yùn)動(dòng),這很好。但我想讓他們動(dòng)起來(lái),而且我要讓粒子系統(tǒng)這樣運(yùn)動(dòng):讓粒子繞著y軸旋轉(zhuǎn)。而且粒子在每個(gè)軸的范圍都在-250到250之間,所以繞著y軸旋轉(zhuǎn)以為這它們繞著系統(tǒng)地中心旋轉(zhuǎn)。
我還假定,你已經(jīng)在某個(gè)地方有了幀循環(huán)的代碼,和我在上一篇關(guān)于著色器中的教程中類似。所以這里我們只需這樣:
復(fù)制代碼 代碼如下:
// 幀循環(huán)
function update() {
// 增加一點(diǎn)旋轉(zhuǎn)量
particleSystem.rotation.y += 0.01;
// 繪制粒子系統(tǒng)
renderer.render(scene, camera);
// 設(shè)置下一次刷新幀時(shí)對(duì)update的調(diào)用
requestAnimFrame(update);
}
現(xiàn)在我們開(kāi)始定義單個(gè)粒子的運(yùn)動(dòng)(譯者注:之前的旋轉(zhuǎn)是整個(gè)粒子系統(tǒng)的運(yùn)動(dòng))。我們來(lái)做個(gè)簡(jiǎn)單的雨點(diǎn)效果,這包含一下幾步:
1.給每一個(gè)粒子賦一個(gè)初始為0的速度
2.在每一幀中,為每一個(gè)粒子賦一個(gè)隨機(jī)的重力加速度
3.在每一幀中,通過(guò)通過(guò)加速度更新速度,通過(guò)速度更新位置
4.當(dāng)一個(gè)粒子運(yùn)動(dòng)出了視線,重新設(shè)置初始位置和速度
聽(tīng)上去很多,其實(shí)代碼寫起來(lái)很少。首先,在創(chuàng)建粒子的過(guò)程中,我們?yōu)槊總€(gè)粒子增加一個(gè)水平速度:
復(fù)制代碼 代碼如下:
// 為每個(gè)粒子創(chuàng)建一個(gè)水平運(yùn)動(dòng)速度
particle.velocity = new THREE.Vector3(
0, // x
-Math.random(), // y: 隨機(jī)數(shù)
0); // z
接下來(lái),在幀緩沖中我們傳遞每個(gè)粒子,并且,當(dāng)粒子離開(kāi)屏幕底部需要重置時(shí),重置其位置和速度。
復(fù)制代碼 代碼如下:
// 幀循環(huán)
function update() {
// 增加旋轉(zhuǎn)量
particleSystem.rotation.y += 0.01;
var pCount = particleCount;
while(pCount--) {
// 獲取單個(gè)粒子
var particle = particles.vertices[pCount];
// 檢查是否需要重置
if(particle.position.y < -200) {
particle.position.y = 200;
particle.velocity.y = 0;
}
// 用隨機(jī)數(shù)更新水平速度分量,并根據(jù)速度更新位置
particle.velocity.y -= Math.random() * .1;
particle.position.addSelf(
particle.velocity);
}
// 告訴粒子系統(tǒng)我們改變了粒子位置
particleSystem.geometry.__dirtyVertices = true;
// 畫
renderer.render(scene, camera);
// 設(shè)置下一次調(diào)用
requestAnimFrame(update);
}
雖然不夠震撼,但這個(gè)粒子至少展示了如何做。你完全應(yīng)該自己創(chuàng)建一些美妙的粒子效果,然后讓我知道。
這里有個(gè)警告你應(yīng)該知道,在幀循環(huán)中,我越雷池了:我在一次循環(huán)中遍歷了所有粒子,這實(shí)際上是種很粗放的方式。如果你的幀循環(huán)中做了太多的工作(譯者注:注意幀循環(huán)的js代碼是在cpu中運(yùn)行的,它不像gpu,能一下子并發(fā)出成千上萬(wàn)個(gè)簡(jiǎn)單進(jìn)程),瀏覽器就會(huì)卡頓,事實(shí)上如果你用了requestAnimationFrame,它視圖每秒刷新60次。所以還是優(yōu)化你的代碼,在幀循環(huán)中做盡量少的事情。
4.小結(jié)
粒子效果太棒了,是個(gè)人都愛(ài)粒子效果,而現(xiàn)在你知道如何在Three.js中加入粒子效果了。我希望你能用得順手,就跟前面一樣!
同樣,這里有源碼下載,而且,讓我知道你喜歡它!
您可能感興趣的文章:
- 使用3D引擎threeJS實(shí)現(xiàn)星空粒子移動(dòng)效果
- 原生JS+HTML5實(shí)現(xiàn)跟隨鼠標(biāo)一起流動(dòng)的粒子動(dòng)畫效果
- 基于Particles.js制作超炫粒子動(dòng)態(tài)背景效果(仿知乎)
- 用JavaScript玩轉(zhuǎn)游戲物理(一)運(yùn)動(dòng)學(xué)模擬與粒子系統(tǒng)
- Canvas + JavaScript 制作圖片粒子效果
- javascript轉(zhuǎn)換靜態(tài)圖片,增加粒子動(dòng)畫效果
- JS庫(kù)particles.js創(chuàng)建超炫背景粒子插件(附源碼下載)
- 基于three.js實(shí)現(xiàn)的3D粒子動(dòng)效實(shí)例代碼
- JavaScript實(shí)現(xiàn)鼠標(biāo)移動(dòng)粒子跟隨效果
- js canvas實(shí)現(xiàn)隨機(jī)粒子特效
相關(guān)文章
在JavaScript應(yīng)用中使用RequireJS來(lái)實(shí)現(xiàn)延遲加載
這篇文章主要介紹了在JavaScript應(yīng)用中使用RequireJS來(lái)實(shí)現(xiàn)延遲加載,JavaScript是一款人氣JS庫(kù),需要的朋友可以參考下2015-07-07JavaScript Math.ceil 方法(對(duì)數(shù)值向上取整)
js Math.ceil用于對(duì)數(shù)值向上取整,即得到大于或等于該數(shù)值的最小整數(shù),需要的朋友可以參考下2015-01-01javascript開(kāi)發(fā)技術(shù)大全-第1章javascript概述
JavaScript 為 HTML 設(shè)計(jì)師提供了一種編程工具HTML 創(chuàng)作者往往都不是程序員,但是 JavaScript 卻是一種只擁有極其簡(jiǎn)單的語(yǔ)法的腳本語(yǔ)言!幾乎每個(gè)人都有能力將短小的代碼片斷放入他們的 HTML 頁(yè)面當(dāng)中。2011-07-07JavaScript 遞增、遞減運(yùn)算符實(shí)例
遞增、遞減運(yùn)算符實(shí)例,基礎(chǔ)Js代碼范例,新手可參考哦。2010-07-07用meta實(shí)現(xiàn)的頁(yè)面跳轉(zhuǎn)代碼
用meta實(shí)現(xiàn)的頁(yè)面跳轉(zhuǎn)代碼,建議與js一起使用,防止頁(yè)面假死或不支持js的情況,都可以實(shí)現(xiàn)效果。2007-09-09在瀏覽器中打開(kāi)或關(guān)閉JavaScript的方法
這篇文章主要介紹了在瀏覽器中打開(kāi)或關(guān)閉JavaScript的方法,由于歷史遺留問(wèn)題,JS在目前任何瀏覽器中都是標(biāo)配...所以不想加載JS也可以選擇關(guān)閉,需要的朋友可以參考下2015-06-06菜鳥(niǎo)javascript基礎(chǔ)資料整理2
JavaScript 對(duì)象,這里涉及到變量與數(shù)組等的使用。2010-12-12