Nvidia Flexの水をカスタマイズしたときの最適化に関するメモ
z軸固定
全パーティクルについてfor分を回して、GetVelocity
SetVelocity
は重い。
全パーティクルは3000程度いくのできっつい。
新しくループを作るのではなく、もとのNvidiaを書き換える事で対応。
→ 書き換えたのは、新規に生成された水粒子に関してのみだったのでダメだった。
新規の水粒子以外でSetVelocity
が呼ばれているのは、ApplyImpulse
とTeleportParticles
だが、DebugLogしてもどちらも呼び出されていないようだった。
しかし、CustomWater.cs
内のOnFlexUpdate
でGetVelocity
するとzの値が0ではなくなっている。
つまりSetVelocity
以外の部分でVelocityの変化が起きていることになる。
原因を探ったがよく分からず(ネイティブプラグイン内かも)、その過程でSetVelocities
関数を発見した。
SetVelocity
をfor分で回すより効率が良いと考え、利用してみた。
var velocities = new Vector3[indices.Length]; particleData.GetVelocities(indices[0], indices.Length, velocities); for(var i = 0; i < velocities.Length; i++) velocities[i].z = 0; particleData.SetVelocities(indices[0], indices.Length, velocities);
結果、ほぼ無視できるレベルに軽量化に成功した。
が、代わりにとんでもないGCが発生した。
原因はGetVelocitiesの時のnew Vector3[]
だろう。
ちなみに、SetVelocity
を使った場合との比較は↓である。
手法 | Total | GC |
---|---|---|
SetVelocity |
2.90ms (7.6%) | 29.5kB |
SetVelocities |
0.03ms (0.1%) | 約60kB (スパイク時:117.7kB) |
SetVelocities
を使う場合はindices
はスタートだけあればよいので、
int[] indices = new int[instance.numParticles];
→ int[] indices = new int[1];
に変える事でnew
を減らすことに成功。
GCを60kB → 44kB (スパイク時:88kB)まで減らした。
ここでのスパイクはFixedUpdate
が1フレーム内で2回呼ばれた時の話だと考えられる。
さらに、_velocities
をクラス変数にして初期化する事でnew
を呼ぶ回数は最初の初期化時に限定。
結果、GCを44kB → 0.072kB (72B) に減らすことに成功!
private Vector3[] _velocities; private void Start(){ _velocities = new Vector3[_flexActor.asset.maxParticles]; } private void OnFlexUpdate(FlexContainer.ParticleData particleData){ particleData.GetVelocities(indices[0], instance.numParticles, _velocities); for(var i = 0; i < _velocities.Length; i++) _velocities[i].z = 0; particleData.SetVelocities(indices[0], instance.numParticles, _velocities); }
これにて、Z軸固定は完了した。
当たり判定及びAddForce
上記同様に、GetVelocities
及び GetParticles
による軽量化を行った。
さらに、IsInCollider(Vector3 pos)
内の targetCollider.ClosestPoint(pos)
が非常に重い。
これは水粒子がコライダー内部にあるかの判定に利用していた。
そこで、コライダーをSphereColliderに限定して、水粒子のコライダー内部判定を(particle - colPos).magnitude < radius
で置き換えた。
汎用性は下がるが、単純なVector3の演算のみになる。
実際にこれでかなりの軽量化に成功した。
しかしながら、magnitude
の計算等でそれなりに処理時間を要していた。
そこで今回はz軸方向を利用しないという点を活かして、Vector3
の演算からVector2
の演算に変更を行った。
これでさらに若干軽くなった。
手法 | Total | GC |
---|---|---|
WaterCollider |
22.50ms (37.0%) | 67.4kB |
WaterSphereCollider |
1.70ms (6.6%) | 36B |