パーティクルを放出させる
旅行から帰ってきましたので、ようやっと更新することができました。まだまだ飽きてはいませんよ。
前回はエミッタを放出させるところまで行ったので、今回はパーティクルを等速で放出させるところまでやっていきます。
今回のソースは以下。相変わらず_gl.pdeは変わっていないので省略。新しくparticle.pdeを加えました。
Particle3.pde(draw()の関数だけ変更されているので、その部分だけ記載。)
void draw(){
background( 0.0 );
perspective( PI/3.0, (float)width/(float)height, 1, 5000 );
gl.glDepthMask(false);
gl.glEnable( GL.GL_BLEND );
gl.glBlendFunc( GL.GL_SRC_ALPHA, GL.GL_ONE );
pgl.beginGL();
emitter.exist();
pgl.endGL();
if( mousePressed ){
emitter.addParticles(20);
}
}
emitter.pde
class Emitter {
Vec3D loc;
Vec3D vel;
Vec3D velToMouse;
color myColor;
ArrayList particles;
Emitter(){
loc = new Vec3D();
vel = new Vec3D();
velToMouse = new Vec3D();
myColor = color( 1, 1, 1 );
particles = new ArrayList();
}
void exist(){
setVelToMouse();
findVelocity();
setPosition();
//rendering Emitter
gl.glEnable( GL.GL_TEXTURE_2D ); //Enable texture mapping
iterateListExist();
render();
gl.glDisable( GL.GL_TEXTURE_2D );
}
void setVelToMouse(){
velToMouse.set( mouseX - loc.x, mouseY - loc.y, 0 );
}
void findVelocity(){
vel.interpolateToSelf( velToMouse, 0.2 );
}
void setPosition(){
loc.addSelf( vel );
}
void iterateListExist(){
pgl.bindTexture( particleImg );
for( Iterator it = particles.iterator(); it.hasNext(); ){
Particle p = (Particle)it.next();
if(!p.ISDEAD){
p.exist();
} else {
it.remove();
}
}
}
void render(){
pgl.bindTexture( emitterImg );
renderImage( loc, 200, myColor, 1.0 );
}
void addParticles( int _amt ){
for( int i=0; i<_amt; i++ ){
particles.add( new Particle( loc, vel) );
}
}
}
particle.pde
class Particle {
int len;
Vec3D[] loc;
Vec3D startLoc;
Vec3D vel;
float radius;
float age;
int lifeSpan;
float agePer;
boolean ISDEAD;
Particle( Vec3D _loc, Vec3D _vel ){
radius = random( 20, 60 );
len = (int)radius;
loc = new Vec3D[len];
startLoc = new Vec3D( _loc.add( new Vec3D().randomVector().scaleSelf( random(5.0) ) ) );
for( int i=0; i
loc[i] = new Vec3D( startLoc );
}
vel = new Vec3D( _vel.scale( 0.5 ).addSelf( new Vec3D().randomVector().scaleSelf( random( 10.0 ) ) ) );
age = 0;
lifeSpan = (int)radius;
agePer = 1.0;
}
void exist(){
setPosition();
render();
setAge();
}
void setPosition(){
for ( int i=len-1; i>0; i-- ){
loc[i].set(loc[i-1]);
}
loc[0].addSelf( vel );
}
void render(){
color c = color( agePer, agePer*0.75, 1.0 - agePer );
renderImage( loc[0], radius*agePer, c, 1.0 );
}
void setAge(){
age++;
if( age > lifeSpan ){
ISDEAD = true;
}else{
agePer = 1.0 - age/(float)lifeSpan;
}
}
}
emitter.pdeの中で特に注目すべきなのは、iterateListExist()の追加。これによって各パーティクルのレンダリング処理を行い、死んだパーティクルをリストから除外している。
particle.pde の中で特によくわかんなかったのが、loc[]の存在について。別に1個だけでいいじゃんと思っていたが、これは後に尻尾というか、パーティクルの軌跡を描画するために使うようだ。loc[0]に一番最新のパーティクルの位置が格納されていて、時が経つごとに順次入れ替えを行っている。
次によくわかんないというか、感覚的じゃないなと思ったのが、new Vec3D( _loc.add( new Vec3D().randomVector().scaleSelf( random(5.0) ) ) )などのベクトル処理。
randomVector() はベクトルをランダムな単位ベクトルに変更するメソッドで、いろいろと便利。scaleSelf()は文字通り、ベクトルを拡大したり縮小したりするメソッド。この返り値を_locベクトルに加算させていることは理解できるのだが、いかんせん感覚的じゃないのが困り者。vec1+vec2とか出来れば理解しやすいのにとか思うけど、javaは演算子のオーバーロードをサポートしていないから仕様がないのか。