バンダイナムコスタジオ プログラマー多田 航氏が登壇。『ACE COMBAT 6 解放への戦火』『テイルズ オブ カード エボルブ』『New ポケモンスナップ』などの開発に携わる
USDをゲームアセットフローに採用する3つのメリット
講演の最初には、一般的に使用頻度が高いとされるJSONを用いたゲームアセットフローと、USDを用いたゲームアセットフローの違いについて説明。基本的に、読み込んだファイルをアセットコンバーターがバイナリファイルとして出力し、ランタイム側で読み込むというワークフローは、どちらの場合も大きく違いません。
ゲームアセットにUSDを採用する主要なメリットとして、多田氏は以下の3点を挙げました。
- コンポジションが使用可能
- DCCツールとの相互運用性が向上
- USD Toolsetが使用可能
①複数ファイルを合成する「コンポジション」が使用可能
USDでは、複数のファイルをアセットコンバーター内で合成し1つのゲームアセットとして出力する「コンポジション」が使用可能です。
「コンポジション」の例。A~Cのゲームアセットがあるとして、それらをアセットコンバーター内で1つのUSDに合成し、それをもとにバイナリファイルとして出力する
コンポジションを使うためには、6種類の「コンポジションアーク」に従いゲームアセットが分割されている必要があります。
スライド右下の図はコンポジションの例。個別キャラクターのUSDパラメーターが他のキャラクターの共通パラメーターUSDを参照するといったことが可能
②DCCツールとの相互運用性が向上
Houdiniの「Solaris」やMayaの「Importer・Exporter」など、各種DCCツールにはUSDに対応した入出力機能が搭載されています。ゲームアセットをUSDで出力することで、各種DCCツールで使用可能になります。
③公式が提供する「USD Toolset」が使用可能
ゲームアセットをUSDで制作すると、USD公式ツールである「USD Toolset」を使用可能です。
USDファイルのビューアーツールである「usdview」や、ファイルの変換などが可能なコマンドラインツール「usdcat」といったツールが提供されている
C#からUSDにアクセスする手順――USDライブラリの組み込み事例
実行環境
USDにはUSDで扱えるファイルフォーマット( .usd / .usdaなど)用のライブラリが提供されています。本講演では、バージョン25.05のWindows版をMonolithic(※) LibraryとしてMSVCでビルドしたUSDを使用しています。USDはゲームランタイムではなく、アセットコンバーターとしてのみの扱いです。
※ 複数の要素を分割せずに、一体化させるアーキテクチャ
C#からUSDにアクセスするフロー
USDをMonolithicビルドしたDLL(usd_ms.dll)のインターフェースは、vectorやVtArrayといったマーシャリングしづらいものが多くなっています。このため、C#からマーシャリングしやすいように中継用としてC++のDLLを作成しました。
さらに、このC++のDLLにアクセスするために、USDの各クラスをオブジェクトとして扱えるようにしたC#のインターフェースライブラリも作成。このUSDアクセスライブラリによって、C#ツールからのUSDの読み書きが可能になります。
C#からUSDへのアクセスについて、usd-unity-sdkのようにUSDライブラリで解析機構を作っている例もあるが、今回は全て手作業
UsdStageやCustomLayerDataなどのC#オブジェクト(左の画面画像)をUSDに出力(右の画面画像)
変換を見込んだC#とUSDの扱い
通常、USDは必要なものを必要な時に読み込み、高速に動作させる処理方式を取っています。しかし、今回は処理速度よりも開発のしやすさに重点を置き、USDを読み込んだ時に一括でAttributeを読み込むようにしています。
C#オブジェクトをUSD出力する際は、C#オブジェクトをUSD上で何に変換するのか、アセットの種類ごとにUSDスキーマ設計をする必要があります。
開発後半にアセットの種類が増えることを想定すると、USDスキーマ設計を簡略にし、自動でUSDにシリアライズできることが望ましいと多田氏は述べました。今回のシリアライズではリフレクションを使用し、C#オブジェクトからUSDへ自動変換します。
C#オブジェクトの表現
C#オブジェクトはPrimを使って表現します。クラス名をUSDのAttributeに記録しておくことで、デシリアライズ時にそのAttributeからクラス名の復元が可能になります。これはJson.NETの$typeと同様の機能になります。
C#のpublic class Simpleのクラス名は(左の画面画像)はUSD上でstring AssemblyTypenameにTest.Simpleの形で出力されている(右の画面画像)
基本型の変換
bool / char / intなどの基本型はUSD側で用意されているため、C#からUSDへの型変換が可能です。基本型の配列もpxr::VtArrayで変換できます。
USDに用意されていない型の変換
USDに用意されていない型は別の方法で表現する必要があります。例えば、Prim配列はUSDに存在しません。このため、C#のオブジェクト配列はPrimのSdfPathに連番を付けて表現しています。
他にも、List、ObservableCollection、Dictionary、HashSetなどのUSDに用意されていない型は独自のPrimを作成して表現しました。
C#のPrim配列はUSD上ではSdfPathのValue_番号の形で表現(左の画面画像)。Dictionary型は、Key・ValueのAttributeを持ったPrimを作成(右の画面画像)。定義はSdfPathの予約語などを避けて行う必要がある
このシリアライザによって、USDスキーマ設計が不要なシンプルなC#オブジェクトはUSDに自動変換が可能になったとのこと。ただし、DCCツールとの相互運用性を高めるためには、USDスキーマ設計を各オブジェクトに手動で丁寧に行うほうが良いと述べていました。
Excelやモデルコンバーターなど、各種ツールでUSDを使うフローを解説
C#からUSDを読み書きできる環境を整え、かつシリアライザも作成することで、さまざまなツールからUSDが扱えるようになります。
Excel、モデルコンバーターなどUSDから使えるツールの具体的な利用例を解説しました。
Excel
ゲームパラメーターのような大量のデータは、Excelやスプレッドシートで管理することがあります。これらのデータをUSDファイルで出力し、さらにバイナリファイルに出力が可能です。
Excelの1行を1つのC#オブジェクト、つまりPrimとして表現できます。列はC#上では変数として、USD上ではAttributeもしくはCustom Dataとして表現が可能です。
ExcelのデータをUSD上でAttributeとCustom Dataにそれぞれ変換した例。どちらにもExcelのパラメーターの値が格納されている
JSONデータをUSD内に組み込む
AttributeやCustom Dataはstringの文字列が扱えるため、USDにJSONのデータを組み込むことも可能です。ただし、JSONを使用した文字列にはコンポジションなどのUSDの機能は使えません。
JSONデータをUSDに組み込むケースとして、それまでJSONで運用してきたゲームアセットをUSDに変換する場合が考えられます。USDで表現しきれない箇所に、JSONをそのままUSD内に組み込むことができます。
USDにスキーマを設定することでDCCとの相互運用性を向上
汎用パラメーターのExcelデータにUsdGeomScopeを使った例、配置情報などの座標情報が含まれているデータにUsdGeomXformを使用した例が紹介されました。このように、スキーマをUSDに設定することでDCCツールとの相互運用性が向上します。
座標情報をAttributeのxformOpのtranslateなどに設定
USDシリアライザを使ってExcelデータをUSD化
前述のUSDシリアライザを使って、ExcelデータからUSDデータを出力することも可能です。このデータは、JSONデータと似たような出力となります。
USDシリアライザで出力した結果を、JSONで出力した例と比較
コンポジションを使って他のExcelファイルの値を参照する
コンポジションを使うと、他のUSDファイルにあるパラメーターの値を参照することができます。
複数のExcelファイルをUSDファイルとしてそれぞれ出力し、コンポジションによって参照関係を保ったまま1つのバイナリファイルとして合成することが可能です。
コンポジションの機能を使えるのは、IDをキーにして共通のパラメーターをマスターファイルから参照しているようなケース
USDで参照を使った具体例。コンポジションの結果はusdcatを使ってプレビューしてからバイナリファイルに出力することができる
カメラ座標を記入したExcelをUSD出力して、DCCツールやゲームエディタで活用――カメラブックマーク
カメラ座標などの情報が入力されたExcelファイルをUSDで出力することで、DCCツールやゲームエディタからカメラブックマークを読み込むことが可能となります。このワークフローはスクリーンショットの自動撮影などに使用できます。
Houdiniでカメラブックマークを使用する例。カメラブックマークのExcelからUSDを出力し、UsdGeomCameraのスキーマで表現。カメラ座標はXformOpのtranslateなどに設定した。Houdini上ではAsset Referenceノードを使って参照
ライティングプリセットExcelの情報をUSD経由でHoudiniで参照
ライティングプリセットとしてExcelを使用する際は、Lookdev用のライティングとしてHDRIと太陽光の情報をExcelに入力します。そのExcelファイルをUSDで出力すると、DCCツールやゲームエディタでライティングの情報を参照できるようになります。
Houdiniでライティングプリセットを使用する場合のスキーマとしては、HDRIはUsdLuxDomeLight、太陽光はUsdLuxDistantLightを使用できます。これらをHoudiniのAsset Referenceノードで読み込むことで、Houdini上にライティングを反映できます。
このフローでは、ライティングアーティストがExcelに入力した設定を、Houdini上から変更することはできません。そのため、アーティストが意図せずライティングアーティストの設定を変更してしまうことを防ぐことができます。
Houdiniでライティングプリセットを使用する例。カメラのExposureなどもUSDで出力可能
モデルコンバーター
USDで出力したHoudiniのモデル情報を、モデルコンバーターでバイナリファイルにすることで、ゲーム側でモデル情報を読み取ることが可能になります。つまり、HoudiniからゲームへのエキスポーターとしてUSDを使用できるということです。
スキーマとしてはUsdGeomMeshを使用し、Divideノードなどを使ってfaceVertexCountsを3に設定します。
HoudiniのエキスポーターとしてUSDを使用する際のフロー
USDスキーマに無いパラメーターはCustom Dataを経由して利用
ゲームの固有のパラメーターなど、USDスキーマに含まれていないパラメーターをUSDに埋め込みたい場合はCustom Dataを使用します。モデルコンバーター側でUSDを読み取った時にCustom Dataも読み取り、その情報をバイナリに埋め込むことで、ゲーム側からHoudiniで設定したパラメーターを利用できます。
例えば、HoudiniのConfigure Primitivesノードに、Custom DataでRenderPassの情報をstring文字列として設定すると、出力したUSDにもstring型でRenderPassが出力されます。このUSDをモデルコンバーターで読み取り、USDに出力されたRenderPassをバイナリファイルに設定。ゲーム側でRenderPass設定後のバイナリファイルを使うことによって、Houdiniで設定したモデルの描画パスに従ってゲーム上での描画が可能になります。
そこそこ存在するUSDスキーマに無いパラメーターはCustom Dataを使った変換が必要となる
モデルデータはUSDを使ってHoudiniでデータデバッグ
モデルデータにUSDを使用することで、HoudiniのScene Graph Treeやusdviewでデータデバッグが行えます。これはモデルコンバーターを作る際に役立つといいます。
コリジョンコンバーター
コリジョン形状は通常ゲームエディタで編集することが多い要素です。しかし、コリジョンコンバーターを介すことで、DCCツールでコリジョン形状の編集が可能になります。スキーマはUsdGeomMeshを使用します。
コリジョンのデータは、開発中に追加パラメーターが必要になる場面が多々あります。例えば、足音の設定で、草や地面といったコリジョン種別のパラメーターが必要になるケースです。こうした場合は追加パラメーターをCustom Dataに設定します。
コリジョンコンバーターはこのコリジョンアセットUSDを読み取り、バイナリファイルを出力します。
コリジョンアセットUSDを使えば複数人での同時編集も可能に
コリジョンアセットUSDは、コンポジションを使うことで複数ファイルに分割することが可能です。この分割したコリジョンアセットUSDファイルを使うことによって、複数人による同時編集が可能になります。
編集したコリジョン形状の各データはsublayersでコンポジションすることで合成します。コンポジション結果をバイナリファイルに出力すれば、複数人による同時編集した結果を利用できます。
Houdiniでそれぞれ作成したコリジョン形状を合成するフロー。コンポジション結果では、それぞれがHoudiniで作成したコリジョン形状が合成されている
複数ツールの組み合わせも実現できる
USDは複数のツールから出力できるため、DCCツールで出力したUSDの一部のパラメーターをExcelのパラメーターで上書きすることも可能です。
Houdiniから出力するUSDのCustom Dataにコリジョン種別を設定。Excelから出力するUSDのCustom Dataにもコリジョン種別を設定。Excelはprepend referencesを使ってHoudiniから出力したUSDを参照している。コンポジションすることで、Houdiniから出力したUSDの一部パラメーターをExcelで変更可能になる
レベルエディタ
レベルアセットのUSDについて
USDが使用できるレベルエディタでは、レベルアセットにUSDを適用できます。出力したレベルアセットUSDは、usdviewでプレビューが可能です。
usdviewのプレビューにメッシュ情報はないため、Entityなどの階層構造の確認のみとなる
レベル構造は、ルートレベルの下にEntity、その下にサブレベルがある。対して、USDはLayerの下にPrimがある。同じツリー構造であるため、結果的にレベル情報はそのままUSDとして表現可能
サブレベルの参照
サブレベルが別のファイルとして存在する場合、コンポジションの参照機能を使い、prepend referencesで参照が可能です。
USDファイル(右の画面画像)ではprepend referencesを使って別のファイルであるSubLevel.usdを参照している
レベルデータUSDからゲームパラメーターを参照する
コンポジションを使うことで、レベルデータのUSDからExcelのゲームパラメーターの値を参照できます。
例として、レベルエディタからレベルデータUSDを、ゲームパラメーターのデータを格納するExcelからゲームパラメーターUSDを出力するケースを想定します。
レベルエディタから出力したレベルデータUSDでは、prepend referencesを使ってExcelファイルから出力したゲームパラメーターUSDを参照します。コンポジション結果をバイナリファイル出力することで、Excelのゲームパラメーターの値を利用できます。
コンポジション結果を見ると、レベルパラメーターの中にゲームパラメーターが埋め込まれているのが確認できる
Diff、マージなどUSDが公式に提供するツール群「USD Toolset」の使い方を紹介
USDが公式に提供している「USD Toolset」には、usdeditやusdcatなどのツールが存在します。いくつかのツールについて使い方の解説がありました。
usdviewとusdcatの使い分け
モデルコンバーターなどにCustom Dataで文字列を入力した場合、Custom Dataにstringで入れた文字列は、usdviewでは見切れてしまい探しづらいことがあります。こうした場合はusdcatを使用して.usdファイルをASCIIである.usdaファイルに変換すると、テキストエディタでアセットなどの検索が可能になります。
usdview(左の画面画像)で見切れている表示は.usdaに変換し、テキストエディタで表示する(右の画面画像)と、文字列全体を表示できる
usdstichを使ったマージ
usdstichでは、複数のUSDに対して、単なるテキスト上のマージではなくオブジェクトマージが実行できます。usdstichを使うと、引数の順序によってマージの優先順位が変更可能です。
test1.usda(左端の画面画像)とtest2.usda(左から2番目の画面画像)をusdstichを使って優先順位を変えてマージした例。test1.usdaとtest2.usdaで競合しているHPの値の扱いが優先順位によって異なっていることが確認できる
usddiffを使ったオブジェクト差分
usddiffは、USDのオブジェクト差分を見ることができるツールです。PerforceのDiffツールにusddiffを登録することで便利に活用できると多田氏は語りました。
USDを効果的に生かせるのは、コンポジションやDCCツールとの連携が生じるアセット
ここまで講演内では、ゲームアセットにUSDを採用するメリットを中心に解説されてきましたが、講演のまとめに入るにあたり、USD採用のデメリットについても触れられました。
USD採用のデメリット
- USDを使うにはpythonなどの環境整備が必要となる
- USDをデバッグビルド/リリースビルド後に問題が発生した場合は、ソースコードをデバッグしなければならない
- USDはLinux版を基準に開発されているので、Windows版でMSVCを使ったビルドでは不具合が出ることがある
MSVCビルドの不具合は、標準ライブラリを実行するときにVERIFY関数などが呼び出されることにより生じることがあるといいます。これは、Linux版をベースに開発しているとなかなか気付けない問題だと多田氏は語ります。
その他、アセットがUSDの仕様の影響を受けることもデメリットだといいます。具体的なデメリットとして3点が挙げられました。
〈パスの生成処理〉
Primはユニークなパスで、文字列として管理される。数字(ID)ベースでアセットを管理している場合、IDを文字列に変換する際に、アンダーバー以外の記号がほとんど使用できず変換で苦労することがある。
〈USDスキーマにないものを表現しづらい〉
DCCツールなどでは、スキーマが無い「線」の表現のためにUsdGeomBasisCurvesで代用する場合がある。カスタムスキーマを使う解決策もあるが、アセットの前方互換性に懸念があるのに加え、DCCツールの相互運用性も低下するため、使いにくい選択肢となっている。
〈Variantで選択していないPrimの情報を取得しづらい〉
USDにおいて、何かを切り替える機能としてはVariantが用意されているが、Variantの仕様に従う必要がある。例えば、StageをTraverseする場合に、Variantで選択していないPrimの情報は取得できないため、Variantを切り替えながら取得するツールなどの実装が必要となる。
多田氏は、ゲームアセットをUSDとして扱うメリットやデメリットを判断材料に、使用の有無を決めるのが良いと述べました。
また、USDに適しているものとして、コンポジションを行うアセットやDCCツールと連携するアセットを挙げています。単純な文字列リストファイルなどはUSDを使用するメリットが少なく、JSONやXMLといった従来のファイルフォーマットが適していると語り、本講演を終えました。
バンダイナムコスタジオ 公式サイトUSDのゲームアセットへの応用について - CEDEC2024
ゲームメーカーズで編集や諸業務に携わっています。『星のカービィ』シリーズと『ポケモン不思議のダンジョン』シリーズが好きです。