Outline
はじめに
前回の記事では、Unityにおけるリソース読み込みについての基本的な知識を総ざらいし、ResourcesやAssetBundleの特徴や違いについて取り上げ、AssetBundleの必要性について述べました。
今回は、残念ながらAssetBundleを使うことになってしまった人たち向けに、AssetBundleの仕組みや使い方、注意点などについて学び、完全に理解しましょうという記事になります。
想定する読者層
- AssetBundleなんもわからん人
- AssetBundleを雰囲気でやっている人
- AssetBundleと向き合う覚悟ができた人
- AssetBundleを完全に理解したい人
- オレオレAssetBundleManagerを作りたい人
- Addressable Asset Systemの利用を検討している人
AssetBundleの概念や必要性についてまだ理解していない方は、前回の記事から読むことをオススメします。
→ 今更誰も教えてくれない、Unityにおけるリソース読み込みについての基礎知識
この記事で分かること
現時点(Unity 2018.2)における、以下の最新の知見が得られます。
- AssetBundleの(より深い)仕組み、動作仕様
- AssetBundleの仕様上の注意点
- AssetBundleを使うにあたって考慮すべき事柄
- 既存のライブラリについての情報
AssetBundleの仕組み
AssetBundleの仕組みについては前回簡単に説明したが、今回はもう少し深掘りしていく。
AssetBundleは、簡単に言えば「Resourcesではアプリのビルド時に行っている処理を事前に行っておく事により、実行時に外部からアセットがロードできるようになる」という仕組み。
AssetBundleからのアセットのロードはメタ情報が肝となっている。そこで、実際にロード時にどのようにメタ情報が取り扱われているか、例を挙げて説明する。
AssetBundleをロードした時の実際の内部動作について
AssetBundleをロードした際、そのAssetBundleが「ディスク上に存在するかしないか」(ディスク上からロードするかどうか)で挙動が変わる。
それぞれのパターンについて解説を行う。
補足:UnityNativeメモリとMonoメモリについて
以下の解説で「UnityNativeメモリ」と「Monoメモリ」という単語が出てくる。簡単にまとめると、以下のような違いがある。
- Monoメモリ:私達が書くC#側で管理されているメモリ領域。プロファイラで見るとMonoと表記されている部分。GCによって不要になったメモリは自動的に解放される。(厳密にはIL2CPP環境の場合Monoメモリと言うのは正しくない気がする)
- UnityNativeメモリ:C#管理外の、Unityのネイティブ実装部分が使うメモリ領域。プロファイラで見るとUnityと表記されている部分。ResourcesやAssetBundleからロードしたアセットはここに読み込まれる。解放するには明示的にリソースをアンロードするか、Resources.UnloadUnusedAssetsなどを呼び出す必要がある。
AssetBundleをディスク上からロードする場合
AssetBundleがディスク上からロードされる条件は以下。
- AssetBundle.LoadFromFileを使った場合
- UnityWebRequestを使ってDL&キャッシュした場合
この場合、AssetBundleのロード段階ではメタ情報のみがロードされ、アセット本体はLoadAssetされたタイミングで初めてロードされる。
例
例えばAssetBundle.LoadFromFileを使ってAssetBundleをロードしたとする。
その段階ではAssetBundleのメタ情報のみがUnityNativeメモリ上にロードされる。
LoadFromFileの返り値となるMonoメモリ上にあるAssetBundleオブジェクトは、UnityNativeメモリ上にあるメタ情報への参照を持っているようなイメージ。
var assetBundleA = AssetBundle.LoadFromFile(path);
ここで、assetBundleAからテクスチャをロードする。すると、その段階で初めてディスク上からアセットをUnityNativeメモリ上に読み込む。
var textureA = assetBundleA.LoadAsset<Texture2D>("textureA");
また、この状態でもう一度同じアセットをロードすると、既にメモリ上に読み込まれているアセットの参照を返す。
- ディスクIOが発生しない
- アセットがメモリ上に重複しない
var textureA2 = assetBundleA.LoadAsset<Texture2D>("textureA");
この状態でAssetBundle.Unload(false)を呼ぶと、AssetBundleのメタ情報がアンロードされる。
これ以降、assetBundleAからLoadAssetすることはできなくなる。
assetBundleA.Unload(false);
残ったアセットは、Texture2Dからの参照が切れた後にResources.UnloadUnusedAssetsを呼び出すなどで解放することができる。
ちなみに、Unload(true)の場合、読み込み済みのアセットまで強制的に解放される。
この場合、ゲーム内で表示中のTextureはmissing状態になる。
assetBundleA.Unload(true);
AssetBundleをメモリ上からロードする場合
AssetBundleがディスク上からロードされない場合(上記以外の場合)はメモリ上からロードされていると言える。
この場合、AssetBundleのロード段階でメタ情報と含まれるアセット全てがUnityNativeメモリ上にロードされる。
例
WebからDLしてきてキャッシュしない場合は、そのままメモリ上にAssetBundleが展開される。
// バージョン等を指定しなければキャッシュされない
var request = UnityWebReqeust.GetAssetBundle(url);
// 例によってWebRequestはawait可能にしてあることとする
await request.SendWebRequest();
var assetBundleA = DownloadHandlerAssetBundle.GetContent(request);
LoadAssetすると既にロード済みのアセットへ参照が貼られる。
assetBundleA.LoadAsset("textureA");
その他はディスク上から読んだ場合と同じ。
AssetBundleの仕様上の注意点
メタ情報は明示的にUnloadしないと解放されない
どういうことかというと、AssetBundle.Unloadを呼び出さなかった場合、C#側でAssetBundleオブジェクトが解放されても、UnityNativeメモリ上のメタ情報は残り続ける。
メタ情報はUnityNative側なためSystem.GC.Collect();
でGCを明示的に発生させてももちろん解放されず、リソースとは別の扱いのため、Resources.UnloadUnusedAssetsでも解放されない。
この場合、AssetBundle.UnloadAllAssetBundlesで全てのメタ情報をUnloadするしか解放する手段が無くなってしまう。
メタ情報が残り続ける事によって、メモリ使用量を圧迫する他、次の問題にも繋がる。
ロード済みのAssetBundleをロードしようとするとエラーになる
例えば以下のコードは確実にエラーになる。
var assetBundle = AssetBundle.LoadFromFile(path);
// 2回目にロードするとエラー
var assetBundle2 = AssetBundle.LoadFromFile(path);
正確に言えば、メタ情報がロード済みのAssetBundleをもう一度ロードしようとするとエラーになると言える。
メタ情報の同一性の判定がどのようにされているかは不明(AssetBundle名あたりかな…?)。
メタ情報がバッティングしなければエラーにならないので、つまり次のコードならばエラーにはならない。
var assetBundle = AssetBundle.LoadFromFile(path);
// メタ情報をUnload
assetBundle.Unload(false);
var assetBundle2 = AssetBundle.LoadFromFile(path);
但し、もう一つ注意点として、「再びロードされたAssetBundleから同じアセットをロードすると、メモリ上に同じアセットが二重にロードされてしまう」という点がある。
具体的には、以下のようなイメージ。
var assetBundle = AssetBundle.LoadFromFile(path);
var texture = assetBundle.LoadAsset<Texture2D>("textureA");
assetBundle.Unload(false);
var assetBundle2 = AssetBundle.LoadFromFile(path);
var texture2 = assetBundle2.LoadAsset<Texture2D>("textureA");
assetBundle2.Unload(false);
同じtextureAをロードしているが、一度メタ情報をUnloadした上で再び読み込んでいるため、同じテクスチャのデータがメモリ上に重複してロードされてしまい、メモリを無駄に消費してしまう。
参考:AssetBundle usage patterns – Unity
この仕様をクリアするため、ロード済みのAssetBundleオブジェクトを管理する仕組みが必要となる。
簡単に言えば、AssetBundleのロードをラップするためのクラスを用意して、未ロードならWebからDLしてきてロードし内部のDictionaryに格納、ロード済みならDictionaryに格納してあるAssetBundleオブジェクトを返す、というような実装になる。
AssetBundle同士に依存関係が存在する場合
例えば、PrefabとPrefabが参照しているテクスチャをそれぞれ別のAssetBundleとしてビルドした場合、AssetBundle同士に依存関係が発生する。
この時、LoadAssetする前に依存しているAssetBundle(のメタ情報)を全てロードしておく必要がある。
例えば、「AssetBundleAに含まれるprefabA」が「AssetBundleBに含まれるtextureB」と「AssetBundleCに含まれるtextureC」の参照を持っているとする。
この時、AssetBundleAはAssetBundleBとAssetBundleCに対して依存関係を持っていることになる。
そのため、以下のようにして事前に全てのAssetBundleをロードしておく必要がある。
var assetBundleA = AssetBundle.LoadFromFile(pathA);
var assetBundleB = AssetBundle.LoadFromFile(pathB);
var assetBundleC = AssetBundle.LoadFromFile(pathC);
var prefab = assetBundleA.LoadAsset<GameObject>("prefab");
ロードする順序は特に問われない。
この仕様をクリアするため、AssetBundle同士の依存関係を保持したリストと、それを利用して自動的に依存関係のあるAssetBundleをロードするような仕組みが必要になる。
AssetBundle同士の依存関係は、ビルド時に生成されるAssetBundleManifestファイルから取得することができる。
そのまま実行時にAssetBundleManifestファイルを使っても良いが、これだけでは他の要件を満たせない(後述)ため、独自にjsonなどにシリアライズしたファイルを用いるのが一般的1。
また、他のロード済みAssetBundleから依存されているAssetBundleが不用意にUnloadされないようにする仕組みも必要となる。
例えば、以下のような事例が考えられる。
// AがBとCに依存している
var assetBundleA = AssetBundle.LoadFromFile(pathA);
var assetBundleB = AssetBundle.LoadFromFile(pathB);
var assetBundleC = AssetBundle.LoadFromFile(pathC);
// Aからprefabをロード
var prefab = assetBundleA.LoadAsset<GameObject>("prefab");
// ~~~ //
// Cからテクスチャをロード
var textureC = assetBundleC.LoadAsset<Texture2D>("textureC");
// 不要だと思ってUnloadする
assetBundleC.Unload(false);
// ~~~ //
// 再びロードしようとするとエラーになる
var prefab = assetBundleA.LoadAsset<GameObject>("prefab");
これについては参照カウントを用いて管理する方法が一般的。LoadとUnloadをラップし、Load時にカウントを+1、Unload時に-1し、カウントが0になった段階で実際にUnloadを呼び出す。
Unity公式のデモ実装が参考になる。
ロード時のMono(C#)側のメモリ確保について
昔はAssetBundleをWebからDLする際はWWW.LoadFromCacheOrDownloadを使っていたが、これを使うとMono(C#)側のメモリが使われてしまうという問題があった。Monoメモリは一度増大すると予約済みとなってしまい、アプリ終了までOSに返還されない。
UnityWebReqeust(+DownloadHandlerAssetBundle)を使えばUnityNativeメモリ側で完結するため、Monoのメモリ領域が不要に確保されることは無い。
今ではWWWクラスは廃止(いつからか分からないが内部的にはUnityWebRequestに投げている)されているため、基本的に気にする必要はない。
但し、AssetBundle.LoadFromMemoryを使う場合は勿論Mono側にAssetBundleのデータをbyte[]で確保する必要があるため、その分メモリ領域が増大する。
- 参考
その他の要件
実際にAssetBundleを使うにあたっては、以下のような要件についても考慮が必要。
AssetBundleのディスクキャッシュ
AssetBundleをWebサーバー上に配置してロードする事を考えた時、毎回サーバーからDLしてくるのは明らかに通信量的に不味いため、一度DLしたものはディスク上にキャッシュしておきたいという要件が発生する。
そこで、UnityWebRequestには標準でAssetBundleをキャッシュするための仕組みが備わっている。
それについては以下の記事に詳細にまとめているため、ここでは割愛する。
[Unity 2018.2] AssetBundleのキャッシュを完全に理解する – Qiita
ここでさらに発生する要件が以下。
- 改竄検出のためのAssetBundleのCRCのリストが必要
- キャッシュされているものと比較してDLが必要かどうか判定するためのAssetBundleのバージョン情報のリストが必要
- 古いバージョンのキャッシュを削除する機能
バージョン情報についてはAssetBundleManifestから取得できるハッシュ値が使えるが、CRCについてはAssetBundleManifestから取得することができない。
AssetBundleのビルドの簡略化
前回の記事では、スクリプトでAssetBundleをビルドする簡単な例を挙げた。(以下再掲)
var builds = new List<AssetBundleBuild>();
// AssetBundle名とそれに含めるアセットを指定する
var build = new AssetBundleBuild();
build.assetBundleName = "Hoge/texture";
build.assetNames = new string[1] { "Assets/AssetBundleResources/Hoge/texture.png" };
builds.Add(build);
// 成果物を出力するフォルダを指定する(プロジェクトフォルダからの相対パス)
var targetDir = "AssetBundle/Android";
if (!Directory.Exists(targetDir)) Directory.CreateDirectory(targetDir);
// Android用に出力
var buildTarget = BuildTarget.Android;
// LZ4で圧縮するようにする
var buildOptions = BuildAssetBundleOptions.ChunkBasedCompression;
BuildPipeline.BuildAssetBundles(targetDir, builds.ToArray(), buildOptions, buildTarget);
しかし、上記のようにAssetBundleBuildの配列を構築する処理を手書きするのは効率が悪い。
そこで、アセットのパスから正規表現を用いてAssetBundle名を決定付けるような実装が必要になる。
これについては、AssetGraphという便利なライブラリを使うのが良い。(後述)
AssetBundleとアセットの対応関係の解決
AssetBundleからアセットをロードする際、当然まずはロードしたいアセットが含まれているAssetBundleをロードし、そのAssetBundleからアセットをロードする必要がある。
これを愚直に書けば以下のようなコードになる。
// AssetBundleをロード
var request = UnityWebReqeust.GetAssetBundle(url);
await request.SendWebRequest();
var assetBundle = DownloadHandlerAssetBundle.GetContent(request);
// アセットをロード
var texture = assetBundle.LoadAsset<Texture2D>("Assets/AssetBundleResources/Hoge/texture.png");
が、アセットをロードするためだけに「アセットがどのAssetBundleに格納されているか」「AssetBundleの配置先URLはどこか」を実装時に考えて書かないといけないのは難しく、非現実的である。
そのため、アセットのパス(=アセットを一意に特定するための文字列)から、そのアセットが格納されているAssetBundleとそのURLを特定し、自動的にDLする仕組みが必要になる。
以下のように書けると理想的。
var texture = AssetBundleManager.LoadAsset<Texture2D>("Assets/AssetBundleResources/Hoge/texture.png");
AssetBundleシミュレーター
AssetBundleを使うことを前提にしてしまうと、アセットを変更した際に毎回AssetBundleをビルドし直してサーバー上に反映する必要がある。これでは開発時には若干不便になってしまう。
そこで、ResourcesやAssetDatabase.LoadAssetAtPathを代替に使うことで、ビルドせずに簡易的にシミュレーションできるような仕組みがあると便利になる。
CDNの反映遅延への対処
AssetBundleをWebで配信するにあたって、それなりの規模のゲームであれば、高トラフィックに耐えるためにCDNを用いるのが一般的である。
しかし、CDNを使う場合、その特性上から必ず反映遅延が発生する。つまり、AssetBundleを上書き更新した場合、CDNに反映されるまでの間、CDNにキャッシュされた更新前のAssetBundleがロードされる可能性がある。これは予期せぬ不具合に繋がる可能性がある。
そこで、古いキャッシュがロードされないようにするため、以下のような対応が必要になる。
- AssetBundleを上書き更新しない(アップロード時にファイル名の末尾にハッシュ値を付けるなど)
- クエリによってキャッシュをコントロールする(CDN側でクエリごとにキャッシュされるように設定し、アプリ側からはDL時にクエリにハッシュ値を入れるなどする)
AssetBundleのダウンロードサイズの表示について
App Storeの審査ガイドラインによって、追加リソースをDLする時には事前にダウンロードサイズを開示する義務があると定められている。
そのため、AssetBundleのダウンロードサイズを取得する仕組みが必要となる。
参考:新 App Store 審査ガイドライン 翻訳&差分ガイド 2018年6月号 – Qiita
AssetBundleManager(仮)の要件まとめ
上記のことから、AssetBundleを使う際には、AssetBundleManager(仮)のような便利クラスが必須と言える。
まとめると、AssetBundleManagerに求められる要件は以下。
- ロード済みのAssetBundleオブジェクトを管理する仕組み
- AssetBundle同士の依存関係を保持したリストと、それを利用して自動的に依存関係のあるAssetBundleをロードするような仕組み
- キャッシュの更新判定をするためのバージョン情報、改竄検出のためのCRCを管理するための仕組み
- アセットのパス(=アセットを一意に特定するための文字列)から、そのアセットが格納されているAssetBundleとそのURLを特定し、自動的にDLする仕組み
- ResourcesやAssetDatabase.LoadAssetAtPathを代替に使うことで、ビルドせずに簡易的にシミュレーションできるような仕組み
- AssetBundleのダウンロードサイズを取得する仕組み
上記の要件を満たそうと思うと、大体以下のような実装になる。
- アセットとAssetBundleの対応関係、AssetBundle同士の依存関係、バージョン情報(ハッシュ値)、CRCを格納したファイルを最初にロードする
- アセットのロード時はアセットのパス(と型)を指定すれば、上記データを元によしなに処理してくれる
既存のライブラリについて
AssetBundle関連の既存のライブラリについて紹介していく。
AssetBundleManager
Unity-Technologies / AssetBundleDemo — Bitbucket
Unity謹製のAssetBundleManagerの実装デモ。WWWクラスを使っていたりして若干レガシー。また既にメンテ停止がアナウンスされている。実装の参考にするのは良いが、そのまま使うことはオススメしない。
Autoya
sassembla/Autoya: thin framework for Unity.
AssetBundleの他に認証系やその他諸々の便利な機能が入ったライブラリ。
概ね要件を満たしているが、見た所恐らく以下の機能が無い。
- 依存関係がある際の参照カウンタによるUnload管理
- ResourcesやAssetDatabase.LoadAssetAtPathを用いたシミュレーション機能
- 古いキャッシュのみを削除する機能
AssetGraph
Unity-Technologies / AssetBundleGraphTool — Bitbucket
AssetBundleのビルドを効率化してくれるツール。
ノードを構築することで、フォルダ構造に応じて柔軟にAssetBundle化の設定を行うことができる。
詳しくは別途紹介記事を書く予定。
AssetBundleBrowser
Unity の Asset Bundle Browser ツール – Unity マニュアル
Unity2018以降ならPackageManagerから導入することが可能。
AssetBundleのメタ情報を見るのに便利。
ビルドの機能は一応付いているが、AssetGraphを用いる方がより柔軟に設定ができて良い。逆にAssetGraphほどの柔軟性が必要無ければこれで十分でもある。
Addressable Asset System(AAS)について
上記のAssetBundleManager(仮)の要件を満たしてくれる(とされている)のが、皆さん待望のAddressable Asset Systemです。素晴らしいですね!
この記事の内容を理解した上であればAASが何をしてくれるのか・何故便利なのか、というのが分かるかなと思います。逆に理解していないとどう使ったらいいのかもよく分からない可能性があります。
AASについては以前解説記事を書いたので、これが参考になるかと思います。(ちょっとバージョンが古いですが、大枠は変わっていないはず)
Addressable Assets Systemを完全に理解する – Qiita
まだまだ開発途上といった雰囲気ですが、暖かく見守っていきたいですね。
おわりに
長くなりましたが、以上でAssetBundleを使うに当たって必要な知識は一通り網羅できたかなと思います。AssetBundle、完全に理解した。
正直言って複雑で面倒くさいと思います。が、そもそもWebからの外部リソースの読み込みというのは本質的に難しい問題だと思います。個人的には、一概にAssetBundleが悪いとは思いません。(アップデートによって大分改良されてきたというのもありますが)
参考資料
- アセットバンドルの基礎 – Unity
- Addressable Assets Systemを完全に理解する – Qiita
- [Unite 2016] 学校では教えてくれないアセットバンドル
- DownloadHandler の作成 – Unity マニュアル
- AssetBundle.LoadFromFileとLoadFromMemoryの挙動の違いについて – Qiita
- [Unity 2018.2] AssetBundleのキャッシュを完全に理解する – Qiita
以下は独自AssetBundleManagerを作った事例の紹介。
- 【Unite 2018 Tokyo】『CARAVAN STORIES』のアセットバンドル事例
- 複雑化するAssetBundleの配信からロードまでを基盤化した話【CEDEC 2017】 | CyberAgent
-
Addressable Asset SystemでもAssetBundleManifestは使わず独自のクラスをJSONにシリアライズして使っている。これはコンテンツカタログと呼ばれている。 ↩
- ActionCableをwebsocket APIとして使ってUnityと通信する
- [Unity] 一定の時間間隔で処理を実行する方法まとめ(時間制御)
- Unityでスターウォーズしてみた
- UnityでVisualStudioCodeを使う (2015年12月時点)
- 【Unity】Unity with Vocaloidで「どれみ」を歌わせるまで
- [Unity] サークルプログレスバーをシェーダで書いてみる
- Gaiaで地形生成してみよう
- Unityでスコアなどのデータを保存する方法(PlayerPrefsのまとめ)
- UnityのResourcesの使い方
- Unity 5.3 & Web GL/HTML5 セミナー by Unity & Mozilla メモ
- 配列(IEnumerable)の中からランダムで一つ返却するLinq拡張
- 重み付きランダム
- UnityEngine.Loggerを使ってみる
- [Unity] C#とObjective-Cの連携まとめ
- AVPro Windows Media マニュアル飛ばし読み
- [Unity] 空気抵抗のある空間での斜方放射で、ある地点に到達するための初速度を求める。
- Unity5.3からUnit Tests Runnerが組み込みになった
- Unityでラスタースクロール
- ブラーシェーダ作ってみた
- 中の人(二次元)になる方法【FaceRig × Live2D × Unity × OBS × AVVoiceChanger × 気合】
- Unityでフィルター処理してみた
- 超使えるフリーサウンド素材集 OculusAudioPack01を効果的に使ってみよう
- Unityからスマホ画面の向きの固定・解除(iOS・Android共通)
- 【UnityAsset】LitJson Ruler
- 私はいかにしてUnityのシリアルポートで悩むのをやめ、MQTTでLive2D少女を操ることになったか
- C#での多次元配列・ジャグ配列の初期化 覚え書き
- uGUIでドラッグについてちょっとだけ詳しく
- 【Unity】Unity 5.3 新機能メモ
- 【Unity】CSVとScriptableObjectどちらの形式でマスターデータを管理したほうが読み込み速度が高速になるか検証しました
- uGUIのScroll Viewをはじめてみる
- MonoBehaviourを継承したシングルトンの実装
- uGUIのScroll ViewでGrid
- 【Unity】一度読み込んだリソースをキャッシュする場合としない場合で読み込み速度にどれくらい差が出るか検証しました
- Unity で Animation を作り込んだ後の Hierarchy 変更
- UnityでRenderer毎にShaderPropertyを制御する
- UE4でSD版ユニティちゃんを動かしてみる ー Part1 ユニティちゃんをUnrealEngineへお出迎え(インポート)ー
- (2017/4/26 追記修正)Google Cardboard SDK for Unity v0.6の3Dサウンド (Spatial Audio)と視線マーカー
- スクリーンショットの撮影完了したらほげほげするコルーチン
- uGUIのScroll Viewでページスクロール
- UnityからSVNを操作するエディタ拡張を作ってみた
- UnityでMQTTライブラリを使って、Milkcocoaに接続、さらにiPadでも動かす
- Unity Shaderの基礎 part 1
- UnityのSpritePackerとAssetBundleを併用する。
- メモ: Unity 5.3 の In-App Purchasing
- Unity VRSamplesを読む
- Unity参考サイト:メモ
- Swift 開発者が Unity の勉強を始めたの巻
- 【Unity】 UnityEditorの時のみDebug.Logを出す方法
- yield return www みたいに書きたい
- UnityのText Mesh Proアセットで日本語を使うときの手順
- UnityIAPで出来ることメモ
- SmartAR for Unityの補足情報とプラクティス
- Unity iOSビルド時にURLスキームを追加するだけのPostProcessBuild
- Unity5 ShaderVariantCollectionを使用しShaderのPreloadを行う
- 【Unity】エディター拡張で木構造を表示させる
- 【エディター拡張】UnityEditor上で動くドット絵エディタを作ってみた
- UnityでLive2Dの複数モーション再生
- uGUIでビットマップフォントを使ってみよう
- LoopBackをサクッと触ってみた(環境構築からAPIまで)+おまけでUnity
- Unity Shaderの基礎 part 2
- UnityでC#で数式パーサーを自作してみた
- グローバルゲームジャムでクラス設計をやったらスムーズに開発が進んだ話
- Debug.Log() や Instantiate() などの速度を計測してみる
- Unity 半透明描画するサーフェースシェーダー
- Unity 網掛けシェーダー
- Unity(C#)超絶初心者の開発メモ
- Unity Unlit/Transparent でアルファ値を外から設定したいシェーダー
- 【エディター拡張】UnityEditor上で数学グラフをプロットさせてみた
- Unityプログラミング基礎 (変数からclassまで)
- DeNA Tech Con 参加セッションまとめ(Unity)
- GGJ2016で作ったゲームにBehaviorTreeを使ってAIを搭載した話
- Unity3D-簡単なゲームを作りながら学ぼう①
- GetComponent()の速度を改めて計測してみる
- “1000m Zombie Escape!”におけるゲームフロー制御方法
- UnityでGooglePlayServicesを入れるにはPlayServicesResolver(unity-jar-resolver)が便利
- 【Unityエディター拡張】ファイルの中身をバイナリで表示するEditorWindowを作ってみた
- UnityのPBXProjectを今更少しだけ触ってみたのでメモ((φ(・д・。)
- 【Unity】pngファイルを読み込み同サイズのTexture2Dを生成する
- Unity用Pub/Subライブラリ”Kuchen”作ってみた
- Unity初心者勉強サイトまとめ
- (たぶん)世界初! VR上でのLT会、VRごっちゃにLT会 in バーチャル#1に参加しました
- UnityでVuforiaを使ってLive2DとARの可能性を感じる
- UnityのWebGLで書きだしたゲームをGitHubを使って公開する
- オブジェクト生成の仕方 Instantiate
- Unity(x86/x64)でWindowsメッセージを受け取る方法
- Unity uGUIのTextをα値で1文字ずつ表示
- IL2CPPでLINQのAOTエラーが結構改善されたような気がする
- LeapMotion Orionでキャラクターの手を動かす
- 【Unityシェーダー】よく使うシェーダー関数はcgincを作ると便利
- UnityでSmartARを使ってLive2Dを表示してみる
- 2Dのちょっとした演出に使えるShaderとか
- [Unity]GLSLをiPadProで表示する備忘録
- リテンション風なプッシュ通知配信ができるUnityアプリを作ってみた(Android)
- 自分で作った3DモデルをUnityとKinect v2を使って動かすまで
- [Unity]声優ハッカソン参加してきました「彼氏力お化け屋敷」
- C#でフォルダ内のすべてのファイルを取得してツリーを記述する処理書いたんで自分用にメモ((φ(・д・。)
- Unityでタメになったリンク集
- RealsenseSDKとWEBカメラの顔認識結果をUnityで利用する
- 【Unity】理想的な陰影をつけるトゥーンシェーダ
- RealsenseSDKとWEBカメラでキャラクターになりきる
Androidに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。
Bitcoinに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。
Goに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。
JavaScriptに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。
Pythonに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。
Rubyに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。
Scalaに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。
Swiftに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。
Unityに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。
Wordpressに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。
機械学習に関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。