Slide 1

Slide 1 text

クラスター株式会社 @yutopp AvatarMakerを支える技術

Slide 2

Slide 2 text

Cluster, Inc. All Rights Reserved. 話す人 @yutopp ソフトウェアエンジニア

Slide 3

Slide 3 text

Cluster, Inc. All Rights Reserved. 本日の内容について ● clusterのAvatarMaker機能を実装した際に得られたUnity開発の知見 ○ どのような前提条件があって ○ どのような調査・試行錯誤をしたか

Slide 4

Slide 4 text

Cluster, Inc. All Rights Reserved. 大枠の話

Slide 5

Slide 5 text

Cluster, Inc. All Rights Reserved. AvatarMakerとは ● そのままcluster内でアバターを作れる機能 ○ Windows(Desktop/VR), Mac, Android, iOS, Meta Quest2で利用可 能!

Slide 6

Slide 6 text

Cluster, Inc. All Rights Reserved. AvatarMakerの要件 1. cluster内でアバターを作成できること (VR/Desktop/Mobile) 2. 服装・髪型・色を切り替えられること 3. 顔の造形・パーツを変更できること 4. 社内外のクリエイターの方が素体の部品をアップロードできること 社内に閉じない 制作ワークフロー どこでも動く 大体いじれる

Slide 7

Slide 7 text

Cluster, Inc. All Rights Reserved. AvatarMaker追加以前のclusterの設計

Slide 8

Slide 8 text

Cluster, Inc. All Rights Reserved. AvatarMaker追加以前のclusterの設計 ● ユーザーの方がVRMをサーバーにアップロード ● clusterアプリで利用時にVRMをダウンロードして表示

Slide 9

Slide 9 text

Cluster, Inc. All Rights Reserved. AvatarMaker追加後の設計

Slide 10

Slide 10 text

Cluster, Inc. All Rights Reserved. AvatarMaker追加後の設計 ● [new] 社内外のクリエイターの方がglTFをサーバーにアップロード ● [new] clusterアプリで利用時にglTFをダウンロードして組み立てて表示 ● [new] clusterアプリがVRMをサーバーにアップロード

Slide 11

Slide 11 text

Cluster, Inc. All Rights Reserved. Clusterの技術構成 ● クライアント ○ Unity 2019.4.22f ○ MVPパターンで大体設計されている ○ ライブラリ ■ Zenject ■ UniRx/UniTask ■ etc… ● サーバー ○ Go ○ VRM/glTFを最適化する機構をもりもり搭載している ■ メタバースプラットフォーム clusterのserverについて(2021応用編) ■ OSSのglTFライブラリにPull Requestを出した件について クラスター Advent Calendar 2021 参照

Slide 12

Slide 12 text

Cluster, Inc. All Rights Reserved. Clusterの技術構成

Slide 13

Slide 13 text

Cluster, Inc. All Rights Reserved. Clusterの技術構成 ● 機能の依存関係の設計の維持を頑張ると、建て増しする際に整理しやすい ○ 変更しやすい状態を維持することを意識するとよさそう

Slide 14

Slide 14 text

Cluster, Inc. All Rights Reserved. 詳細の話

Slide 15

Slide 15 text

Cluster, Inc. All Rights Reserved. 全体実装

Slide 16

Slide 16 text

Cluster, Inc. All Rights Reserved. 全体実装 実験用アプリとclusterを別で作った。

Slide 17

Slide 17 text

Cluster, Inc. All Rights Reserved. 全体実装 ● 最初からclusterには組み込まず、独立して開発 ○ ライブラリと試験実装アプリとして分離 ● 途中からライブラリのみcluster本体に組み込みこんだ ○ インターフェイスの微調整などしつつ… 社内外で使うためには、 ある程度外に出せるよう に境界を引く必要があっ た…

Slide 18

Slide 18 text

