PostProcessing V2効果が異常になる

今回の主な話題：スマホで異常に表示されたPostProcessing V2のbloom効果を解決する方法、Lua GCとC# GCの非同期をバランスさせる方法、WebGLがリリースされた後のメモリ変更、重力下での弾道をシミュレートする方法、UI要素のバッチ処理に関する注意事項。

---
###PostProcessing
Q1: スマホでPostProcessing V2のbloom効果の表示が異常になります。
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/207e745f-0f29-1eea-33f9-0be979f54173.png)

①
>
不正な値があります。自有のNaN機能でチェックすることをお勧めします。これは主に、特殊効果またはGGX、Specなどの0で割ったことが原因です。
>
PS：NaN機能は、Porcine parvovirus 2 (PPV2)のlayerスクリプトにNaNピクセルをチェックするオプションのようです。実際、ほとんどのSpec値は大きすぎますから、自分でmax関数を使用してコントロールすることができます。

②
>
私たちのプロジェクトでも同じ状況が発生しました。HDRを使用しまして、一部のシェーダーではこの問題が発生しました。
>
解決策は、最初にbloomのclampを比較的小さい値に設定し、2以下をお勧めします。それでも問題が解決しない場合は、問題のあるシェーダーを具体的に確認し、fixとhalfをfloatに変更します。これにより、ほとんどの問題を解決できます。

③
>
問題主からの補充：NaNの自己検査をする後に黒い点があります。最後に、PBRのShaderに問題があることが判明しました。

---
###Lua
Q2: プロジェクトでxLuaを使用すると、問題があります。あるUI（文字が多くと再現しやすい）が開き、廃棄され、再び開き、そして再び廃棄されます…何度も繰り返します。Monoが成長し続け、C# GCを行っても完全にGCできません。
そして、１つ低下できる方法を見つけました。
LuaをGCした後に、C#をGCしたら、Monoは少し戻ります（ただし、元の状態には戻りません）。この問題は、両者が回収のためにカウントを引用しますが、両方が同期されていないことです。オブジェクトをDestroyしたけど、LuaにはまだGCされていませんので、Luaに引用されているオブジェクトなどもまだ引用されています。
そして、GCを両側で数回行ったり来たりすると、基本的に元のMono値に返すことができます。

インターネットで類似な問題を見たことがありましたが、ToLuaに関するものです。この中にいくつの方案が提出され、２つの変更を行いました。
A、Lua GCの頻度を少し上げてみます。
B、そして、xLua自体も引用を消しるLuaEnv.Tick()関数（引用されたC#オブジェクトが廃棄されたかどうかをゆっくりとトラバース検出します。廃棄された場合にnullにします。引用を解けられ、後にGCさせられます。）を提供します。そして毎回トラバースの回数を増やします。しかし、まだ増長があります。みんながこの問題をどうやって解決しますかを知りたいです。感謝します。
（UIをキャッシュプールにすれば比較的に良いですが、Monoを拡大しやすく、問題を引き起こす可能性はまだあります。）

PS：まだ辛いことがあります。LuaとC#のリークは、当時のどこが原因を分かりにくいです。必ず短時間内でいくつの簡単な操作を繰り返して、大体何かリークしたことを推測でき、そして対応する場所で問題を見つけられます。どのLuaの所がどのC#を適用するか、またはC#がLuaのどの所を見つける便利な方法はありますか？
たとえば、いくつかの両方引用があり、GCできません。どことどこが引用しているとこだけを推測できます。
>問題主がLuaとC#メモリを非常に深く理解しています。私たちも同じ問題がありますが、１つ目の処理だけを行いました。
>
Lua GCの2つのパラメーターを調整して、Luaゴミの回収をより積極的にさせます。この問題の原因は、Luaは小さなUser dataが代表するものがC#世界に占める重さを感じできないことです。基盤が間違っており、頻度を上げることしかできません。パラメータが合理的でコストも大きくない限り、これは最も簡単で効果的な方法です。
>
Monoを拡大する問題について、私たちにもあるはずですが、まだこの部分に進めていません。現在、正常に操作すればMonoのピーク値は20MBぐらいで、納得できます。
>
LuaがC#を引用することについて、Luaにはインデックスを取得するだけです。オブジェクトの実際の持有はObjectPoolを通じて実現します。そしてObjectPoolに対して操作します。2つのステップに分けることができます。
>
1、コールスタックを記録する
C#スタックは、StackTraceUtility.ExtractStackTrace()を介して取得できます。
Luaスタックは、DoString(“return debug.traceback()”)を介して取得できます。
これらの2つの文字列をobjと一緒にObjectPoolに記録できます。こうすると、どのobjがリークしているかがわかっている限り、それがどこで引入されたかがわかります。
>
2、割り当て番号を記録する
どのobjがリークしたかを確認するために、objがプールに入るときに割り当て番号を指定できます。この割り当て番号は自動的に増加し続き、これによりdiffをマークできます。
たとえば、ある瞬間にAをマークしました、当時の割り当て番号は100であり、そして別の瞬間でBをマークし、この時の割り当て番号は150であります。そしてさまざまなGCがリリースし、プールをトラバースして100と150の間にあるobjを見つけます。この部分のobjの存続状況が予期を満たしているかどうかを分析します。満たしていない場合は、2つのスタックを印刷します。真実は明らかです。
>
C#がLuaを引用することに関しては、この部分はそんなに危険ではないはずです。私たちはLuaBehaviourの外部使用を禁止させ、破壊したときに制御します。これ以外、Delegateも適切な制御が必要で、他には一時的に思い出していません。

