テラシュールブログ

旧テラシュールウェアブログUnity記事。主にUnityのTipsやAR・VR、ニコニコ動画についてのメモを残します。

【Unity】Scene上に構築したステージを、Entity群に変換してECSで利用可能にする「SubScene」

f:id:tsubaki_t1:20190307014827j:plain

ECS 0.0.12 preview 26から、GameObjectとComponentをEntity&ComponentDataに変換する機能が追加されました。まずは、この中で最も便利であろうSubSceneについて紹介します。

GameObjectをECS向けに変換する

preview26でGameObjectConversionUtility.ConvertGameObjectHierarchy(...)GameObjectConversionUtility.ConvertScene(...)等のAPIが追加されました。このAPIは特定のコンポーネントを対応するComponentDataに変換するといった機能を持ています。例えば下のような感じ。

  • TransformをPositionRotationに変換する
  • MeshRendererとMeshFilterをRenderMeshに変換する

f:id:tsubaki_t1:20190306232854j:plain
GameObjectをEntityへ変換

これはPrefabからEntityや、シーンに配置したGameObjectからEntity、SceneまるごとEntityといったレベルでの変換が可能です。

当然、変換なので変換先のComponentDataが無い物は変換出来ない為に完全簡単に移行という訳には行きませんし、現状、ライトマップ等のSceneに紐づく情報は剥がれます。が、Unityエディターのワークフローでシーンにオブジェクトを配置し、ゲームで利用する事が可能になるのでECSを利用する上では、使いやすくなりそうです。

f:id:tsubaki_t1:20190306233151j:plain
StealthデモのステージをEntity群に変換して表示

ということで実際にScene上のステージをEntity群に変換して利用して見るわけですが、そこで既に便利な機能「SubScene」があったので、そちらを使います。

SubScene

SubSceneの説明によると、機能は大体こんな感じみたいです。Unityがシーン展開に使用しているようなデシリアライズとは異なり、ECSのメモリ構造を概ねそのまま展開して配置出来るので楽という発想でしょう。

シーンを保存する時、UnityはSubSceneをネイティブのバイナリフォーマットに変換します。このフォーマットはメモリに対応していて、RAM内のデータを少し変更するだけでロードもしくはストリーミングが可能です。このフォーマットは大量のEntityをストリーミングするのに理想的です。

いくつかのロードが超早いと評判のゲームは、このアプローチを使っていると聞いていたと聞いているので、とても良さそうです。

実際に使ってみる

【動作環境】

  • Unity 2019.1 b5(b4以前はSubSceneの機能が正常に動作しないかもしれません)
  • Entity 0.0.12 preview
  • Hybrid Renderer
  • Windows 10

1. 選択したオブジェクトのサブシーン化

シーンにあるオブジェクトをサブシーンにします。

オブジェクトを選択して 右クリック→New SubScene from Selection をクリックすると、指定した範囲内のオブジェクトをサブシーンにします。Stageのようなオブジェクトが既に存在し、Colliderとは別に配置されている場合には、こちらのほうがやりやすいかもしれません。

よくあるGameObjectをサブフォルダのように使うが如く、シーンを階層化出来ます。SubSceneの下にSubSceneを配置するなども可能です。

https://user-images.githubusercontent.com/1644563/53929490-3a2ed100-40d1-11e9-83c5-f07ff6d06a9d.gif

シーンファイルは、親シーンと同名のフォルダ以下に配置されるみたいです。

なお、基本的に動かさないオブジェクトにはStatic Optimize Entityを追加します。これを追加してあると、描画時に軽くなります(staticフラグが付いてるなら自動で設定してくれても良いのに)

f:id:tsubaki_t1:20190307125536j:plain
動かさないならStatic Optimize Entityを追加

2. SubSceneの編集

SubSceneに持っていっても、編集は可能です。

Editボタンを押せば、Entity & ComponentDataの代わりにGameObject & Componentが表示され、編集することが出来ます。この状態になると、普通のシーンと同様の操作系になります。

https://user-images.githubusercontent.com/1644563/53894988-65cf9e00-4074-11e9-9352-e3c3744e807b.gif

3. SubSceneをEntity群に変換

Entity群に変換します。

変換するには、SubSceneのRebuild Entity Cacheボタンを押すだけです。

既存のシーンの場合は、SceneAssetに追加すれば変換が可能です。

f:id:tsubaki_t1:20190307000032g:plain
SubSceneの追加

この手順が完了すると、Assets/EntityCache/ResourcesフォルダとStreaming Assets/EntityCacheフォルダにEntityをシリアライズしたファイルが生成されます。

PrefabはSharedComponentDataをシリアライズした情報、あとはSceneHeader(シーン情報とシリアライズしたバイナリを紐付ける)といった感じでしょうか。

また変換後でもEditボタンで編集が可能です。

f:id:tsubaki_t1:20190307001209j:plain
キャッシュをビルドすると出来る成果物

これでゲームを実行すると、Sceneから変換したEntity群がロードされます。

f:id:tsubaki_t1:20190307003219p:plain
実行結果

SubSceneに変換出来ない場合

変換出来ない場合、同一のコンポーネントが複数セットされている事が考えられます。

というのも、ECSは仕組み上「一つのEntityに同じComponentを複数登録できない」という制限があります。なので、Colliderなど一つのオブジェクトに複数のコンポーネントを登録しているものを排除します。

また変換出来ないEntityの情報は尽く剥がされます。これはスクリプトで拡張が出来ますが(Renderer等もHybrid Rendererパッケージで拡張されて変換可能になっている)無いものは変換出来ません。

ArgumentException: It is not allowed to have two components of the same type on the same entity. (BoxCollider and BoxCollider)と出ます。

f:id:tsubaki_t1:20190307125435j:plain
複数のBoxColliderがある場合、変換出来ない

既存のシーンを変換する

上でもチラっと書きましたが、New SubScene from Selectionを使用してSceneを作らない場合でも、SubSceneのSceneAssetにSceneを適応すればSubSceneとして扱えます(変換も可能です)

ただし、その場合は一旦シーンを開き直さないとSubSceneをSceneと認識しませんでした。

f:id:tsubaki_t1:20190307000358j:plain
SubSceneに既存のSceneを使う

その他機能

f:id:tsubaki_t1:20190307003545j:plain
SubSceneの中にSubSceneを配置

また、キャラクターのコンポーネント情報がどうなっているのか等を確認したい場合、LivelinkでEntityの情報をGameObjectに反映させるという事ができそうな感じがあります。

f:id:tsubaki_t1:20190307005052j:plain
Livelink

MeshRendererやLODは使えないの?

MeshRendererやLOD以外でも、独自スクリプトでも差し替えは可能そうです。詳しくはこちら

tsubakit1.hateblo.jp

感想

まだ機能が限られていますが、現状でも「ステージの大雑把な情報やキャラクターはGameObject & Component」「細かく大量にあるステージ上の小物はEntityで制御」のような使い分けができそうです。

またSubSceneで一つのシーンを複数で分割し、同時編集するといった事も今までのマルチシーン構想よりスムーズにできそうです。特にGameObjectをフォルダのように利用して階層分けしていた場合、より高速でスムーズなアプローチとして期待出来るかもしれません。

ところでSubSceneは普通に現行のGameObjectベースのシーンシステムに欲しいんですが…

関連

データをロードする部分は大体コレ

tsubakit1.hateblo.jp

SubSceneのサンプル

github.com