- 投稿日:2019-10-04T23:47:29+09:00
OculusGo,OculusQuest向けUnityパフォーマンスガイド
OculusGoやOculusQuest向けにUnityのVRゲーム作るぞ!!!と思った人が
- ポリ数の制限はどんな感じなのかな?
- マテリアルどのくらい使えるの?
- Unity上の設定項目は何がおすすめ?
みたいなことで悩む事があります。なので日本語でまとめておきます。
ベースの文書は下記Oculusオフィシャルドキュメントです。(2019年10月現在)OculusのDeveloper Guide (Testing and Performance Analysis)
https://developer.oculus.com/documentation/unity/latest/concepts/unity-perf/同じくOculusのUnity Mobile Performance Intro(Android)
https://developer.oculus.com/documentation/unity/latest/concepts/unity-mobile-performance-intro/#unity-mobile-performance-introシーン内の描画制限
- 60FPSのキープ(審査が通らなくなるので)
- 50-100 drawcall(つまり、シーン内全部、ではなく見える範囲でのSetPassCall数の話です)
- 5万~10万ポリゴン(これも、シーン内全部、ではなく見えている範囲でのポリゴン数の話です)
これを満たすようにデザイナーさんやモデラーさんにお願いすると良いです。
満遍なくカリングが利くシーンなら、全体で20万ポリゴンあっても大丈夫かもしれませんが、パーティクルなどを出す余地を考えると、 大雑把に10万ポリ制限 だと思っておくと良さそうです。
GameView上のStatsにチェックを入れて、この統計情報のTris:が100k以下で SetPassCallが100以下になっていればセーフです!
レンダリング最適化の為に
DrawCallの削減
DrawCallというかSetPassCallというか、要するにマテリアルやシェーダーの切り替える個数です。シーン内によく似た別マテリアルがいっぱいある場合は、同一マテリアルにしましょう。
あるいはMeshBakerとかで1マテリアルにまとめましょう。上にも挙げた通り、SetPassCallは100以下になるようにしましょう。
DrawCall Batching
Unity上だけで設定できることもあります。
- Static Batching
- Dynamic Batching
- GPU Instancingなどを利用することで、SetPassCallを減らせます。
Culling
プレイヤーから見えないオブジェクトは非表示にする、という仕組みは
Occlusion Cullingで設定できます。例えば無限に広がるオープンワールドゲームだと遠くまで全てのオブジェクトを描く必要がありますが、室内のシーンなら廊下や別の部屋を描かなくても良いです。
(注意:Occlusion Cullingを計算するCPU負荷があります。有効無効を切り替えて計測しましょう)また、地味なところですが
UnityのLayerごとにCameraからどの位距離が遠ざかったらレンダリングを止めるか、という設定ができます。チェックしてください。https://docs.unity3d.com/ScriptReference/Camera-layerCullDistances.html
Reducing Memory Bandwidth
メモリ帯域を削減しましょう。特にPCと違ってOculusGoやOculusQuestはメインメモリとGPUメモリが同居しているので、この帯域がネックになりやすいです。メモリ帯域を削減するとかなりパフォーマンスに効いてきます。
- Texture Compression:テクスチャ圧縮フォーマット。ETC2を古いドキュメントでは推奨していたけど、今はASTCが推奨です。(Snapdragon系はASTCをサポートしているので。ETC2でも悪くはないです)
- Texture Mipmaps: テクスチャのミップマップは常に有効化してください。UnityはテクスチャImport時に自動生成してくれます。
- Texture Filtering: テクスチャ設定のFilterModeです。Trilinear は負荷が上がりますが、それに見合うだけVRで見たときに奇麗に見えます。(もしギリギリまでパフォーマンスが必要ならBilinearも良いと思います)
- Texture Sizes: テクスチャ解像度は(Unity上の設定で)下げましょう。AssetStoreで買える奇麗なモデルは、往々にしてテクスチャ解像度がモバイルVRに不向きな位に高いです。実際にシーンに配置して、テクスチャ解像度を切り替えながら許容可能な値を探しましょう。大体の1オブジェクト毎のテクスチャはMax Size 1024でも足りると思います。(テクスチャをまとめてパックしてAtlasにするなら2048とか4096でも良いです)
- Framebuffer Format: デプスバッファはUnityデフォルトのモバイルでは24bitですが、16bitでも足りることが多いです。また、Unlitが多い(フォトリアルじゃなくてイラストタッチなら)カラーバッファも16bitで足りるかもしれません。Screen Resolution: UnityEngine.XR.XRSettings.renderScale=1.0fがデフォルトですが、0.9fや0.7fにすると一気に軽くなります。ただし綺麗に見せるには1.2f程度が必要だったりします。
モデルのジオメトリ(メッシュ)の注意点
LODを使える場合は使いましょう。多くのAssetStoreで買えるモデルはハイポリすぎることが多いです。
また、ゲームオブジェクトは統合出来るならすべきで、ビルトインStandardShaderはとても重いです。テクスチャ及びオーバードロー
Pixel Complexity:マテリアルが参照するテクスチャの枚数は可能な限り減らしてください。ビルトインシェーダーを使うなら、スペキュラマップなどを焼き込んでUnlitかMobile/Diffuseマテリアルに出来ないか検討してください。
Overdraw: シーンに半透明オブジェクトがあると、描画順を考える必要があります。オーバードローと言います、確認できます。そのため密な半透明パーティクルを使ったりすると、レンダリング負荷が一気に上がります。
SceneViewでOverdraw表示にすることで確認できます。(真っ赤な場所があったらピンチです)Best Practices
- 可能な限りテクスチャはパック(アトラス化)しましょう。
- 動かないオブジェクトはライトマップベイクしてstatic なオブジェクトにしましょう。
- 動くオブジェクトのライティングもdynamic lightingではなくlight probesで対応しましょう。
- Precomputed GIではなくライトマップベイクを使いましょう。
- Non-Directional Lightmapを使いましょう。 https://docs.unity3d.com/Manual/LightmappingDirectional.html
- specular reflections, ambient occlusion などのテクスチャはdiffuseテクスチャに焼き込みましょう。
- カメラをシーンに一個だけにしましょう(RenderTextureは重い…)
- 3パス以上のシェーダーを使わないようにしましょう。
- シェーダーの中でalpha testを避けましょう。
- アルファブレンドも最小限にしましょう。半透明は避けましょう。
- テクスチャ圧縮はASTCにしましょう
- PlayerSettingsから Disable Depth and Stencilをチェックしましょう
- フルスクリーンのImageEffectを避けましょう
- LoadSceneAdditiveAsyncとかを使わず、真っ暗を出してAsyncじゃないロードをしましょう。
- StandardShaderを避けましょう。重いです
- Projectorコンポーネントを避けましょう。重いです。
- Unity Default Skyboxは重いので避けてマテリアルで指定しましょう。(CameraのClearFlagもSkyboxではなくSolidColorを使いましょう)
CPU最適化
- シーン合計のGameObjectの数は少ない方が軽いです。
- Update()やFixedUpdate()を毎フレーム計算するオブジェクトは減らしましょう。
- Physicsは本当に必要なものだけ計算しましょう。
- 頻繁に破壊と生成が行われるものはObjectPoolを使いましょう。
- AudioSourceを使うときにPlayOneShotを避けましょう。重いです。
- 複雑な数値計算は避けましょう。
- キャッシュできるコンポーネント(例:Transform)は毎回探さずにキャッシュしましょう。
忘れがちポイント
補足
UE4事情
UE4のRobo Recallでは様々な最適化設定の上で 250ドローコール で60FPSをキープしています。
https://www.unrealengine.com/ja/developer-interviews/learn-how-drifter-entertainment-leveraged-elegant-optimizations-to-bring-robo-recall-to-the-oculus-quest将来の展望
Vulkan実装が動くようになるともうちょっといっぱい描けるようになりそう。
- 投稿日:2019-10-04T22:36:28+09:00
【Unity】Animationによるプロパティの変更を検知する
void OnDidApplyAnimationProperties()
が使えます。https://docs.unity3d.com/ja/2019.1/ScriptReference/UI.LayoutGroup.OnDidApplyAnimationProperties.html
// アニメーションのプレビューでも値をチェックしたいのでExecuteAlwaysする [ExecuteAlways] public class Foo : MonoBehaviour { public float foo; // TimelineとかAnimationでこの値を変更する void OnDidApplyAnimationProperties() { // ……すると、このメソッドが呼ばれる Debug.Log("foo changed!") } }どの値が変更されたのかはわからないので、古い値をとっておいて自分でチェックする必要があるっぽい。マジか……?
[SerializeField] private _foo; float _lastFoo; [SerializeField] private _bar; float _lastBar; void OnDidApplyAnimationProperties() { if (_foo != _lastFoo) { Debug.Log("foo changed!") } if (_bar != _lastBar) { Debug.Log("bar changed!") } _lastFoo = _foo; _lastBar = _bar; }もっといい方法あれば教えてください。
参考
- 投稿日:2019-10-04T20:02:45+09:00
【Unity】Animation単体の時に、アニメーションを最初から再生する方法
はじめに
Animatorを使わずに、Animationのみで実装する系の記事って意外と(?)無い気がするんですよね…。
というか、Unityのアニメーション関連は検索するのが難しい…。
で、「Animation 最初から」とかで検索かけてもあまりヒットしなくて毎回苦労しているのでメモ。開発環境
Unity2019.1.8f1
巻き戻せば良いんや
再生する前に、最初の状態に戻しましょう。
「Animation 最初から」でググるからいけなかった。「巻き戻す」でググれば良かったんですね。PlayAnime.csAnimation anime; anime = GameObject.Find("Animationがアタッチされているオブジェクト").GetComponent<Animation>(); anime.Rewind("アニメーション名"); //0フレーム目に巻き戻す anime.Play("アニメーション名");Animation-Rewind - Unity スクリプトリファレンス
最後に
他にもこんな方法あるよーというのがございましたらぜひご教示ください!
- 投稿日:2019-10-04T12:39:23+09:00
【Unity(C#)】VIVE用にデバッグ時のリセット実装
デバッグでPCまで戻るのめんどくさい
デバッグはしらみつぶしに行いたいのでキー入力でリセットの実装にしてると
何度もPCとプレイ位置を往復するのでめんどうです。かなり短くてしょーもない記事ですが、今後毎回使いそうなのでメモします。
コード
ベースはまんま前の記事1ですが、、、
#if UNITY_EDITOR using UnityEngine; using UnityEngine.SceneManagement; using Valve.VR; public class DebugReload : MonoBehaviour { [SerializeField] SteamVR_Input_Sources hand; [SerializeField] SteamVR_Action_Boolean grabAction; [SerializeField] float inputSeconds; bool preventContinuityPushButton; float timer; void Update() { if (grabAction.GetStateDown(hand)) { preventContinuityPushButton = true; } if (grabAction.GetState(hand) == false) { timer = 0; return; } else if (grabAction.GetState(hand) && preventContinuityPushButton) { timer += Time.deltaTime; } if (timer > inputSeconds) { Scene loadScene = SceneManager.GetActiveScene(); SceneManager.LoadScene(loadScene.name); } } } #endifSteamVR 2.0からVIVEの入力回りは、最初に設定したアクションから取得する形になってます。
簡単に言えば、それぞれの入力にポーズ名が決まっているだけのことです。今回はGripButtonの取得をしたいので、GrabGripを設定すればOKです。
Platform Dependent Compilation(プラットフォーム依存コンパイル)2
下記のようにEditor上のみでコンパイルする設定にしておけば、
実行ファイル形式で書きだした際に、変な機能が残ったままにならないので便利です。#if UNITY_EDITOR #endif
- 投稿日:2019-10-04T12:10:00+09:00
LineSDK入れ込みでハマった話
経緯
- LineSDKでログイン認証することに
- とりあえずSDKを入れて、ID設定して、コード書いてみた
- Unity上だと動作チェックできないのでUnityCloudBuildでiOS, Androidビルド
- >> ビルドエラー! <<
原因1:対応バージョン見てなかった
LineSDKは Android API 17(Android4.2)以上、 iOS 10.0以上対応 です。
これをビルド時の対応バージョン修正することで、Androidはビルドできるようになりました。
だからReadmeは読めとあれほど(ry原因2:Library Search Paths
iOSが相変わらずビルドできない上に、よく見るあのエラーが発生していることを確認。
Undefined symbols for architecture arm64
そう、やつです。
エラー文だけではどこが悪いのか全然分からないやつです。
CocoaPodの設定が悪いのかなど散々迷走したあげく、Swift関連のライブラリが軒並みリンク失敗して入れ込めてないことに気づきました。参考:https://stackoverflow.com/questions/52536380/why-linker-link-static-libraries-with-errors-ios
参考リンク先で言われているように、Unityの
OnPostprocessBuild
内にて、以下を追加することでiOSビルドができるようになりました。
project.AddBuildProperty (target, "LIBRARY_SEARCH_PATHS", "$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)");
感想
今回、UnityCloudBuildを使ったことで、より問題を複雑に考えて迷走しました。
原因はどっちも基本的な部分にあったので、一旦落ち着いてローカル環境でも同じ問題が起きるかなどきちんと確かめていくと絞り込みやすいかなと思いました。
あと、Readmeは読もう。
- 投稿日:2019-10-04T04:04:54+09:00
ARFoundationをLWRP(URP)環境下で動かす手順
経緯
ARFoundationを使ったアプリの中にVFX Graphを使用したパーティクル表現を導入しようとしてLightWeightRenderPipeline(LWRP)にレンダリングを切り替えたところ、ビルドするとカメラが真っ暗になり何も写されなくなった為。
内容
LWRP環境下でARFoundationアプリを動かす方法。
また名称が変わっただけですがUniversal Render Pipeline(URP)でも以下の記事のLWRPの部分をURPにすることで動作します。環境
Unity 2019.2.5f1
AR Foundation 3.0.0-preview3 (ARFoundationのLWRPサポートは3.0.0-preview1からになります。)
AR Core XR Plugin
AR Kit XR Plugin
Light Weight RP version 6.9.1(以下の方法は5.7.2~,URPの場合は7.0.0~)方法
まずAsset->Create->Rendering->LWRP->ForwardRendererを作成します。
次にRenderer Features ListにAR Background Renderer Featureを追加します。
そうしたらGraphicsのScriptable Render Pipeline Settingに追加するためのRenderPipelineをAsset->Create->Rendering->LWRP->Pipeline Assetから作成します。
Pipelineの設定でGeneralの項目のRender TypeをCustomにしDataに先ほど作ったForward Renderを適用させます。
Edit->Project Setting->GraphicsのScriptable Render Pipeline Settingsに作ったPipelineを適用させます。
これでLWRP環境下でもARFoundationをつかってちゃんと描写することができます。
参考資料