Cluster, Inc. All Rights Reserved. 全体実装 メリット ● 疎結合な設計を強制できる & asmdefを切りやすい ● 単体アプリとして動作確認のイテレーションを高速にできる デメリット ● どこまで最適化するかの塩梅が難しいがち ○ 組み込んでわかるリソースの上限・プラットフォームごとの差異など 結構あった

Slide 19

Slide 19 text

Cluster, Inc. All Rights Reserved. glTF 2.0 おなじみ Khronos Group開発の3Dモデルを扱うファイル形式。 (中身は基本 json + binary blob) 「glTF is the "JPEG of 3D"」 https://www.khronos.org/gltf/ かのVRM形式はglTFの上に構築されてい る

Slide 20

Slide 20 text

Cluster, Inc. All Rights Reserved. glTF 2.0 AvatarMakerでは、glb(binary) 形式を利用。glTFの拡張領域にclusterの拡張 を定義し、そこにアバターの部品データのメタデータを格納している。 元データは普通にブラウザでも読み 込める (cluster上では難読化して配信)

Slide 21

Slide 21 text

Cluster, Inc. All Rights Reserved. glTF 2.0 メリット ● AssetBundleのように各プラットフォームに向けて何度もビルドする必要なし ● 標準的な規格なので、他言語のライブラリからでも読める相互運用性の高さ ○ プラットフォームごとのデータの最適化はバックエンド側で担保できる デメリット ● glTFの拡張領域を自由にライブラリから使うのが難しい マルチプラット フォームで使うに は最高

Slide 22

Slide 22 text

Cluster, Inc. All Rights Reserved. glTF 2.0 > デメリット ● glTFの拡張領域を自由にライブラリから使うのが難しい 解決策 UnityでglTFを扱うライブラリを丸ごと作って解決 yutopp / VGltf using (var importer = new Importer(gltfContainer, timeSlicer)) { importer.Context.Importers.Materials.AddHook(new Hooks.Part.AvatarPartVRM0MtoonImporterHook()); importer.Context.Importers.Nodes.AddHook(new VGltf.Unity.Ext.AvatarImporter()); return await importer.ImportSceneNodes(ct); } glTFのimport/export VRMのexport で利用

Slide 23

Slide 23 text

Cluster, Inc. All Rights Reserved. アバターの合成実装 複数のglTFパーツをダウンロードし、クライアントで1つのHumanoidモデル に合成して表示する部分。 + = + etc…

Slide 24

Slide 24 text

Cluster, Inc. All Rights Reserved. アバターの合成実装 ボツ案:複数のglTFパーツは単体でもHumanoidなので、合成せずに Animatorを同じ位置に重ねて表示する。

Slide 25

Slide 25 text

Cluster, Inc. All Rights Reserved. アバターの合成実装 ボツ案:複数のglTFパーツは単体でもHumanoidなので、合成せずに Animatorを同じ位置に重ねて表示する。 メリット ● パーツの合成処理をVRM出力時に1度だけ行えばよい デメリット ● パーツ切替時にAnimationのタイミングをすべて合わせるのが非常に面倒 だった… ● 必須のComponentをすべてのパーツにつけ、同期するのも大変だった

Slide 26

Slide 26 text

Cluster, Inc. All Rights Reserved. アバターの合成実装 ボツ案:複数のglTFパーツは単体でもHumanoidなので、合成せずに Animatorを同じ位置に重ねて表示する。 メリット ● パーツの合成処理をVRM出力時に1度だけ行えばよい デメリット ● パーツ切替時にAnimationのタイミングをすべて合わせるのが非常に面倒 だった… ● 必須のComponentをすべてのパーツにつけ、同期するのも大変だった Skeletonの付け替えの実行時のコス トはそこまで高くなかった (フレー ム落ちも目立たないくらい)

Slide 27

Slide 27 text

Cluster, Inc. All Rights Reserved. アバターの合成実装 現行:glTFパーツを切り替えるたびに実行時に1つのHumanoidに合成しなお す。

Slide 28

Slide 28 text

