UniRx使用経験の共有

今回の主な話題：UniRx使用経験の共有、特殊効果はテクスチャの合併最適化に値ませんか、AssetBundleのLZMAやLZ4圧縮、Unity 5.6.5のiOSレンダリングに関するクラッシュ問題、Shadows.RenderShadowMapの時間コストの最適化。

---
###ロジックコード
Q1: 正式なプロジェクトでUniRxを使う経験のある人に感想を求めます。この前にいくつのUniRxドキュメントを見たことがあります。しばらく前にQFrameworkを見た時に、これをお勧めしていることがわかりました。今日オープンソースライブラリを見たところ、まだ会いました、人気も高いです。https://github.com/neuecc/UniRx

なので、ドキュメントをよく読んで興味津々です。新会社の枠に入れたいのですが、正式なプロジェクトでは使っていませんから、何かメモリまたは使用法に関する注意すべき点があるかどうかを知りたいです。

“UniRx (Reactive Extensions for Unity) is a reimplementation of the .NET Reactive Extensions. The Official Rx implementation is great but doesn’t work on Unity and has issues with iOS IL2CPP compatibility. This library fixes those issues and adds some specific utilities for Unity. Supported platforms are PC/Mac/Android/iOS/WebGL/WindowsStore/etc and the library.”

設計理念から言うと、Event（Action）のアイデアに基づいて非同期プログラミングの問題を解決し、同時にUnityコルーチンのいくつかの小さな欠陥を補う方は、良いように見えますが、依然としてポーリングまたは既存イベントのカプセル化に基づいたものであります。その後のメンテナンスコストの増加や、ほんとにパフォーマンスに問題がある場合の最適化のコストが心配なので、コミュニティの皆さんに聞きたいです。誰かがプロジェクトで大規模に使う経験のある人はいませんか？利点と欠点を教えてください。[Assets Storeでの評価も比較的高いです。](https://assetstore.unity.com/packages/tools/integration/unirx-reactive-extensions-for-unity-17276)

>現在のプロジェクトで小規模に使うことがありましたが、何らかの理由で取り替えました。個人的な意見のみを話します、誤りがございましたら、許してください。

>1）上手く慣れるまでには時間がかかり、チーム全体の素養には一定の要件があります。特にあまり知っていない場合は、もっと変なコードを書くこともあります。
2）执行の順序はあまり制御できません。特に执行順序に要求が比較的に高い場合、問題が発生する可能性があります。また、デバッグにもあまり直感的ではなく、コードの維持はより困難です。
3）パフォーマンスに関しては、プロジェクトの開始時に狭い範囲でしか使用されていないため、体系的なテストはありません。

---
###レンダリング
Q2: 私たちのゲームの特殊効果の作成方法は、1つのマテリアルが1つのテクスチャに対応し、それらすべてがハッシュ小さなテクスチャとして存在するため、特殊効果の高いDrawCallの問題が発生します。 特殊効果を最適化するために、UIアトラスのアイデアを参照して、特殊効果で使用される一セットのテクスチャを1つのアトラスにまとめることができますか？

利点：DrawCallを効果的に減らすことができます。

欠点：
1）共通のテクスチャが何度も大きな画像にマージされるか、または共通の画像セットが表示されます。一つの特殊効果に複数の大きなテクスチャが必要になる可能性があります。
2）テクスチャのマージにより、必然的にパッケージ本体が増加し、メモリとビデオメモリが元の状況よりも多く占有されます。それが逆最適化を引き起こすかどうかはわかりません。

2つのTencentゲームを参照すると、それらの特殊効果マップはハッシュされているように見え、マージされていません。皆さんのプロジェクトの特殊効果DrawCallはどのように最適化するか、類似の最適化またはより良い最適化アイデアがあるかをお聞きしたいと思います。 感謝します！

①
>個人的には特殊効果のテクスチャマージの価値はあると思いますが、理想的なマージ方法はちょっと難しいです。 その理由は、特殊効果のテクスチャは通用性がありますが、集約性が不十分であるためです。 たとえば、UIのテクスチャは、共有テクスチャと特有テクスチャを区別できます。複数の共有テクスチャをマージしたり、各システムインターフェイス内のテクスチャをマージしたりできるため、これで論理的に集約性があります。
特殊効果テクスチャの構成構造は、通常、下図に示すフォルダの区別方法など、効果によって区別されます。
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/0a3af66b-dbfa-9c58-53af-28ba77977e50.png)
Bloomエフェクトのやつをマージするなど、この種のフォルダメソッドに従ってマージします。しかし、例えば、一つのスキルでスモーク効果とスパークル効果がついてある場合、必ず二つフォルダのテクスチャを使用する必要があり、DrawCallも低下させられません。単一特殊効果にマージをするのは、問題主が言う欠点であります。冗長性が高く、全体的な状況を考慮することはできません。 これは、ほとんどのゲームが特殊効果テクスチャに対してマージをする状況はあまりない理由でもあります。

>私たちのやり方はデフォルトでハッシュすることであり、長期間存在し、DrawCallに大きな影響を与える特殊効果については、特定の最適化（特定アトラスの使用、高低配置のパーティクル表示を制御することなど）を行います。一般的な特殊効果にはマージされません。