---
###WebGL
Q3: 下図のように、現在のメモリ使用量は843MBであり、非アクティブ期間を過ごしと、メモリ使用量は150MBに低下します。機能はブラウジングのみで、800MBを占有する場合の流暢さは150MBを占有する場合とまったく同じです。誰かが原因を教えてください！
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/6c02da08-747a-9630-a642-e9080e335d9b.png)
>前にWebGLをやりましたが、問題主のような問題が存在するかどうかを気づいてしませんでした。当時に使用したデバッグブラウザはChromeでありました。
ブラウザには通常、開発者ツールが搭載されており、パフォーマンス分析を実行してメモリ使用量を確認できます。例としてChromeを取り上げます。
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/87bccca6-c97e-8974-014f-427fce3a5f74.png)
![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/ec2def3d-8987-bd5c-494d-67e2c809efb3.png)
リリースしたゲームのメモリ占用または各部分のメモリ占有比率を確認することができます。遭ったことはありませんので、できることはアイデアを簡単に話すことだけで、問題主に役立つかどうもわかりません。
まず、他のブラウザでリリースして状況を確認し、一般的な問題かどうかを判断する必要があると思います。
>
共通している場合は、最も完全な分析ツールを備えたブラウザを見つけて、メモリが割り当てられているどちらと低下する時メモリがリリースされたどちらを確認して問題を確定します。
Firefoxブラウザーにのみ表示される場合は、最初にブラウザー自体にサポート問題が存在するかどうか、またはゲーム自体に問題があるかどうかを判断する必要があります（一部のブラウザーはサポートしていませんが、一部のブラウザーのサポートに問題があります）。
>
別の簡単なゲームをリリースして、問題があるかどうかを確認します。問題がある場合は、Unityのバージョンを変更してテストをリリースします。空きプロジェクトなどの簡単なシーンでも問題が存在する場合は、基本的にブラウザのサポートに問題があります。そうでない場合は、ツールを使用してメモリのロケーション問題を分析し、問題の解決を試みてください。

---
###物理
Q4: FPSゲームで、弾丸にRigidbodyを使用する以外に、重力下での弾道をシミュレートするための何かより効率的な方法ありませんか？たとえば、Raycastを使用する場合に、実現の主なポイントは何ですか？ 感謝します。
>FPSの大ファンです。弾丸の実現について少し理解しています。問題主に１つの参照用Raycastに基づく擬似コードを提供します。
>
```ruby:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Bullet : MonoBehaviour
{
    public float Speed;   // 弾丸スピート
    public Vector3 Gravity; // 重力ベクトル
    Vector3 _PrePos;  // 光線の方向を計算するために元位置を保持する
    Vector3 _NewPos;  // 弾丸の新しい位置
    void FixedUpdated(){
        _NewPos += Speed * transform.forward * Time.deltaTime;  // 速度が座標への変更
        _NewPos += Gravity;  // 重力が座標への変更
        var direction = _NewPos - _PrePos;
        var distance = direction.magnitude;
        if( Physics.Raycast(_PrePos, direction, distance) ) {
            // dosomething();
        }
        else {
            _PrePos = transform.position;
            transform.position = _NewPos;  // ターゲットが検出されない場合は、弾丸を新しい位置に移動する
        }
    }
}
```

---
###UI
Q5: UGUIレンダリングを最適化したいのですが、この問題が見つかりました。たとえば、インターフェイスのScrollviewには多くのItemがあり、UIルートノードのZが0の場合、バッチ処理が行われます。Zが0でない場合、Itemは１つずつに描画され、バッチ処理はありません。この状況にどうすれば良いですか？教えてください、感謝します。
>UI要素PositionのZ値が0でない場合、3D UIと見なされ、バッチ処理に参加しません。親ノードZ!=0の場合、次の要素は全部バッチ処理できません。

---
UWA Technologyは、モバイル/VRなど様々なゲーム開発者向け、**パフォーマンス分析**と**最適化ソリューション**及び**コンサルティングサービス**を提供している会社でございます。

UWA公式サイト：https://jp.uwa4d.com
UWA公式ブログ：https://blog.jp.uwa4d.com