AssetResolution(1) - usdResolverExample
Universal Scene Description AdventCalendar2021 15 日目は、 USD の Asset Resolution (アセットパスの解決)についてです。
AssetResolution とは
AssetResolution とは、その名の通りアセットの実際のリソースまでのパスを 解決するためのプロセスのことを指します。
Stage Layer Spec の記事に書いた通り、USD は1つのファイルではなくて複数の(それは多くの)レイヤーによって 1つのステージが構成されています。 つまり、あるレイヤーの中には別のレイヤーへのパスが記述されているはずです。
例えば、Kitchen_set.usd を見ると、中で Reference されているモデルは ./assets/~ といった 現在開いているファイルからの相対パスで記述されていて、 子の相対パスで記述されたアセットのパスを「現在のファイルから見た相対パス」として 探し出し、その結果をロードしています。 あるいは、 PXR_AR_DEFAULT_SEARCH_PATH という環境変数が指定されている場合は Windows の PATH と同じように、DEFAULT_SEARCH_PATH で指定されたパス以下を検索して 見つかった場合は、そのフォルダ以下にあるファイルを使用するようになっています。
図に表すと、このようになります。
デフォルトの場合はその名の通り「ArDefaultResolver」と呼ばれるアセットのパス解決のための 機能が実装されています。 この ArDefaultResolver は、相対パスで記述されたアセットのパスを検索し 実際のリソースまでのフルパスを返します。 これによって、相対パスで記述されていてもフルパスで表示ができるようになっています。
このように、ある入力のパス(相対パス)からリソースまでのフルパスを検索して その結果を返す機構のことを「Asset Resolution」と呼び、 そのためのインターフェースを AssetResolver と呼びます。 デフォルトの ArDefaultResolver も ArAssetResolver から継承され 実装されたプラグインです。
このパスを解決するためのプロセスは、独自にカスタマイズすることが可能です。
具体的な使い方を見る
といっても、これだけでは使用イメージがつかみにくいと思いますので 今回は、USD リポジトリ以下にあるサンプルプラグイン usdResolverExample をみながら どのようなものか、そしてどう使うのかを説明していこうとおもいます。
ビルドする
まずは USD をビルドします。
git clone https://github.com/PixarAnimationStudios/USD.git
どこか適当なフォルダにクローンしておきます。 そして、
環境変数の PATH に、Python の Path を通しておきます。 Python のバージョンは、3.7.9あたりを入れておきます。 なお私は、3.7.7 ですが多分それでも大丈夫でしょう。
VisualStudio2017 を事前にインストールしておいて、開発者コマンドプロンプト for VS 2017 をクリックします。
pip install PyOpenGL PySide2
忘れずに pip で PyOpenGL と PySide2 を入れておきましょう。
python build_scripts/build_usd.py <インストールするフォルダ>
あとは、これを実行して30分ほど待ちます。 Python は、環境変数で指定されている PATH の Python でビルドされるので 今回なら 3.7.7 で使用できる USD ができあがります。
はじまって
無事終わると、このような表示になります。
ビルドが完了したら、インストール先のパスを環境変数に指定します。 しかし困ったことに、この環境変数を指定してしまうと Houdini がいろいろおかしなことになってしまうので
set PATH=C:\USD\lib;C:\USD\bin;%PATH%
SET PYTHONPATH=C:\USD\lib\python;%PYTHONPATH%
cmd /k
私はこのような Bat を用意してそこから起動するようにしています。 (あるいは VSCode の環境変数で指定)
サンプルプラグインをコピーする
ビルドができたら、usdResolverExample を plugin にコピーします。 ビルドで指定したフォルダ(サンプルの場合 C:/USD)以下 share/usd/examples/plugin にある
この3つのファイルを、 plugin/usd 以下にコピーします。
コピーができたら準備完了です。
サンプルを開く
サンプルの Resolver が使えるようになったので、 Resolver のサンプル usd ファイルを見ながらどのようなものかを見ていきましょう。
extras/usd/examples/usdResolverExample/testenv/testUsdResolverExample
サンプルは、以下のフォルダにあるので このフォルダをどこかわかりやすいところにコピーします。 自分の場合は D ドライブ直下に置いておきます。
まずは何も考えず、サンプルの shot_1/shot_1.usda を開いて見ます。
すると、盛大にエラーが出ていて表示できません。
shot_1.usda をエディタで開いてみると
references = @asset:Buzz/Buzz.usd@
リファレンスで読み込むファイルが asset: から始まるパスになっていて、相対パスではありません。 この「asset」は、URI(Uniform Resource Identifiers) と呼ばれる 通常の相対パスなどではなく特定の処理を するための「識別子」になっています。
asset: と uriSchemes
この識別子は、pluginfo.json によって指定されています。
{
"Plugins": [
{
"Info": {
"Types": {
"UsdResolverExampleResolver": {
"bases": ["ArResolver"],
"uriSchemes": ["asset"],
"implementsContexts": true
}
}
},
"LibraryPath": "../usdResolverExample.dll",
"Name": "usdResolverExample",
"ResourcePath": "resources",
"Root": "..",
"Type": "library"
}
]
}
usdResolverExample の pluginfo.json を見ると、 Types の uriSchemes に asset が指定されているのがわかります。 これは、 アセットパスに asset:~~ になってい場合は、UsdResolverExampleResolver プラグインを呼び出すようにしてくれ という、AssetResolver プラグインを使用するための設定になっています。
usd の plugins は、plugin/usd/pluginfo.json にある内容をロードします。 そして、 plugin/usd/plugin/pluginfo.json は subdir/resources/pluginfo.json を Include します。 なので、今回の Resolver プラグインの pluginfo.json は plugin/usd/usdResolverExample/resources 下にあります。 このあたりの話はまたいずれ。
set USD_RESOLVER_EXAMPLE_ASSET_DIR=D:\testUsdResolverExample\assets
サンプルの Resolver は、アセット置き場を別途指定してあげる必要があるので 上のように USD_RESOLVER_EXAMPLE_ASSET_DIR を指 定して もう一度 shot_1/shot_1.usda を開いてみます。
今度は開くことができました。
usdview で Buzz Prim のコンポジションをみると、 assets 以下の Buzz がリファレンスされているのがわかります。 usdResolverExample プラグインは、 asset:Buzz の Buzz 部分が AssetName として解釈して、USD_RESOLVER_EXAMPLE_ASSET_DIR 以下の AssetName の AssetName.usd にアセットパスが解決されました。
Asset のフォルダ構成
ではこの呼び出されている Buzz アセットフォルダ以下はどのような構成になっているでしょうか。
Buzz 以下に Buzz.usd があり、 サブフォルダでバージョンごとのフォルダがあるのがわかります。
Buzz 以下にある Buzz.usd を usdcat してみると
Buzz/Buzz.usd は、 Buzz 以下 のバージョンフォルダをペイロードしています。
アセットは、このようにバージョン管理をすることがよくあると思いますが、
asset:Buzz/Buzz.usd
asset:<AssetName> のように解釈するのに加えて、
{
"Buzz" : "1",
"Woody" : "1"
}
shot_1 以下にある versions.json というファイルの中身を参照し、 このファイルに書かれているバージョンのアセットを使用するようになっています。
つまりまとめると、アセットのパスが asset:AssetName/AssetName.usd のように指定されていた場合、
- shot 以下の versions.json を見て、環境変数 VESION に AssetName のバージョンを指定
- USD_RESOLVER_EXAMPLE_ASSET_DIR で指定したアセットフォルダ以下から
- AssetName 以下の AssetName.usd をリファレンスして
- その本体は、AssetName : version で指定されている バージョン以下のものをペイロードする
ということが、 usdResolverExample で行われています。
試しに、 versions.json を
{
"Buzz" : "latest",
"Woody" : "1"
}
このようにかきかえてみます。
すると、AssetInfo は latest ではなく 2 になっています。
次は バージョンフォルダを増やしてみます。
latest をコ ピーして 2 にします。 latest 以下の Buff_sublayer.usd の AssetInfo を書き換えて version:3 にしておきます。
すると、latest 以下の Buzz.usd が読まれているのがわかります。
{
"Buzz" : "2",
"Woody" : "1"
}
2 にすれば、 latest ではなく 2 のフォルダを参照しに行きます。