Cluster, Inc. All Rights Reserved. アバターの合成実装 現行:glTFパーツを切り替えるたびに実行時に1つのHumanoidに合成しなお す。 メリット ● いくらglTFパーツが増えても、操作するアバターとしては1つの Humanoidモデル扱いできる デメリット ● なし

Slide 29

Slide 29 text

Cluster, Inc. All Rights Reserved. Bone合成 今回のAvatarMakerのglTFパーツは、Humanoidのボーンに関しては仕様を統 一しているので、切替時にHumanDescriptionの変更はしていない。 (基本はSkinnedMeshRendererのSkeletonの付け替えのみ) !Tips ● Humanoid関連のボーンを組み直す場合は、以下の値を編集したAvatarを animatorにセットする必要がある。 ○ HumanDescription.human ○ HumanDescription.skeleton ● Avatar.isHumanがfalseを返さないように気をつける。

Slide 30

Slide 30 text

Cluster, Inc. All Rights Reserved. Texture合成シェーダ テクスチャや色を合成して上書きする部分。 = + 色 + etc…

Slide 31

Slide 31 text

Cluster, Inc. All Rights Reserved. Texture合成シェーダ マテリアルごとに、複数のテクスチャを一枚にベイクする。previewの表示と VRM出力で同じデータを使えるように、リアルタイムで合成する。 = + 色 + etc…

Slide 32

Slide 32 text

Cluster, Inc. All Rights Reserved. Texture合成シェーダ ボツ案 : CustomRenderTexture 「カスタムレンダーテクスチャはレンダーテクスチャの拡張機能で、これを使 うと簡単にシェーダー付きのテクスチャを作成できます。」 https://docs.unity3d.com/ja/2019.4/Manual/class-CustomRenderTexture.html 合成 Shader Material Custom Render Texture 色々なテ クスチャ 色々なプ ロパティ

Slide 33

Slide 33 text

Cluster, Inc. All Rights Reserved. Texture合成シェーダ ボツ案 : CustomRenderTexture メリット ● 今どき デメリット ● Android端末で異常な結果を返し続ける (真っ黒なtexture)

Slide 34

Slide 34 text

Cluster, Inc. All Rights Reserved. Texture合成シェーダ Custom Render Texture appears black on mobile - Unity Answers 「fairly inane workaround…」

Slide 35

Slide 35 text

Cluster, Inc. All Rights Reserved. Texture合成シェーダ 現行 : 1x1のメッシュに通常のShaderで描画したものを平行投影で撮影した RenderTextureを使う 合成 Shader Material Render Texture 色々なテ クスチャ 色々なプ ロパティ 撮影ス クリプト ExecuteCommandBu fferで描画する

Slide 36

Slide 36 text

Cluster, Inc. All Rights Reserved. Texture合成シェーダ 現行 : 1x1のメッシュに通常のShaderで描画したものを平行投影で撮影した RenderTextureを使う メリット ● どの環境でも安定して動く、とてつもない安心感 デメリット ● 枯れた技術感

Slide 37

Slide 37 text

Cluster, Inc. All Rights Reserved. IL2CPP モバイルのときに影響を受けがちな印象ですが、普通にWindowsでバックエ ンドをIL2CPPビルドにしても再現できるものが多かった。

Slide 38

Slide 38 text

Cluster, Inc. All Rights Reserved. IL2CPP ● checkedの範囲が変わる ○ checkedでsignedもunsignedに変換されてしまった https://github.com/yutopp/VJson/commit/3d2f4dbefbacf050dcad71e6f8286fa834da1261 + if ( i < 0 ) + { + throw new OverflowException(); + } o = checked((byte)i);

Slide 39

Slide 39 text

Cluster, Inc. All Rights Reserved. IL2CPP ● Type/TypeInfoのGetCustomAttributesで返ってくるインスタンスが キャッシュされてる ○ 実装依存っぽさ… https://github.com/yutopp/VJson/commit/120020a1c90dd1f0275d0f9353eef4e089943b0a TypeHelper.GetCustomAttribute(ty)? .MemberwiseClone();

