2023年9月19日火曜日

Particle2 炎

前回パーティクルの仕組みを作ったので今回はその続き

前回からの課題は、パーティクルを追加とともにシェーダ作成も行っていたので、当たり前なんだけどシェーダ作成は切り離すことにした。


パーティクルシェーダ登録


これまでのシェーダは基本的には固定で、決められたデータを追加するとそれに応じて描画されていた。
パーティクル用のシェーダはそれぞれがカスタムシェーダで、パーティクルの種類毎にシェーダが増えていくことになる。
システムから渡される固定のリソースは、カメラ、パーティクルオブジェクトのWorldマトリックス、時間。
これに加えて前回は入れてなかったカラー、ID、インデックスも追加した。

オプションでサンプラ、テクスチャ、ピクセルシェーダソースを指定できるようにした。



炎のエフェクト


パーティクルの仕組みが出来たので、なにか作ってみようと思う。
定番の炎にチャレンジする。

よく見るのが、ノイズのテクスチャを用意してUVスクロールさせるというもの。

まず、セルラーノイズを動的に作成してテクスチャとして登録する。
パーティクルは適当に散らばせて、上昇させる。
表面にノイズテクスチャを貼り付けるとこんな感じ。

シェーダ

Out.Col = Tex.Sample( Sampler, ( In.UV * 0.5f )) ;


テクスチャを貼り付けただけ


全部同じ見た目になってるので、ランダムにテクスチャの表示位置をずらして、タイマーでUVスクロールをする。
distanceを使って、円形にくり抜く。

シェーダ

float d = 1 - distance( float2( 0.5, 0.5 ), In.UV ) ;
float2 r = rand( In.ID * 0.0001 ) ;
Out.Col = Tex.Sample( Sampler, ( In.UV * 0.5f ) + r + float2( 0.0f, Param.Time*0.3 )) ;
Out.Col.a *= step( 0.5, d ) * d ;


丸くなった


登録時に色をランダムに設定する。(赤は192~255、緑は96~159、青は64~95)
また、更新タイミングで全体を減らしていく。
アルファは時間により255~0にする。
Emissiveにも同じように書き込む。

シェーダ

float d = 1 - distance( float2( 0.5, 0.5 ), In.UV ) ;
float2 r = rand( In.ID * 0.0001 ) ;
float c = Tex.Sample( Sampler, In.UV * 0.5f + r + float2( 0.0f, Param.Time*0.3 )).r ;
Out.Col = In.Col * step( 0.5, c ) * c ;
Out.Col.a *= step( 0.5, d ) * d ;
Out.Emissive = Out.Col ;


それっぽくなった


ランダムのパラメータにIDを指定しているが、これをインデックスにすることにより、別のオブジェクトが消えたときにインデックスがずれて、テクスチャの表示する場所がワープすることにより、メラメラ感が増す。

シェーダ

float d = 1 - distance( float2( 0.5, 0.5 ), In.UV ) ;
float2 r = rand( In.Idx * 0.0001 ) ;
float c = Tex.Sample( Sampler, In.UV * 0.5f + r + float2( 0.0f, Param.Time*0.3 )).r ;
Out.Col = In.Col * step( 0.5, c ) * c ;
Out.Col.a *= step( 0.5, d ) * d ;
Out.Emissive = Out.Col ;

メラメラ増し


パフォーマンス


調子に乗って連打しまくっていると、FPSがどんどん落ちて30台まで落ちた。
5000パーティクルぐらいでこれだと、先が辛そう。

1パーティクルに1スレッドをその場で生成してそれぞれ更新処理を任せてみたけど、1スレッドだけで処理したほうが速かった。
パーティクル専用スレッドを1つ用意して、処理対象を2つに分けてメインスレッドと分担するようにしてみたら、多少マシになった。
試しにリリースビルドでやってみたら60FPSから落ちることもなく、シングルスレッドでも60FPS維持してた。速くなることは確認できてるので、パーティクル専用スレッドはそのまま採用することにする。


まとめ


初めてエフェクト作ってみたけど、意外とすごいのが出来た。
エフェクトは1つだけでなく、複数のエフェクトを重ねて1つのエフェクトを作ってるみたいで、例えば今回の炎にしても、別途煙を炎の消えたあたりからモクモク出すといいらしい。


0 件のコメント:

コメントを投稿