②
>開発時間が許せば、ゲーム特殊効果のDraw Callをマージすることをお勧めします。特にほぼ同じ頻度の特殊効果に対します。パーティクルシステムについては、Texture Sheet Animation機能を考慮することをお勧めします。これについては、今年のUWA DAYで詳しく説明しました。Googleでその使用法を検査できます。
![2-1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/e57a5617-90a7-4110-32f8-49db54e6ac4a.jpeg)
ただし、説明すべきことは、複雑な状況（Mobaでのチームバトルなど）では、依然として特殊効果の重なり合うことが回避できません。この場合、Draw Callの占用は高める可能性もまたあります。したがって、上記の方法は確率的にDraw Callの使用を減らすとしか言えず、どれだけ減らすことができるか、開発チームが自分のプログラム次第で確認してください。

---
###クラッシュ
Q3: iPhone Xを使用して外部ネットワークで実機テストを行うと、クラッシュが発生しました。具体的な表現は、ゲームが突然フリーズし、時には画面が真っ暗になり、しばらくすると自動的に終了することです。クラッシュ後すぐにBuglyを更新すると、クラッシュの数は+1になり、クラッシュ時間は一致します。

ワールドボスと戦う途中にフラッシュしました。どのモデルに換えてもフラッシュしましたが、内部ネットワークで再現できず、外部ネットワークも閉鎖されました。一見するとGPUレンダリングに関するフラッシュのようですが、内部ネットワークで再現できないため、Bugが解決されているかどうかを検証できません。皆さんはこのような問題に遭うことがありませんか？どうやって解決しましたか？

具体的な状況：
Unity 5.6.5
XCode10.x
iPhone 7Plus、iPhone X、iPhone XS Maxで全部フラッシュしました。

私は以下の方法を試しました：
1）Unity 5.6.6にアップグレードしても、外部ネットワークでまだクラッシュしました。
2）Unityの設定を確認しました。OpenGLES 2.0でレンダリングされていました。

私の質問は、Metalレンダリングを使用しないように設定しましたが、Metalレンダリングのインターフェイスのように見えるAppleMetalGLRendererにアクセスするのはなぜですか？
>多くの調査と検証の結果、ついに原因を見つけました。

>command bufferを使ってシャドウをレンダリングすると、レンダリングしたいMeshを取得する必要があります。変更後、再びCombineMeshを行います。CombineMeshのフレームで、Meshは「中間状態」にあります（UnityのBugである可能性があります）。このフレームにcommand bufferを使ってレンダリングされたシャドウも一つの不規則な形状になり、XCodeがエラーを報告します。また、クラッシュを引き起こす可能性もあります。

>解決方法：CombineMeshのフレームでシャドウをレンダリングしなくなり、次のフレームにMeshをレンダリングする準備ができるまで待機します。 このようにして、シャドウの不規則な形状は表示されず、XCodeはエラーやクラッシュを報告しません。

---
###アセット管理
Q4: UnityはLZMAファイルのダウンロードプロセス中にファイルをLZ4の形式でキャッシュに保存するので、LZMA形式のファイルをダウンロードした後にファイルを保存するときに、LZ4のAssetBundleパッケージ圧縮形式に変更してローカルに保存することはできますか？
![3-1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/c86eb698-54bf-fcb9-75cd-72df52bf6f09.jpeg)
>ファイルを保存するときに、LZ4のAssetBundleパッケージ圧縮形式に変更してローカルに保存します。このアイデアは非常に新鮮で、考えたことはありませんでした。

>ただし、LZMAからLZ4に切り替える場合は、直接のインターフェイスがないはずです（これまで見たことがありません）。次に、LZMA解凍してから、LZ4に圧縮する必要があります。LZMAの圧縮率は非常に高く、解凍時間のコストは少し高いです。圧縮プロセスを追加するとより長くなりやすいです。ですから、このソリューションは変換時間のコストが高いという問題があると思います。問題主はそれが実装されているかどうかを評価してから、テストデータに基づいてソリューションを評価する必要があります。テストデータが最も説得力があります。

>一般的なアプローチは、LZ4を直接使用し、再び処理や圧縮を行わないことです。1つは非圧縮形式で、7zipなどのツールを使用して圧縮します。圧縮率は自分で選択し、高い圧縮率を使ったらLZMAよりも小さくなる可能性があります。もちろん代償もあります、圧縮率が高いほど解凍時間が長くなります。現在、非圧縮を使用しております。圧縮ツールで直接圧縮することは、解凍時間が少し長いと感じているため、圧縮率のバランスをとったり、LZ4に変更したりすることができます。

---
###レンダリング
Q5: コードスタックのShadows.RenderShadowMapは時間がかかりますが、どのように最適化するのですか？
![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653855/bb0f816a-0dd7-88b0-e791-85c088cf8f81.png)

①
>リアルタイムシャドウを使用する場合、シャドウを投影するオブジェクトは追加のレンダリングを一回受け、シャドウを受け取るオブジェクトもサンプリングされたシャドウ強度の計算を増やすため、レンダリング時間への影響は比較的大きくなります。問題主の時間コスト比率はまだ比較的高いので、シーン内でシャドウを投影/受けるオブジェクトの数を手動で制御することを考慮できます。キャラクターだけがシャドウを必要とする場合は、FastShadowReceiverでProjectorを使用することを考慮できます。

②
>リアルタイム投影のコストはまだ比較的多く、一般的にできることは、シャドウの品質を下げたり、投影および受けるシャドウの数を制御したりして、コストを減らすことです。

>私たちのやり方は、キャラクターにFastShadowReceiverを採用します。静的オブジェクトにベイク処理を採用します。他の動的オブジェクトは特定の状況によって異なって、下部に中央から端に向かってオブジェクトと一緒に移動するシャドウまたはFastShowReceiverをつけます。あるいは直接に投影されていません。

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

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