粒⼦模擬是計算機圖形技術的可視化圖形效果。典型的效果有:落葉,⽕焰,爆炸,流星,雲等等。它不同於其它圖形渲染, 粒⼦是基於模糊來渲染。它的結果在基於像素下是不可預測的。粒⼦系統的參數描述了隨機模擬的邊界。傳統的渲染技術實現粒⼦渲染效果很困難。有⼀個好消息是你可以使⽤QML元素與粒⼦系統交互。同時參數也可以看做是屬性,這些參數可以使⽤傳統的動畫技術來實現動態效果。
概念(Concept)
粒⼦模擬的核⼼是粒⼦系統(ParticleSystem),它控制了共享時間線。⼀個場景下可以有多個粒⼦系統,每個都有⾃⼰獨⽴的時間線。⼀個粒⼦使⽤發射器元素(Emitter)發射,使⽤粒⼦畫筆(ParticlePainter)實現可視化, 它可以是⼀張圖⽚,⼀個QML項或者⼀個着⾊項(shader item)。⼀個發射器元素( Emitter) 也提供向量來控制粒⼦⽅向。 ⼀個粒⼦被發送后就再也⽆法控制。 粒⼦模型提供粒⼦控制器( Affector) , 它可以控制已發射粒⼦的參數。
在⼀個系統中, 粒⼦可以使⽤粒⼦群元素( ParticleGroup) 來共享移動時間。 默認下, 每個例⼦都屬於空( “”) 組。
- 粒⼦系統(ParticleSystem) - 管理發射器之間的共享時間線。
- 發射器(Emitter) - 向系統中發射邏輯粒⼦。
- 粒⼦畫筆(ParticlePainter) - 實現粒⼦可視化。
- ⽅向(Direction) - 已發射粒⼦的向量空間。
- 粒⼦組(ParticleGroup) - 每個粒⼦是⼀個粒⼦組的成員。
- 粒⼦控制器( Affector) - 控制已發射粒⼦。
簡單的模擬( Simple Simulation)
讓我們從⼀個簡單的模擬開始學習。Qt Quick使⽤簡單的粒⼦渲染⾮常簡單。下⾯是我們需要的:
- 綁定所有元素到⼀個模擬的粒⼦系統( ParticleSystem) 。
- ⼀個向系統發射粒⼦的發射器( Emitter) 。
- ⼀個ParticlePainter派⽣元素, ⽤來實現粒⼦的可視化。
importQtQuick2.6
importQtQuick.Window2.2
importQtQuick.Particles2.0
Window{
visible:true;
id: root;
width:480;
height:160;
color:"#1f1f1f";
ParticleSystem{
id: particleSystem;
}
Emitter{
id: emitter;
anchors.centerIn: parent;
width:160;
height:80;
system: particleSystem;
emitRate:10;//每S發送10個粒子
lifeSpan:2000;//每個粒子生命周期為1000ms
lifeSpanVariation:500;//一個已發射粒子的生命周期變化是500ms
size:16;//一個粒子開始的大小是16像素
endSize:32;//生命周期結束時的大小是32個像素( endSize:32)
// Tracer {colro: "green"};
}
ImageParticle{
source:"/blur.png";
system: particleSystem;
}
}
運⾏結果如下所⽰:
我們使⽤⼀個480x160的矩形框作為我們的根元素和背景。 然后我們定義⼀個粒⼦系統(ParticleSystem)。這通常是粒⼦系統綁定所有元素的第⼀步。 下⼀個元素是發射器( Emitter),它定義了基於矩形框的發射區域和發射粒⼦的基礎屬性。發射器使⽤system屬性與粒⼦系統進⾏綁定。
在這個例⼦中,發射器每秒發射10個粒⼦( emitRate:10) 到發射器的區域,每個粒⼦的⽣命周期是1000毫秒( lifeSpan:1000) , ⼀個已發射粒⼦的⽣命周期變化是500毫秒( lifeSpanVariation:500) 。 ⼀個粒⼦開始的⼤⼩是16個像素( size:16) , ⽣命周期結束時的⼤⼩是32個像素( endSize:32) 。
發射器發射邏輯粒⼦。⼀個邏輯粒⼦的可視化使⽤粒⼦畫筆( ParticlePainter) 來實現, 在這個例⼦中我們使⽤了圖像粒⼦( ImageParticle),使⽤⼀個圖⽚鏈接作為源屬性。
圖像粒⼦也有其它的屬性⽤來控制粒⼦的外觀。
- 發射頻率( emitRate) - 每秒粒⼦發射數( 默認為10個) 。
- ⽣命周期( lifeSpan) - 粒⼦持續時間( 單位毫秒, 默認為1000毫秒) 。
- 初始⼤⼩( size),結束⼤⼩( endSize)- 粒⼦在它的⽣命周期的開始和結束時的⼤⼩( 默認為16像素)。
粒⼦參數( Particle Parameters)
我們已經知道通過改變發射器的⾏為就可以改變我們的粒⼦模擬。粒⼦畫筆被⽤來繪制每⼀個粒⼦。 回到我們之前的粒⼦中, 我們更新⼀下我們的圖⽚粒⼦畫筆( ImageParticle)。⾸先我們改變粒⼦圖⽚為⼀個⼩的星形圖⽚:
粒⼦使⽤⾦⾊來進⾏初始化, 不同的粒⼦顏⾊變化范圍為+/- 20%。
color:'#FFD700'
colorVariation:0.2
為了讓場景更加⽣動, 我們需要旋轉粒⼦。 每個粒⼦⾸先按順時針旋轉15度, 不同的粒⼦在+/-5度之間變化。 每個例⼦會不斷的以每秒45度旋轉。每個粒⼦的旋轉速度在+/-15度之間變化:
rotation:15
rotationVariation:5
rotationVelocity:45
rotationVelocityVariation:15
最后, 我們改變粒⼦的⼊場效果。 這個效果是粒⼦產⽣時的效果, 在這個例⼦中, 我們希望使⽤⼀個縮放效果:
entryEffect: ImageParticle.Scale
現在我們可以看到旋轉的星星出現在我們的屏幕上。
代碼:
importQtQuick2.6
importQtQuick.Window2.2
importQtQuick.Particles2.0
Window{
visible:true;
id: root;
width:480;
height:160;
color:"black";
ParticleSystem{
id: particleSystem;
}
Emitter{
id: emitter;
anchors.centerIn: parent;
width:160;
height:80;
system: particleSystem;
emitRate:10;//每S發送10個粒子
lifeSpan:1000;//每個粒子生命周期為1000ms
lifeSpanVariation:500;//一個已發射粒子的生命周期變化是500ms
size:16;//一個粒子開始的大小是16像素
endSize:32;//生命周期結束時的大小是32個像素( endSize:32)
// Tracer {colro: "green"};
}
ImageParticle{
source:"/start.bmp";
color:"#ffd700";
colorVariation:0.2
rotation:15
rotationVariation:5
rotationVelocity:45
rotationVelocityVariation:15
entryEffect:ImageParticle.Scale
system: particleSystem;
}
}
粒⼦⽅向( Directed Particle)
我們已經看到了粒⼦的旋轉, 但是我們的粒⼦需要⼀個軌跡。 軌跡由速度或者粒⼦隨機⽅向的加速度指定, 也可以叫做⽮量空間。
有多種可⽤⽮量空間⽤來定義粒⼦的速度或加速度:
- ⾓度⽅向( AngleDirection) - 使⽤⾓度的⽅向變化。
- 點⽅向( PointDirection) - 使⽤x,y組件組成的⽅向變化。
- 目標⽅向( TargetDirection) - 朝着目標點的⽅向變化。
讓我們在場景下試着⽤速度⽅向將粒⼦從左邊移動到右邊。
⾸先使⽤⾓度⽅向( AngleDirection) 。 我們使⽤AngleDirection元素作為我們的發射器( Emitter) 的速度屬性。
velocity:AngleDirection{}
粒⼦的發射將會使⽤指定的⾓度屬性。 ⾓度值在0到360度之間, 0度代表指向右邊。 在我們的例⼦中, 例⼦將會移動到右邊, 所以0度已經指向右邊⽅向。 粒⼦的⾓度變化在+/-15度之間:
velocity:AngleDirection{
angle:0
angleVariation:15
}
現在我們已經設置了⽅向, 下⾯是指定粒⼦的速度。 它由⼀個梯度值定義,這個梯度值定義了每秒像素的變化。 正如我們設置⼤約640像素, 梯度值為100, 看起來是⼀個不錯的值。 這意味着平均⼀個6.4秒⽣命周期的粒⼦可以穿越我們看到的區域。 為了讓粒⼦的穿越看起來更加有趣, 我們使⽤magnitudeVariation來設置梯度值的變化, 這個值是我們的梯度值的⼀半:
velocity:AngleDirection{
...
magnitude:100
magnitudeVariation:50
}
粒⼦畫筆( Particle Painter)
粒⼦控制( Affecting Particles)
粒⼦組( Particle Group)
總結( Summary)
未完待續。。。。。