- 投稿日:2020-11-13T22:10:19+09:00
UnityでC++Puligin(Mac)
UnityでC++を使いたい
UnityでC++のコードを使いたいけどいまいちよく分からない
Windowsでの記事はたくさんあるがMacの記事は少ない
X Codeをインストールすればいいらしいけど、そんな機能の割に容量の喰うアプリを入れたくないと言うことでUnityとC++の開発環境(g++/clang++)があればできる方法を伝えます。
ターミナルでg++は使える前提で話をします。C++ファイルの作成
lib.h#include <iostream> #include <vector> #include <algorithm> using namespace std; extern "C" { int sum(int a, int b); // a+bを求める関数 int listsum(int* array, int size); // 配列の総和を求める関数 };lib.cpp#include "lib.h" int sum(int a, int b) { return a + b; } int listsum(int* array, int size) { int r = 0; for (int i=0;i<size;i++) { r += array[i]; } return r; }ビルドしてUnityで使う
必ず
/usr/bin/g++
を使用してください。$ /usr/bin/g++ -dynamiclib -o lib.bundle lib.cppUnityでC#と連携
MainScript.csusing System.Collections; using System.Collections.Generic; using System.Runtime.InteropServices; using UnityEngine; static class DLL { [DllImport("lib")] public static extern int sum(int a, int b); [DllImport("lib")] public static extern int listsum(System.IntPtr array, int size); } public class MainScript : MonoBehaviour { public int[] Array; // Start is called before the first frame update void Start() { Debug.Log(DLL.sum(1, 2)); System.IntPtr ptr = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(int)) * Array.Length); Marshal.Copy(Array, 0, ptr, Array.Length); Debug.Log(DLL.listsum(ptr, Array.Length)); Marshal.FreeCoTaskMem(ptr); } // Update is called once per frame void Update() { } }Asset内の適当なフォルダに
lib.bundle
を置いてUnityEditor上から配列の中身を適当に設定して実行する。ちゃんとConsoleに出力されれば成功!!!
参考サイト
- 投稿日:2020-11-13T19:59:55+09:00
Unityモジュールのローディング詳細解析(テクスチャ編)
ゲームやVRプロジェクトの開発中、モジュールのローディング(つまり、「ローディング効率」、「シーン切り替え速度」など)によって生じるパフォーマンスコストとメモリフットプリントは、開発チームにとってよくある問題です。 これにはアセットのローディングコストだけではなく、シーンオブジェクトのインスタンス化やアセットのアンロードも含まれます。開発者からすれば、当該モジュールはUnityエンジンでレンダリングに続いて2番目に大きいモジュールです。 したがって、モジュールのローディングに関する主要な性能問題をここで共有したいと考えています。
UWAオンラインに提出された多数のプロジェクトを統計することで、モジュールのローディングで最も時間のかかるパフォーマンスコストは、アセットのローディング、アセットのアンロード、オブジェクトのインスタンス化、コードのシリアル化等に起因すると考えられます。今回は先にアセットのローディングの中でテクスチャのローディングパフォーマンス分析を行います。
アセットローディング
アセットのローディングは、ローディングモジュールで最も時間かかる部分です。そのCPUコストは、Unityエンジンで主にLoading.UpdatePreloadingとLoading.ReadObjectに反映されます。
Loading.UpdatePreloadingはLoadLevel(Async)のようなインターフェイスが呼び出された場合に現れますが、主に現在シーンのアセットをアンロードおよび次のシーンの関連アセットとシリアル化情報をローディングします。次のシーンの自信のGameObjectとアセットが多ければ、ローディングコストが大きくなります。
多くのプロジェクトでは、もう一つのローディング方法が存在します。つまりシーンが空のシーンで、ほとんどのアセットとGameObjectsは、OnLevelWasLoadedコールバック関数によってローディング、インスタンス化、combinemeshインタフェースに呼び出されます。この場合は、Loading.UpdatePreloadingのローディングコストは小さくなります。
Loading.ReadObjectは、アセットがローディングの実際のアセット読み取りパフォーマンスコストです。基本的に、Unityエンジンの主要なアセット(テクスチャ、グリッド、アニメーションなど)はこれによって読み取られます。この項目は、プロジェクトシーンの切り替え効率を大きく左右すると言えます。このため、現在のプロジェクトで使用されている主流のアセットについて多くの試験と分析を実施しており、開発中のプロジェクトにお役に立てるように以下に分析結果を共有します。
注意事項:現在、UWAオンラインにはモバイルプラットフォーム向けのゲームプロジェクトが90%以上のため、この記事のアセットパフォーマンス分析は主にモバイルプロジェクトを対象としています。したがって、モバイルデバイス上の各アセットのローディングパフォーマンスを最初に分析および要約します。
アセットローディングパフォーマンステストコード
以下は、テストで使用したテストコードです。各アセットを特定のサイズのAssetBundleファイルにし、次のコードを使用して1つずつ異なるデバイスでローディングし、異なるハードウェアデバイスでのアセットローディングパフォーマンスの比較結果を取得します。
テスト環境
Unityエンジンバージョン:Unity 5.2
テスト対象デバイス:5つの異なるグレードのモバイルデバイス(Android:Redmi2、RedmiNote2、およびSamsungS6,iOS:iPhone 5 と iPhone 6)
テクスチャアセット
テクスチャアセットは、プロジェクトのローディングプロセスで最も高コストのアセットの1つであり、そのローディング効率はそれ自体のサイズによって決まります。 現在、テクスチャアセットのサイズを決定する3つの主な要素があります:解像度、フォーマット、およびMipmapが有効かどうか。
1. 解像度とフォーマット
これら2つの項目の設定はテクスチャアセットのサイズに大きな影響を与えるため、解像度とフォーマットはテクスチャアセットの読み込み効率に影響する重要な要素です。 したがって、これら2つの要素を詳細にテストしました。
テストケース1:同じフォーマットと異なる解像度でのローディング効率テスト
解像度2048×2048の2つの一般的なテクスチャアセットを選択し、AssetBundleを設定するときに、最大解像度を512×512、1024×1024、および2048×2048に設定し、テクスチャフォーマットをETC1(Android)とPVRTC(iOS)に設定しました。 そして、Mipmap機能を無効にしています。 したがって、3セットのテクスチャのメモリ使用量はそれぞれ256KB、1MB、4MBであり、対応のAssetBundleサイズは156KB、531KB、1.92MB(Androidプラットフォームの場合)、175KB、628KB、2.4MB(iOSプラットフォームの場合)です。 Unityバージョンは5.2で、圧縮形式はデフォルトのLZMA圧縮です。
Androidプラットフォームテストテクスチャ:
これらのテクスチャアセットを5つの異なるグレードのデバイスにローディングし、偶然性を下げるために、各デバイスでローディング操作を10回繰り返し、最終的に平均値をパフォーマンスコストとします。具体的なテスト結果を以下の表に示します。
上記のテストにより、次の結論を得ることができます。
- テクスチャアセットの解像度は、ローディングパフォーマンスに大きな影響を与えます。解像度が高ければ高いほど、ローディングに時間がかかります。デバイスの性能が悪ければ悪いほど、処理時間の差は顕著に現れます。
- デバイスの性能が良ければ良いほど、ローディング効率はよくなります。ただし、ハードウェアでサポートされるテクスチャ(ETC1 / PVRTC)の場合、ミッドエンドデバイスとハイエンドデバイスのローディング効率の違いはすでに小さく、たとえば、図のRedmiNote2とSamsung S6デバイスはそれほど違いがありません。
テストケース2:異なるフォーマットと同じ解像度でのローディング効率テスト
解像度1024×1024の2つの一般的なテクスチャアセットを選択し、AssetBundleをフォーマットするときに、異なるプラットフォームに応じて、パッケージ用のテクスチャフォーマットを異なるフォーマットに設定しました。 Androidプラットフォーム向けではETC1、ETC2、RGBA16、RGBA32を使用し、iOSプラットフォーム向けではPVRTC 4BPP、RGBA16、RGBA32フォーマットを使用し、同時にテクスチャごとにMipmap機能を無効にします。したがって、3セットのテクスチャのメモリ使用量は1MB、1MB、4MB、8MB(Androidプラットフォーム)/ 1MB、4MB、8MB(iOSプラットフォーム)です。
Androidプラットフォームテストテクスチャ:
テストケース1と同様に、5つの異なるグレードで10回のローディング操作を繰り返し、最終的に平均値をパフォーマンスコストとしました。 具体的なテスト結果を下図に示します。Androidデバイス:
iOSデバイス:
上記のテストにより、次の結論を得ることができます。
- テクスチャアセットのフォーマットはローディングパフォーマンスに大きな影響を与えます。Androidプラットフォームでは、ETC1とETC2のローディング効率が一番高いです。同様に、iOSプラットフォームでは、PVRTC 4BPPのローディング効率が最も高いです。
- RGBA16のテクスチャのローディング効率もRGBA32フォーマットと比較して非常に高く、そのローディング効率はETC1 / PVRTCに非常に近く、デバイスが優れているほど、ローディングコストの差はそれほど明確ではありません。
- RGBA32のテクスチャのローディング効率は、ハードウェアデバイスのパフォーマンスに大きく影響されますが、ETC / PVRTC / RGBA16はハードウェアデバイスの影響をあまり受けません。
注:テストで使用したETC1およびETC2テクスチャはすべてRGB 4Bitフォーマットであるため、半透明のテクスチャマッピングには2つのETC1形式のテクスチャが必要です(1つのRGBチャネル、もう1つのAlphaチャネル)。 2つのETC1のテクスチャを随一読み込むと、ローディング効率はRGBA16フォーマットよりも低くなりますが、ロード方法で補正できます。これについては、後続の記事で詳しく説明します。
2. Mipmap機能を有効に
Mipmap機能をオンにすると、テクスチャの一部のサイズも大きくなり、一般に、メモリは元のサイズの1.33倍に増加します。したがって、Mipamp機能を有効にする前後のローディングパフォーマンスをテストしました。
テストケース3:Mipmap機能のローディング効率テストのオン/オフを切り替えます
ETC1、PVRTC、RGBA16フォーマットおよびRGBA32を使用して、解像度が1024×1024の2つの一般的なテクスチャアセットを使用します(テストで使用されるテクスチャはテストケース2と同じです)。AssetBundleに設定する際に、1セット目をMipmap機能をオンにして、もう1セットのMipmap機能をオフにします。
テストケース1と同様に、5つの異なるグレードで10回のローディング操作を繰り返し、最終的に平均値をパフォーマンスコストとしました。具体的なテスト結果を下図に示します。
Androidプラットフォーム:
iOSプラットフォーム:
上記のテストにより、Mipmap機能をオンにしたことによりアセットのローディングに時間がかかり、デバイス性能が低いほど、ローディング効率の影響が大きくなることがわかります。上記のパフォーマンステストを通じて、テクスチャアセットを読み込むための推奨事項は次のとおりです。
RGBA32およびARGB32テクスチャの使用を厳密にコントロールし、視覚効果を確保するという前提下で、「ギリギリで十分」という原則に基づいて、テクスチャアセットの解像度を下げ、ハードウェアでサポートされるテクスチャフォーマットを使用します。
ハードウェアフォーマット(ETC、PVRTC)が視覚効果を満たせない場合、RGBA16フォーマットは比較的によいオプションであり、視覚効果を高めることもでき、ローディング時間も短縮することもできます。
UIテクスチャのMipmapが有効になっているかどうかに特に注意しながら、テクスチャアセットのMipmap関数を厳密にチェックします。 UWAで評価されたプロジェクトの中で、プロジェクトのUIテクスチャの多くがMipmap機能を有効にしました。これにより、メモリ使用量が無駄になるだけでなく、ローディング時間も長くなります。
ETC2は、OpenGL ES3.0をサポートするAndroidモバイルデバイスの半透明テクスチャフォーマットを処理するための良いフォーマットです。ただし、ゲームを多数のOpenGL ES 2.0デバイスで実行する必要がある場合は、ETC2のテクスチャを使用することはお勧めしません。大量のメモリ(RGBA32へのETC2)が発生するだけでなく、読み込み時間も長くなるためです。次の図は、Samsung S3およびS4デバイスのテスト2で使用されたテストテクスチャのパフォーマンスを示しています。 OpenGL ES2.0デバイスでは、ETC2フォーマットのテクスチャがETC1フォーマットよりも大幅に高く、RGBA16フォーマットのテクスチャよりもわずかに高いことがわかります。そのため、開発チームがプロジェクトでETC2フォーマットのテクスチャを慎重に使用することをお勧めします。
開発チームが関連する情報列を並べ替えるだけでアセット使用量をすばやく確認できるように、検出された各テクスチャリアセットパラメーターの詳細表示をUWA評価レポートに含めたのは、上記のローディング効率の問題のためです。 パフォーマンスの問題を引き起こしている特定のアセットを見つけることができます。
説明:上記は、テクスチャアセットのローディング時のパフォーマンステストです。 テストデータは、当社が使用するテストテクスチャの読み込みデータです。コンテンツの違いによりAssetBundle圧縮パッケージのサイズが異なり、最終的な読み込み効率が異なるため、異なるテクスチャの読み込み効率が異なることに注意してください。 ここでは、特定のパフォーマンス比較を行います。意図は、ローディングパフォーマンスに対するテクスチャフォーマット、解像度、およびMipmap関数の影響を誰も直感的に理解できるようにすることです。
UWA Technologyは、モバイル/VRなど様々なゲーム開発者向け、パフォーマンス分析と最適化ソリューション及びコンサルティングサービスを提供している会社でございます。
UWA公式サイト:https://jp.uwa4d.com
UWA公式ブログ:https://blog.jp.uwa4d.com
- 投稿日:2020-11-13T19:46:58+09:00
知っておくべきAssetBundle管理メカニズム
前回の記事「AssetBundleを明らかにする」に続き、AssetBundleを探し続けましょう。管理メカニズムから、アセットのロードとアンロードの原理について説明します。
AssetBundleロードの基礎
AssetBundleを介したアセットのロードは、2つのステップに分かれています。一番目のステップはAssetBundleオブジェクトを取得することであり、2番目のステップはこのオブジェクトを介して必要なアセットをロードすることです。そして一番目のステップは2つの方法に分かれており、下記に一般的に使用されるAPIと併せて詳しく説明します。
一、AssetBundleオブジェクトのよく使うAPIを取得する
(1)最初にWWWオブジェクトを取得し、次にWWW.assetBundleを介してAssetBundleオブジェクトを取得します。
●public WWW(string url);
BundleファイルをロードしてWWWオブジェクトを取得します。完了すると、メモリにより大きなWebStream(解凍されたコンテンツは通常、元Bundleファイルサイズの4〜5倍であり、テクスチャアセットの比率が大きくなる場合があります)を作成しますが、後続のAssetBundle.Loadは直接にメモリに実行できます。
●public static WWW LoadFromCacheOrDownload(string url, int version, uint crc = 0);
BundleファイルをロードしてWWWオブジェクトを取得します。同時に、解凍されたBundleコンテンツをキャッシュとしてディスクに保存します(Bundleがすでにキャッシュにある場合、この手順は省略されます)。完了すると、小さなSerializedFileのみがメモリに作成されます。後続のAssetBundle.Loadは、IOを介してディスクのキャッシュから取得します。●public AssetBundle assetBundle;
前の2つのインターフェイスを介してWWWオブジェクトを取得した後、WWW.assetBundleを介してAssetBundleオブジェクトを取得できます。(2)AssetBundleを直接取得します。
●public static AssetBundle CreateFromFile(string path);
圧縮されていないBundleファイルを介してAssetBundleオブジェクトを同期的に作成し、これは最も早い作成方法です。完了すると、小さなSerializedFileのみがメモリに作成されます。後続のAssetBundle.Loadは、IOを介してディスクから取得します。●public static AssetBundleCreateRequest CreateFromMemory(byte[] binary);
Bundleのバイナリデータを介して、AssetBundleオブジェクトを非同期で作成します。完了すると、より大きなWebStreamがメモリに作成されます。コールするとき、Bundleの解凍は非同期で実行されるため、圧縮されていないBundleファイルに対して、このインターフェイスはCreateFromMemoryImmediateと同等です。●public static AssetBundle CreateFromMemoryImmediate(byte[] binary);
このインターフェイスは、CreateFromMemoryの同期バージョンです。PS:バージョン5.3で、名前はLoadFromFile、LoadFromMemory、LoadFromMemoryAsyncに変更されて、LoadFromFileAsyncは追加され、メカニズムもある程度に変更しました。詳細については、Unityの公式ドキュメントを参照してください。
二、AssetBundleからアセットをロードするためのよく使うAPI
●public Object Load(string name, Type type);
指定された名前とアセットタイプにアセットをロードします。ロードする時に他の依存するアセットが自動的にロードされます。つまり、一つのPrefabをロードすると、引用されているTextureアセットは自動的にロードされます。●public Object[] LoadAll(Type type);
特定のアセットタイプのすべてのアセットをBundleに一回にロードします。●public AssetBundleRequest LoadAsync(string name, Type type);
このインターフェイスは、Loadの非同期バージョンです。PS:バージョン5.xで、名前はLoadFromFile、LoadFromMemory、LoadFromMemoryAsyncに変更されて、LoadFromFileAsyncも追加されました。
AssetBundleロード 進級
一、インターフェイスの比較:new WWWとWWW.LoadFromCacheOrDownload
(1)前者の利点
●後続のロード操作はメモリ内で実行され、後者に比べてIO操作のコストが少なくなります。
●キャッシュファイルを形成できません、後者はキャッシュを格納するために追加のディスクスペースが必要です。
●WWW.texture、WWW.bytes、WWW.audioClipなどのインターフェイスを介して直接外部アセットをロードでき、後者はAssetBundleのみロードできます。(2)前者の欠点
●毎回ロードすると解凍操作が含まれますが、後者は2回目のロードでの解凍のコストを節約します。
●メモリには大きなWebStreamがありますが、後者のメモリには通常は小さなSerializedFileしかありません。(これは一般的な状況ですが、絶対的なものではありません。シリアル化された情報が多いPrefabの場合、SerializedFileがWebStreamより大きい可能性もあります。)二、メモリ分析
AssetBundleを管理する場合、ロードプロセスにメモリへの影響を理解することは非常に重要です。上図では、中間にAssetBundleがアセットをロードする後に、メモリに各オブジェクトの分布をリストし、左側に各タイプのメモリの生成に関するロードAPIを示します。●WWWオブジェクト:最初のステップのメソッド1で生成され、メモリコストが低いです。
●WebStream:new WWWまたはCreateFromMemoryを使用するときに生成され、通常、メモリのコストは大きいです。
●SerializedFile:最初のステップの二種類のメソッドでも生成され、通常、メモリコストが低いです。
●AssetBundleオブジェクト:最初のステップの二種類のメソッドでも生成され、メモリコストが低いです。
●アセット(Prefabを含む):2番目のステップでロードによって生成されます。アセットタイプ次第に、メモリコストは別々のサイズがあります。
●シーンオブジェクト(GameObject):2番目のステップでInstantiateによって生成され、通常、メモリのコストは小さいです。次の章では、このマップにあるさまざまなメモリオブジェクトに対してアンロード方式を分析して、メモリの残留やリークを回避します。
三、注意点
●CreateFromFileは非圧縮のAssetBundleにのみ適用でき、AndroidシステムのStreamingAssetsは圧縮ディレクトリ(.jar)にあるため、CreateFromFileを使用する前に、非圧縮のAssetBundleをSDカードに配置する必要があります。Application.streamingAsstsPath = "jar:file://" + Application.dataPath + "!/ assets /";
●iOSシステムのオープンファイル上限は256であるため、メモリにCreateFromFileまたはWWW.LoadFromCacheOrDownloadによってロードされるAssetBundleオブジェクトもこの値より低くなります。新しいバージョンでは、LoadFromCacheOrDownloadが上限を超えると、自動的にnew WWWの形式に変更してロードしますが、以前のバージョンでロードは失敗になります。
●CreateFromFileとWWW.LoadFromCacheOrDownloadをコールすると、ResistentManager.Remapperのサイズが大きくなります。そしてPersistentManagerがアセットの永続ストレージを維持します。Remapperは、メモリにロードされたアセットHeapIDとソースデータFileIDの間のマッピング関係を保存します。これはMemory Poolで、動作はMonoメモリに似ていて、減少せずに増加するだけなので、これら2つのインターフェイスの使用について合理的な計画を立てる必要があります。
●依存関係のあるBundleパッケージに対して、ロードするときに順序に注意してください。たとえば、CanvasAがBundleAにあり、依存するAtlasBがBundleBにありと仮定します。アセットが正しく引用されるようにするために、BundleBのAssetBundleオブジェクトを作成する最も遅い時点は、CanvasAをインスタンス化する前です。つまり、BundleAのAssetBundleオブジェクトを作成する時とLoad(“CanvasA”)時に、BundleBのAssetBundleオブジェクトはメモリにないことが可能です。
●経験に基づいて、AssetBundleファイルのサイズは1MBを超えないようにすることをお勧めします。これは、一般的に、バンドルのロード時間とそのサイズの関係は直線的にではありませんから、大きすぎるBundleがより大きいロードコストを起こす可能性があります。●WWWオブジェクトのロードは非同期であるため、1つずつにロードすれば下図のようなCPUが暇な状況になりやすいです(選択したフレームのVsyncが大部分を占めます)。このとき、CPU使用率を上げるまたはロード完了のスピードを加速するために、複数のオブジェクトを同時にロードすることをお勧めします。
AssetBundleのアンロード
上記にAssetBundleを介してアセットをロードする際のメモリ割り当て状況について言及しました。次には、よく使うAPIを組み合わせて割り当てられたメモリをアンロードする方法を紹介します。最終的にすべての関連するメモリをクリアするという目的を達成します。
一、メモリ分析
上図の右側に、さまざまなメモリオブジェクトをアンロードする方法を示します。●シーンオブジェクト(GameObject):このタイプのオブジェクトは、Destroy関数を使用してアンロードできます。
●アセット(プレハブを含む):Prefab以外のアセットファイルは三つの方法でアンロードできます。1)Resources.UnloadAssetで指定するアセットをアンロードでき、CPUコストは小さいです。
2)Resources.UnloadUnusedAssetsで全ての引用されていないアセットを一回でアンロードします。CPUコストは大きいです。
3)AssetBundle.Unload(true)でAssetBundleオブジェクトをアンロードする時に、ロードされたアセットを一緒にアンロードします。
Prefabに対して、今はDestroyImmediateを介してのみアンロードできます。アンロード後、AssetBundleをリロードしないとPrefabをリロードできません。メモリコストが小さいため、特定的なアンロードは一般的にお勧めしません。
●WWWオブジェクト:オブジェクトのDispose関数をコールします。またはnullに設定します。
●WebStream:WWWオブジェクトと対応するAssetBundleオブジェクトをアンロードした後、この部分のメモリはエンジンによって自動的にアンロードされます。
●SerializedFile:AssetBundleをアンロードした後、この部分のメモリはエンジンによって自動的にアンロードされます。
●AssetBundleオブジェクト:AssetBundleをアンロードする方法は2つあります。1)AssetBundle.Unload(false)を使用して、AssetBundleオブジェクトをアンロードする時にメモリにロードされたアセットを保持します。
2)AssetBundle.Unload(true)を使用して、AssetBundleオブジェクトをアンロードする時にメモリにロードされたアセットをアンロードします。この方法はアセット引用のロストを引き起こしやすいため、頻繁に使用することはお勧めしません。
二、注意点
AssetBundleオブジェクトがAssetBundle.Unload(false)を介してアンロードされた後、オブジェクトを再作成して前にロードしたアセットをメモリにリロードすると、冗長性を導き、つまり同じアセットが2つ存在します。
スクリプトの静的変数が引用したアセットは、Resources.UnloadUnusedAssetsをコールする時にアンロードされません。Profilerにこの引用状況を見られます。
UWAからの推奨案
上記の説明を通じて、AssetBundleのロードとアンロードについて明確に理解されていると思います。以下では、API選択に関する推奨を簡単に説明します。
●メモリに常駐する必要なBundleファイルに対して、メモリ占用の削減を優先します。したがって、Prefab以外のアセット(特にテクスチャ)を格納するBundleファイルに対しては、WWW.LoadFromCacheOrDownloadまたはAssetBundle.CreateFromFileを使用してロードし、WebStreamがメモリに常駐することを回避できます。より多くのPrefabアセットを格納するBundleの場合、WWW.LoadFromCacheOrDownload でロードする時に生成するSerializedFile はnew WWW が生成するWebStream より大きい可能性があるため、new WWWロードを使用することを考えしてください。
●ロード後にアンロードされるBundleファイルに対して、2つの状況があります。速度(シーンのロード時)優先と流暢さ(ゲームの進行中)優先です。
1)シーンをロードする場合、WWWオブジェクトを1つずつロードすることによって発生するCPUの暇状況を回避するように注意する必要があります。ロード速度の速いWWW.LoadFromCacheOrDownloadまたはAssetBundle.CreateFromFileの使用を考慮できますが、その後の大量のアセットロード、IOコストを引き起こすことを回避する必要があります(直接にLoadAllすることが試せます)。
2)ゲームが実行している場合、重い状況を引き起こさないために同期操作の使用を回避することが必要です。だからnew WWWとAssetBundle.LoadAsyncを一緒に使ってスムーズにロードすることを考えられます。ただし、Shaderやより大きいTextureなどのアセットに対して、初期化操作は時間がかかり、重いやすいことに注意すべきです。シーンをロードする時にこのようなアセットをプリロードすることをお勧めします。
●CreateFromMemory インターフェイスの読み込みが遅いため、Bundleを暗号化する必要のある状況のみで考慮します。
●Resources.UnloadUnusedAssets()インターフェイスのコストが高く、重いやすいため、できる限りにゲームでこのインターフェイスを回避します。Resources.Unload(obj) を使用して1つずつアンロードし、ゲームのスムーズさを確保することができます。
上記のメモリ管理は、Unity5.3より前のバージョンに適していることに注意してください。Unityエンジンは、5.3でAssetBundleのメモリ使用量に一定の調整を加えており、現在、さらなる勉強と研究を行っています。
UWA Technologyは、モバイル/VRなど様々なゲーム開発者向け、パフォーマンス分析と最適化ソリューション及びコンサルティングサービスを提供している会社でございます。
UWA公式サイト:https://jp.uwa4d.com
UWA公式ブログ:https://blog.jp.uwa4d.com
- 投稿日:2020-11-13T19:46:58+09:00
知っておくべきAssetBundle管理の原理
前回の記事「AssetBundleを明らかにする」に続き、AssetBundleを探し続けましょう。管理の原理から、アセットのロードとアンロードの原理について説明します。
AssetBundleロードの基礎
AssetBundleを介したアセットのロードは、2つのステップに分かれています。一番目のステップはAssetBundleオブジェクトを取得することであり、2番目のステップはこのオブジェクトを介して必要なアセットをロードすることです。そして一番目のステップは2つの方法に分かれており、下記に一般的に使用されるAPIと併せて詳しく説明します。
一、AssetBundleオブジェクトのよく使うAPIを取得する
(1)最初にWWWオブジェクトを取得し、次にWWW.assetBundleを介してAssetBundleオブジェクトを取得します。
●public WWW(string url);
BundleファイルをロードしてWWWオブジェクトを取得します。完了すると、メモリにより大きなWebStream(解凍されたコンテンツは通常、元Bundleファイルサイズの4〜5倍であり、テクスチャアセットの比率が大きくなる場合があります)を作成しますが、後続のAssetBundle.Loadは直接にメモリに実行できます。
●public static WWW LoadFromCacheOrDownload(string url, int version, uint crc = 0);
BundleファイルをロードしてWWWオブジェクトを取得します。同時に、解凍されたBundleコンテンツをキャッシュとしてディスクに保存します(Bundleがすでにキャッシュにある場合、この手順は省略されます)。完了すると、小さなSerializedFileのみがメモリに作成されます。後続のAssetBundle.Loadは、IOを介してディスクのキャッシュから取得します。●public AssetBundle assetBundle;
前の2つのインターフェイスを介してWWWオブジェクトを取得した後、WWW.assetBundleを介してAssetBundleオブジェクトを取得できます。(2)AssetBundleを直接取得します。
●public static AssetBundle CreateFromFile(string path);
圧縮されていないBundleファイルを介してAssetBundleオブジェクトを同期的に作成し、これは最も早い作成方法です。完了すると、小さなSerializedFileのみがメモリに作成されます。後続のAssetBundle.Loadは、IOを介してディスクから取得します。●public static AssetBundleCreateRequest CreateFromMemory(byte[] binary);
Bundleのバイナリデータを介して、AssetBundleオブジェクトを非同期で作成します。完了すると、より大きなWebStreamがメモリに作成されます。コールするとき、Bundleの解凍は非同期で実行されるため、圧縮されていないBundleファイルに対して、このインターフェイスはCreateFromMemoryImmediateと同等です。●public static AssetBundle CreateFromMemoryImmediate(byte[] binary);
このインターフェイスは、CreateFromMemoryの同期バージョンです。PS:バージョン5.3で、名前はLoadFromFile、LoadFromMemory、LoadFromMemoryAsyncに変更されて、LoadFromFileAsyncは追加され、メカニズムもある程度に変更しました。詳細については、Unityの公式ドキュメントを参照してください。
二、AssetBundleからアセットをロードするためのよく使うAPI
●public Object Load(string name, Type type);
指定された名前とアセットタイプにアセットをロードします。ロードする時に他の依存するアセットが自動的にロードされます。つまり、一つのPrefabをロードすると、引用されているTextureアセットは自動的にロードされます。●public Object[] LoadAll(Type type);
特定のアセットタイプのすべてのアセットをBundleに一回にロードします。●public AssetBundleRequest LoadAsync(string name, Type type);
このインターフェイスは、Loadの非同期バージョンです。PS:バージョン5.xで、名前はLoadFromFile、LoadFromMemory、LoadFromMemoryAsyncに変更されて、LoadFromFileAsyncも追加されました。
AssetBundleロード 進級
一、インターフェイスの比較:new WWWとWWW.LoadFromCacheOrDownload
(1)前者の利点
●後続のロード操作はメモリ内で実行され、後者に比べてIO操作のコストが少なくなります。
●キャッシュファイルを形成できません、後者はキャッシュを格納するために追加のディスクスペースが必要です。
●WWW.texture、WWW.bytes、WWW.audioClipなどのインターフェイスを介して直接外部アセットをロードでき、後者はAssetBundleのみロードできます。(2)前者の欠点
●毎回ロードすると解凍操作が含まれますが、後者は2回目のロードでの解凍のコストを節約します。
●メモリには大きなWebStreamがありますが、後者のメモリには通常は小さなSerializedFileしかありません。(これは一般的な状況ですが、絶対的なものではありません。シリアル化された情報が多いPrefabの場合、SerializedFileがWebStreamより大きい可能性もあります。)二、メモリ分析
AssetBundleを管理する場合、ロードプロセスにメモリへの影響を理解することは非常に重要です。上図では、中間にAssetBundleがアセットをロードする後に、メモリに各オブジェクトの分布をリストし、左側に各タイプのメモリの生成に関するロードAPIを示します。●WWWオブジェクト:最初のステップのメソッド1で生成され、メモリコストが低いです。
●WebStream:new WWWまたはCreateFromMemoryを使用するときに生成され、通常、メモリのコストは大きいです。
●SerializedFile:最初のステップの二種類のメソッドでも生成され、通常、メモリコストが低いです。
●AssetBundleオブジェクト:最初のステップの二種類のメソッドでも生成され、メモリコストが低いです。
●アセット(Prefabを含む):2番目のステップでロードによって生成されます。アセットタイプ次第に、メモリコストは別々のサイズがあります。
●シーンオブジェクト(GameObject):2番目のステップでInstantiateによって生成され、通常、メモリのコストは小さいです。次の章では、このマップにあるさまざまなメモリオブジェクトに対してアンロード方式を分析して、メモリの残留やリークを回避します。
三、注意点
●CreateFromFileは非圧縮のAssetBundleにのみ適用でき、AndroidシステムのStreamingAssetsは圧縮ディレクトリ(.jar)にあるため、CreateFromFileを使用する前に、非圧縮のAssetBundleをSDカードに配置する必要があります。Application.streamingAsstsPath = "jar:file://" + Application.dataPath + "!/ assets /";
●iOSシステムのオープンファイル上限は256であるため、メモリにCreateFromFileまたはWWW.LoadFromCacheOrDownloadによってロードされるAssetBundleオブジェクトもこの値より低くなります。新しいバージョンでは、LoadFromCacheOrDownloadが上限を超えると、自動的にnew WWWの形式に変更してロードしますが、以前のバージョンでロードは失敗になります。
●CreateFromFileとWWW.LoadFromCacheOrDownloadをコールすると、ResistentManager.Remapperのサイズが大きくなります。そしてPersistentManagerがアセットの永続ストレージを維持します。Remapperは、メモリにロードされたアセットHeapIDとソースデータFileIDの間のマッピング関係を保存します。これはMemory Poolで、動作はMonoメモリに似ていて、減少せずに増加するだけなので、これら2つのインターフェイスの使用について合理的な計画を立てる必要があります。
●依存関係のあるBundleパッケージに対して、ロードするときに順序に注意してください。たとえば、CanvasAがBundleAにあり、依存するAtlasBがBundleBにありと仮定します。アセットが正しく引用されるようにするために、BundleBのAssetBundleオブジェクトを作成する最も遅い時点は、CanvasAをインスタンス化する前です。つまり、BundleAのAssetBundleオブジェクトを作成する時とLoad(“CanvasA”)時に、BundleBのAssetBundleオブジェクトはメモリにないことが可能です。
●経験に基づいて、AssetBundleファイルのサイズは1MBを超えないようにすることをお勧めします。これは、一般的に、バンドルのロード時間とそのサイズの関係は直線的にではありませんから、大きすぎるBundleがより大きいロードコストを起こす可能性があります。●WWWオブジェクトのロードは非同期であるため、1つずつにロードすれば下図のようなCPUが暇な状況になりやすいです(選択したフレームのVsyncが大部分を占めます)。このとき、CPU使用率を上げるまたはロード完了のスピードを加速するために、複数のオブジェクトを同時にロードすることをお勧めします。
AssetBundleのアンロード
上記にAssetBundleを介してアセットをロードする際のメモリ割り当て状況について言及しました。次には、よく使うAPIを組み合わせて割り当てられたメモリをアンロードする方法を紹介します。最終的にすべての関連するメモリをクリアするという目的を達成します。
一、メモリ分析
上図の右側に、さまざまなメモリオブジェクトをアンロードする方法を示します。●シーンオブジェクト(GameObject):このタイプのオブジェクトは、Destroy関数を使用してアンロードできます。
●アセット(プレハブを含む):Prefab以外のアセットファイルは三つの方法でアンロードできます。1)Resources.UnloadAssetで指定するアセットをアンロードでき、CPUコストは小さいです。
2)Resources.UnloadUnusedAssetsで全ての引用されていないアセットを一回でアンロードします。CPUコストは大きいです。
3)AssetBundle.Unload(true)でAssetBundleオブジェクトをアンロードする時に、ロードされたアセットを一緒にアンロードします。
Prefabに対して、今はDestroyImmediateを介してのみアンロードできます。アンロード後、AssetBundleをリロードしないとPrefabをリロードできません。メモリコストが小さいため、特定的なアンロードは一般的にお勧めしません。
●WWWオブジェクト:オブジェクトのDispose関数をコールします。またはnullに設定します。
●WebStream:WWWオブジェクトと対応するAssetBundleオブジェクトをアンロードした後、この部分のメモリはエンジンによって自動的にアンロードされます。
●SerializedFile:AssetBundleをアンロードした後、この部分のメモリはエンジンによって自動的にアンロードされます。
●AssetBundleオブジェクト:AssetBundleをアンロードする方法は2つあります。1)AssetBundle.Unload(false)を使用して、AssetBundleオブジェクトをアンロードする時にメモリにロードされたアセットを保持します。
2)AssetBundle.Unload(true)を使用して、AssetBundleオブジェクトをアンロードする時にメモリにロードされたアセットをアンロードします。この方法はアセット引用のロストを引き起こしやすいため、頻繁に使用することはお勧めしません。
二、注意点
AssetBundleオブジェクトがAssetBundle.Unload(false)を介してアンロードされた後、オブジェクトを再作成して前にロードしたアセットをメモリにリロードすると、冗長性を導き、つまり同じアセットが2つ存在します。
スクリプトの静的変数が引用したアセットは、Resources.UnloadUnusedAssetsをコールする時にアンロードされません。Profilerにこの引用状況を見られます。
UWAからの推奨案
上記の説明を通じて、AssetBundleのロードとアンロードについて明確に理解されていると思います。以下では、API選択に関する推奨を簡単に説明します。
●メモリに常駐する必要なBundleファイルに対して、メモリ占用の削減を優先します。したがって、Prefab以外のアセット(特にテクスチャ)を格納するBundleファイルに対しては、WWW.LoadFromCacheOrDownloadまたはAssetBundle.CreateFromFileを使用してロードし、WebStreamがメモリに常駐することを回避できます。より多くのPrefabアセットを格納するBundleの場合、WWW.LoadFromCacheOrDownload でロードする時に生成するSerializedFile はnew WWW が生成するWebStream より大きい可能性があるため、new WWWロードを使用することを考えしてください。
●ロード後にアンロードされるBundleファイルに対して、2つの状況があります。速度(シーンのロード時)優先と流暢さ(ゲームの進行中)優先です。
1)シーンをロードする場合、WWWオブジェクトを1つずつロードすることによって発生するCPUの暇状況を回避するように注意する必要があります。ロード速度の速いWWW.LoadFromCacheOrDownloadまたはAssetBundle.CreateFromFileの使用を考慮できますが、その後の大量のアセットロード、IOコストを引き起こすことを回避する必要があります(直接にLoadAllすることが試せます)。
2)ゲームが実行している場合、重い状況を引き起こさないために同期操作の使用を回避することが必要です。だからnew WWWとAssetBundle.LoadAsyncを一緒に使ってスムーズにロードすることを考えられます。ただし、Shaderやより大きいTextureなどのアセットに対して、初期化操作は時間がかかり、重いやすいことに注意すべきです。シーンをロードする時にこのようなアセットをプリロードすることをお勧めします。
●CreateFromMemory インターフェイスの読み込みが遅いため、Bundleを暗号化する必要のある状況のみで考慮します。
●Resources.UnloadUnusedAssets()インターフェイスのコストが高く、重いやすいため、できる限りにゲームでこのインターフェイスを回避します。Resources.Unload(obj) を使用して1つずつアンロードし、ゲームのスムーズさを確保することができます。
上記のメモリ管理は、Unity5.3より前のバージョンに適していることに注意してください。Unityエンジンは、5.3でAssetBundleのメモリ使用量に一定の調整を加えており、現在、さらなる勉強と研究を行っています。
UWA Technologyは、モバイル/VRなど様々なゲーム開発者向け、パフォーマンス分析と最適化ソリューション及びコンサルティングサービスを提供している会社でございます。
UWA公式サイト:https://jp.uwa4d.com
UWA公式ブログ:https://blog.jp.uwa4d.com
- 投稿日:2020-11-13T19:33:55+09:00
AssetBundleの非同期ロードを中断する方法
今回の主な話題:AssetBundleの非同期ロードを中断する方法、コードがdllにパッケージされた後にProfilerできません、updateWhenOffscreenの割役
ロード
Q1: 非同期インターフェースyield return AssetBundle.ASyncLoadを使用する場合、そういう疑問が起きました:非同期処理が完了する前にどうやってこのタスクをキャンセルできますか。つまり、AssetBundleが半分ロードされていますが、ロードを諦めたいのですが、どうすればよいですか?
①
Unityインターフェースには中断操作はありませんが、プロジェクトのAssetBundleMgrモジュールのビジネスロジックレイヤーに中断できるインターフェースを提供できます。つまり、アセットがMgrにロードされた後、ビジネスレイヤーが不要になった場合、コールバックは返されません/実行されません。この「不要な」アセットをキャッシュまたはアンインストールする必要があるかどうかについては、自分のプロジェクトに従って処理する必要があります。
②
Unityドキュメントにある小さなトラップを共有しましょう。実際に答えはわかりません。ソースコードを知っている友達が助けてくれることを願っています。
AssetBundleが非同期で要求されると、AssetBundleCreateRequestオブジェクトが返されます。Unityの公式ドキュメントには、AssetBundleCreateRequest.assetBundleを述べる時には、下記の文が記載されています。“DescriptionAsset object being loaded (Read Only). Note that accessing asset before isDone is true will stall the loading process.”
「stall」という言葉が使っていますが、前に「停止」の意味と理解し、このインターフェイスのコールは非同期要求を中断できると考えていました。この特性を乗って、「同じAssetBundleが非同期にロードされているときに同期要求が来ました」状況で使用しました。
今日この問題を見て、このドキュメントを読むと、「stall」という言葉は「停止」の意味ではなく、「遅延」を意味する可能性が高いと感じています。非同期ロード要求の場合、スレッドで実行しますが、このときメインスレッドからのアクセスリクエストがあるとクロススレッドロックロジックが必要になり、ロードが遅くなる場合があります。 停止する場合は、ドキュメントでStopなどのより具体的な単語を使用する必要があると思います。③
問題主が私たちと同じ問題に遭いましたね。最後に、Promiseを使用してアセットのロードインターフェイスをカプセル化しました。
返されたhandleオブジェクトの状態が固化すると、変更できません。code1op = loadasset() yield return op if op.error != nil then log("fail=" + op.error) endcode2op:reject("next scene is loading")④
APIとUnityReferenceSourceを見に行きました。プロジェクトはずっとUnity5.6バージョンを使用しているため、Unity2017および2018のAssetBundleはまだテストされていません。Unity 5.6は、AssetBundleアセットをキャンセルまたはブロックすることはできませんが、新しいDocにブロックはアセットを取得できると記載されています。referenceSourceにあるAssetBundleのAPIも言及していますが、AssetのAPIには言及していません。私の理解では、非同期が完了する前に、アセットをアクセスすると同期になってすぐにこのリソースを取得できます。テストしたことのある学生さんがこれを答えてください。本当にそうであれば良かったです。多くのプロジェクトは、デザイン的に非同期と同期は共存して、ただ「一つ非同期ロードしているアセットを同期ロードする」ことを避けましただけ。Unityがこの辺を変更すると、「一つ非同期ロードしているアセットを同期ロードする」という問題を完璧に解決できます。
Unity Docによく騙されたため、ReferenceSourceにもっと信じています。AssetBundleは非同期ロードしているアセットを同期ロードすることを実現したが、Assetには実現していないと推測します。
アニメーションシステム
Q2:キャラクターの動きを作るために70本の骨(準備済みリボンが多い)を試用したいとアーティストと話し合いましたが、各モデル(各セットのファッション)はそのうちの30〜40本しかスキニングに参加しません。この状況と40本の骨を使ってキャラクターの動きを作る(Optimize GameObjectを開く)と比べると、パフォーマンスに大きな違いはありますか?
この考えの理由は、ファッションの実装のためにより多くのスペースを確保したいからです。最初は、コードを使ってすべてのリボンを動的なボーンに制御することを計画しましたが、Optimize GameObjectをオンにすると、スキニング骨格情報を変更できなくなります。これに対して何か方法はありませんか?
一つ目の問題に対して、2つの状況のパフォーマンスの違いを比較するのは難しいです。Optimize GameObjectがオンになっているかどうかに関係なく、最も影響を受けるパフォーマンスコストは、下図にあるDirtySceneObjectsとWriteJobであります。そして骨格の数が影響するのは下図にあるProcessAnimationsJobです。だからこの両者はお互いに大きな関連性はありません。したがって、問題主に適切かどうかを判断する前に、実機で自分のモデルに対してテストをすることをお勧めします。
二番目の問題を答えます。一般的に、リボンは追加のアニメーションファイルとして処理できます。Optimize GameObjectを行う時に、リボンがキャラクターにかける親ノードをバレさせたら大丈夫です。そうすればリボンは自分のアニメーション計算を行え、元のキャラクターと結合する必要はありません。もちろん、上記は一つの一般的なやり方で、問題主に最も適切のものはプロジェクト次第で決定する必要があります。
ロジックコード
Q3:開発プロセス中に、デザイナーアーティストが私たちのコードを使用しました。C#ファイルをdllファイルにパッケージし、パフォーマンスを分析する時にProfilerを使ってドットを追加してロケーションする必要がります。しかし、dllにドットを追加すると、Unity Profilerパネルにデータが表示されません。
レンダリング
Q4:updateWhenOffscreenの用途は何ですか?オンにすることをお勧めしますか?私たちの髪はalpha blendingのShaderを使っていますが、時々に理由もなくで消える状況はあり、これは原因かどうかを疑っています。
①
主にBounds:https://docs.unity3d.com/ScriptReference/SkinnedMeshRenderer-localBounds.html
オンにすれば、フレームごとにBoundsを更新します。しかし、updateWhenOffscreen自身のドキュメントを見ると、困惑しています。
https://docs.unity3d.com/ScriptReference/SkinnedMeshRenderer-updateWhenOffscreen.html実際にテストしたら、チェックすると、画面を離れなくでもフレームごとにBoundsを更新します。チェックしないと、画面にあっでも更新しません。そしてupdateWhenOffscreenを無効化するとanimationsも無効になさせる効果は見つけませんでした。オンにすると追加のコストが必然的に発生するため、当然、オンにしないことをお勧めします。
②
この問題はBoundsに関連しているようです。RecalculateBoundsを前処理することをお勧めします。
メモリ管理
Q5:パフォーマンスレポートにある「Monoメモリの割り当て詳細」レポートから、一番目のZOutputSteam.ctorに50MBが割り当てられていることがわかりましたが、この部分はどうやって最適化できますか?しかし、「コード効率/Monoメモリの割り当て」からこれは見つけませんでした。
ZOutputSteam.ctorとは、ZOutputSteam類が構造関数を実行していることを説明します。つまり、コードが複数回にNew ZOutputSteam操作を執行しています。問題主にこれを確認することをお勧めします。そうであれば、頻繁なNewの代わりに、ZOutputSteamの実例をサンプリングと再利用することを考えられます。
「コード効率/Monoメモリの割り当て」で表示される情報は、全体的なMonoメモリ割り当て情報だけです。だらか、Monoメモリ検測を実行する必要があります。
UWA Technologyは、モバイル/VRなど様々なゲーム開発者向け、パフォーマンス分析と最適化ソリューション及びコンサルティングサービスを提供している会社でございます。
UWA公式サイト:https://jp.uwa4d.com
UWA公式ブログ:https://blog.jp.uwa4d.com
- 投稿日:2020-11-13T12:42:13+09:00
[Unity + Android + Windows] Android SDK 29を入れようとしたらsdkmanagerに怒られた
2020年11月2日からAndroidアプリのアップデートをする際にtargetSDKバージョン29以上が必須になったらしい
sdkmanagerでAndroid SDK 29を入れてみる
この記事を参考にAndroid SDK 29を入れようとしてみた
https://kudougames.com/2020/08/30/unity%E3%81%A7-android-api-level-29-%E3%81%AE%E3%83%93%E3%83%AB%E3%83%89/しかし、sdkmanagerさんに以下のエラーで怒られます
C:\Program Files\Unity\Hub\Editor\2019.4.10f1\Editor\Data\PlaybackEngines\AndroidPlayer\SDK\tools\bin>sdkmanager.bat "platforms;android-29" Exception in thread "main" java.lang.NoClassDefFoundError: javax/xml/bind/annotation/XmlSchema at com.android.repository.api.SchemaModule$SchemaModuleVersion.<init>(SchemaModule.java:156) at com.android.repository.api.SchemaModule.<init>(SchemaModule.java:75) at com.android.sdklib.repository.AndroidSdkHandler.<clinit>(AndroidSdkHandler.java:81) at com.android.sdklib.tool.sdkmanager.SdkManagerCli.main(SdkManagerCli.java:73) at com.android.sdklib.tool.sdkmanager.SdkManagerCli.main(SdkManagerCli.java:48) Caused by: java.lang.ClassNotFoundException: javax.xml.bind.annotation.XmlSchema at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:602) at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178) at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522) ... 5 more解決方法
環境変数「Path」と「JAVA_HOME」にJDK 8のPathを追加するだけでした
例:
C:\Program Files (x86)\Java\jre1.8.0_271\bin
おしまい
- 投稿日:2020-11-13T11:43:10+09:00
[Unity]ドライブの空き容量が少ない場合の対処
備忘用
やあ、4ヵ月ぶりですね。
元気に3Dゲーム作成して遊んでいます。<はじめに>
この作業を行い、発生したいかなる事象に関して当方は一切の責任を取りません。<経緯>
うちのノートPC、120GBしか容量ないねん。
空き容量が2GBしかない。Unityしかやってないのにおかしいやんけ!!<やったこと>
1.ネットで落ちてるなんやかんやの空き容量の確保作業。
(ディスクのクリーンアップ、CCleaner、不要アプリ削除、他)
2.Unityの古いパッケージファイルの削除(※※今回の作業※※)Unity様が開発しているいくつかのパッケージが容量を圧迫してました。
使っているバージョン以外は不要なので削除します。※最新版ダウンロードしたときに古いバージョン消してくれてもいいやんけ・・・
って思ったけど複数のプロジェクト抱えてそれぞれ別バージョンを使っている場合とか
考慮しているんだろうきっと。
- 投稿日:2020-11-13T05:14:09+09:00
MacでAndroidをビルドする際に参考にしたサイト
macでunityをビルドしてAndroid実機でテストする方法
https://note.com/pes88/n/n2141cffd2f8fUnityでAndroidにビルドする(Mac)
https://sh-lu0.hatenablog.com/entry/2018/12/09/Unity%E3%81%A7Android%E3%81%AB%E3%83%93%E3%83%AB%E3%83%89%E3%81%99%E3%82%8B%28Mac%29Unity2018インストールからAndroidビルドするまでの手順
https://qiita.com/taroyan/items/2ff7f6aadd640221bde5
※このサイトが一番参考になったAndroid Studioは結局使ってない。どこかで使うシーンが出てくるんだろうが、テスト用にAndroidのスマホにビルドしたアプリを入れるだけなら必要なかったので、案外楽チンだった