【Unity】Hybrid ECS + MeshInstanceRenderer

前回でHybrid ECSを使ってUpdate() 部分をマルチスレッド化してみた。

やはり描画負荷が高いよね。
MeshInstanceRenderer を使いたくなる!!
調べても使い方が難しく意味が分からん!(じゃぁこの投稿は何だよw

MeshInstanceRenderer

試しにGameObject アタッチしメッシュやマテリアルを設定しても描画してくれないよね。
理由はTransformの情報がない(?)かと思います。

じゃ、ネットでMeshInstanceRendererについて調べたら、

var manager = World.Active.GetOrCreateManager<EntityManager>();
var archetype = manager.CreateArchetype(...); // Position とか Rotationとか
var entity = manager.CreateEntity(archetype);
var look = ... // MeshInstanceRenderer
manager.AddSharedComponentData(entity, look);

と、今まで使って来なかった書き方をヒットします。

やりたいこと

従来の概念をあまり捨てないでどうやってMeshInstanceRendererを使うか?
(ECSの考えにあってるかどうかわからんが) 書きました。
gist.github.com

上記のコンポーネントをGameObjectにアタッチすると、

PositionComponent
RotationComponent
MeshInstanceRendererComponent
CopyTransformFromGameObjectComponent

を勝手にアタッチしてくれます。
なぜか ScaleComponent の情報がコピーしてくれないので、今回は無視する!

Awake() 時に、
MeshFilter と MeshRenderer があれば
情報を取得し MeshInstanceRenderer にセットする
ついでにMeshRendererも無効に!

実行結果

f:id:kou_yeung:20181108165006g:plain
160FPS 以上になりました。
これぞ Hybrid ECS!!

次回:
【Unity】Hybrid ECS から Pure ECS へ - 浮遊島

【Unity】Hybrid ECS

Entity Component Systemを使いたいが、Pure ECSの学習コストが高い!
大量なオブジェクトのUpdate()だけスレッドで処理したく、
Hybrid ECSを試しました。( Unity バージョン:2018.2.10f1 )

準備

Scripting Runtime Version 設定

ECS を使うために、.NET4.x に設定する必要があります

Package をインストール

Unityエディタで [Window] -> [Package Manager] を開き [All] タブを選択し
以下Package をインストールする

・Entities (0.0.12-previre.19)

オブジェクトを大量生成する

プレハブを指定して大量なオブジェクトを生成するクラスです。
生成したら座標や向きを設定する
※ECSと関係ないので実装詳細は飛ばしても問題なし!

gist.github.com

動かせるスクリプトを作成する

今までのやり方でオブジェクトを動かせます
gist.github.com

f:id:kou_yeung:20181107165600g:plain
3xFPS ぐらい

Hybrid ECS化

プレハブを選択し Add Component から "Game Object Entity" をアタッチする。
あとは Move.cs を修正する

gist.github.com

ECS にしたが、実行してもあまり差が感じないよね。
原因は更新部分がまだマルチスレッドしていません。

Job で マルチスレッド

IJobParallelForTransformを実装し並列処理を行う。
gist.github.com

f:id:kou_yeung:20181107165316g:plain
5xFPS ぐらいになりました。

最低限のマルチスレッド処理ができました

Unity 従来の使い方でマルチスレッド化できたので
Hybrid ECSはとても手軽で魅力的ですね。

次回:
【Unity】Hybrid ECS + MeshInstanceRenderer - 浮遊島

【Unity】ボタン作成時のカスタム拡張

UnityEditor のメニューに [GameObject/UI/Button] でボタンを作成したが、
プロジェクトによってはカスタムのコンポーネントを追加したり、
デフォ画像を設定したりしたいわけですが、

毎回手動でやると面倒ですよね!!!!

UnityEditor.UI.MenuOptions というクラスをHACKしてコールバックを追加してみました。

gist.github.com

使い方

例: 自前の ButtonSE というコンポーネントを追加したい!
gist.github.com

とても手軽になりました!

MenuItem 重複による警告

Cannot add menu item 'GameObject/UI/Button' for method 'MenuOptions.AddButton' because a menu item with the same name already exists.

上記の警告が表示されるので、気になる場合

// MenuOptions.cs
[MenuItem("GameObject/UI/Button", false, 2001)]
↓
[MenuItem("GameObject/UI/Button/Create", false, 2001)]

に変更すれば警告は消えます。(その代わりにメニューの階層が深くなりますorz)

OverrideXml

皆さん~
C#XML を解析時、どんなシリアライザーを使いますか?
おそらく真っ先にXmlSerializer クラス (System.Xml.Serialization) にたどり着くでしょう。

だけど、XmlSerializerを使うと、
XmlElement クラス (System.Xml) とか
XmlAttribute クラス (System.Xml) とか
クラスやメンバーに属性を付ける必要があります。

場合によっては、クラスに編集を加えることができないし
いわゆる「非侵入型シリアライザー」がほしいです。

今年に面白い子「OverrideXML」 と出会いましたよ。
日本語の記事はほぼないので、ぜひ皆さんに紹介したいですね。

OverrideXML とは

XmlAttributeOverrides クラス (System.Xml.Serialization) を使うと、
XmlSerializer も非侵入型シリアライズができるんです。
が、サンプルを読んでも使い方はよくわからないですね
OverrideXML は XmlAttributeOverrides をとても使いやすくしてくれるクラスです。

OverrideXML の導入方法

方法1:nuget からインストール

NuGet Gallery | OverrideXml 1.0.0

方法2:GitHub からダウンロードして自分のプロジェクトに取り込む

github.com
ファイルは1つしかないのでとても手軽です。( Unity でも使えます )

OverrideXML の使い方

例えば以下のXMLファイルがあります
gist.github.com

上記XML データ構造によってクラスを定義します
gist.github.com

OverrideXml を使ってXmlAttributeOverrides を構築する
gist.github.com

もっと詳細に説明すると
OverrideXML はメソッドチェーンを使って記述していきます。

イメージしやすいように、
行毎にコメントを記載してみる

// まずは OverrideXml のインスタンスを作成して
new OverrideXml()
// class Table をオーバーライドし
.Override<Table>()
  // ルートタグを "table" 指定し
  .XmlRoot("table")
  // class Table のメンバー [border] を XmlAttribute [border] と紐付けます
  .Member("border").XmlAttribute("border")
  // class Table のメンバー [tr] を XmlElement [tr] と紐付けます
  .Member("tr").XmlElement("tr")
// class TR をオーバーライドし
.Override<TR>()
  // class TR のメンバー [td] を XmlElement [td] と紐付けます
  .Member("td").XmlElement("td")
// class TD をオーバーライドし
.Override<TD>()
  // class TD のメンバー [value] を XmlText と紐付けます
  .Member("value").XmlText()
// コミットしXmlAttributeOverrides を構築されます
.Commit();

最後はデシリアライズします。
gist.github.com

以上 OverrideXML の使い方でした。