Slide 40

Slide 40 text

Cluster, Inc. All Rights Reserved. IL2CPP ● code strippingによって静かに実行時エラーが発生 ○ “[Preserve]” 属性をつけて解決… https://github.com/yutopp/VJson/blob/4db11d1a89fcaa61c8d4f26cf7d2c1f9c2794f18/Packages/net.yutopp.vjs on/Runtime/Attribute.cs#L20 public class PreserveAttribute : System.Attribute { }

Slide 41

Slide 41 text

Cluster, Inc. All Rights Reserved. IL2CPP ● code strippingによって静かに実行時エラーが発生 ○ “[Preserve]” 属性をつけて解決… https://github.com/yutopp/VJson/blob/4db11d1a89fcaa61c8d4f26cf7d2c1f9c2794f18/Packages/net.yutopp.vjs on/Runtime/Attribute.cs#L20 ● 自前定義…? ● Unityに “UnityEngine.Scripting.PreserveAttribute” ない? ○ PureC#のコード部分なので、UnityEngineへの参照を持ちたくない…

Slide 42

Slide 42 text

Cluster, Inc. All Rights Reserved. IL2CPP ● code strippingによって静かに実行時エラーが発生 ○ “[Preserve]” 属性をつけて解決… https://github.com/yutopp/VJson/blob/4db11d1a89fcaa61c8d4f26cf7d2c1f9c2794f18/Packages/net.yutopp.vjs on/Runtime/Attribute.cs#L20 ● 自前定義…? ● Unityに “UnityEngine.Scripting.PreserveAttribute” ない? ○ PureC#のコード部分なので、UnityEngineへの参照を持ちたくない 「For 3rd party libraries that do not want to take on a dependency on UnityEngine.dll, it is also possible to define their own PreserveAttribute. The code stripper will respect that too, and it will consider any attribute with the exact name "PreserveAttribute" as a reason not to strip the thing it is applied on, regardless of the namespace or assembly of the attribute.」 https://docs.unity3d.com/2019.4/Documentation/ScriptReference/Scripting.PreserveAttribute.html

Slide 43

Slide 43 text

Cluster, Inc. All Rights Reserved. IL2CPP ● code strippingによって静かに実行時エラーが発生 ○ “[Preserve]” 属性をつけて解決… https://github.com/yutopp/VJson/blob/4db11d1a89fcaa61c8d4f26cf7d2c1f9c2794f18/Packages/net.yutopp.vjs on/Runtime/Attribute.cs#L20 ● 自前定義…? ● Unityに “UnityEngine.Scripting.PreserveAttribute” ない? ○ PureC#のコード部分なので、UnityEngineへの参照を持ちたくない 「For 3rd party libraries that do not want to take on a dependency on UnityEngine.dll, it is also possible to define their own PreserveAttribute. The code stripper will respect that too, and it will consider any attribute with the exact name "PreserveAttribute" as a reason not to strip the thing it is applied on, regardless of the namespace or assembly of the attribute.」 https://docs.unity3d.com/2019.4/Documentation/ScriptReference/Scripting.PreserveAttribute.html “PreserveAttribute” という名前であ れば、どこに定義していても最適化を抑 制できるattributeとして扱われる (あ りがたいけれどなんだそれは…)

Slide 44

Slide 44 text

Cluster, Inc. All Rights Reserved. IL2CPP ● 開発終盤は (Windows, MacOS, iOS, Android, Linux) x IL2CPPビルドで 動作確認するような用心深さに… ○ CIで回したい

Slide 45

Slide 45 text

Cluster, Inc. All Rights Reserved. まとめ ● 設計を維持するのは最終的に速い ● 頑張って共通の規格を使っておくといろいろ相乗りできて便利 ● 開発イテレーションを早く回して罠をたくさん踏み抜くのが大事 ○ インターフェースの切り方 ○ Texture、IL2CPPのトラブルシュートなど