はじめに
この記事は Universal Scene Description Advent Calender 2024 の14日目の記事です
今回は Asset Resolution 2.0 で ArPathmapResolver を作成した話をしたいと思います!
せっかくなのでビルドも試せるように、ソースコードも Github にアップしています
また、進めるにあたっての補助として、用語等を説明した記事も投稿しています
どうぞよろしくお願いします
それでは、いきましょう!
ArPathmapResolver
ArPathmapResolver ですが簡単に言えば、
ArDefaultResolver を拡張して HOUDINI_PATHMAP が機能するように調整した
カスタムリゾルバーです
これを作成しようと思ったきっかけは、WindowsとLinux間でデータのやり取りをする際に、USDのパスが上手くマップされず、その結果読み込めない事があったためです
HOUDINI_PATHMAP
Houdiniには HOUDINI_PATHMAP という環境変数が用意されており、下記のような形でファイルパスをマップする事が出来るのですが、
どうやら、SolarisやHuskではUSDのパス解決においては、対応していないようでした
{ "c:/temp": "/tmp", "/mnt/render": "//storage/share/render" }
# c:/temp/hoge/fuga -> /tmp/hoge/fuga
USDでファイルを書き出す時に、相対パスでの書き出しを心がけてはいるものの、
重めのキャッシュなど、別ドライブや、別マウントされた場所へと保存する事もあり、
そうすると絶対パスで保存されたUSDのパスが、OS間で解決できない状態でした。
また、それがリファレンスされている場合は、参照先がどんどん深くなっていくので
表面上のパスだけではなく、参照されているパスも全て解決する必要 があります
VFX-UsdAssetResolver
そこで、何かできる事はないかと調べたところ、
カスタムリゾルバーであれば解決できそうでした。
ちょうどその頃に LucaScheller さんの VFX-UsdAssetResolver がGithubで公開され、
それを見てみると、自分がやりたい事と近い内容だったり、HoudiniでビルドされたUSDを使ってビルドしていたので、開発環境を整えるコストも低く、これならば...と思いカスタムリゾルバーを作る事にしました。
とはいえ、完成されたソースを見ても、自分には
何が必要で、何が必要でないかもわからない状態だったので
まずは、細かく段階を踏んで作っていく事にしました。
なので、ここからは自分が踏んでいった工程を実際にビルドしてもらいながら
各項で説明していければと思います
準備
ArPathmapResolver を作るにあたって、
まずはどういうアプローチで作るかを考えていきたいと思います
Asset Resolution
今回は LucaScheller さんの USD Survival Guide から図をお借りして
Asset Resolution では、Asset Identifier とよばれる
@...@
で囲まれた文字列を解決する事で、
実際のアセットのパスがどこにあるのかを特定する事ができます
Asset Resolver / Asset Identifier
Asset Identifier は実際のファイルパスを指している訳ではなく、
アセットを区別するためのタグのようなもので、
Asset Resolver によって、これを実際のファイルパスやURIへと変換しています
Asset Resolver Context
その際に Asset Resolver Context を Asset Resolver に関連付ける事で、
特定の動作を変更したり、異なる検索パスを指定したりする事ができます
より詳しく知りたい方は、いつもお世話になっている @fereria さんのページや、先程の LucaScheller さんのページもご覧下さい
という事で、今回に関しては Asset Identifier を特に変えなくてもよさそうだったので、
Asset Resolver と Asset Resolver Context を調整して
カスタムリゾルバーを作っていく事にします
目次
ここからはいくつかの ステップに分けて説明していきたいと思います
Step1. まずはビルドしてみる!
Step2. 改めて実装してみる
Step3. Pythonモジュールを作成する
Step4. ArPathmapResolverを作成する
また、これらの過程の中で、
このCMakeのオプション何で使うの? とか このマクロって何してるんだ?
という事があったので、それらを 用語集 として用意したので
そちらもご確認して頂けると嬉しいです
開発環境
OS :
AlmaLinux8
, Windows10
コンパイラ:
gcc 8.5.0
, MSVC 19.29.30153.0
ビルドツール:
cmake 3.25+
バージョン :
Houdini 20.0.653
,
ソースコード管理
git
エディタ:
VSCode
Step1. まずはビルドしてみる!
ここでは、まずHoudiniでビルドされたUSDから、
ヘッダーやライブラリを読み込んでビルドする事を目標 に進めていきたいと思います
Gitからリポジトリを読み込む
git clone -b learning/jp_step1_simple_build https://github.com/yu-kita89/USD_PathmapResolver.git USD_PathmapResolver_Step1
上記のコマンドで USD_PathmapResolver_Step1
をクローンするか、
ここ からダウンロードして下さい
フォルダ構成
フォルダ構成は下記のようになっています。各ファイルに説明書き もしているので
ここでは、ざっくりと概要のみ説明します
USD_PathmapResolver_Step1
├── CMakeLists.txt # メインの処理をするcmakeファイル
└── src
├── CMakeLists.txt # 実際にライブラリなどをビルドするcmakeファイル
├── debugCodes.cpp # デバッグを有効にするためのファイル
├── debugCodes.h
├── pathmapResolver.json # Houdini用のパッケージファイル
├── plugInfo.json.in # プラグインを読み込むためのリソースファイル
├── resolver.cpp # AssetResolverのメイン処理
└── resolver.h
CMakeLists.txt
- コンパイラなどのプロジェクトの設定
- ライブラリやヘッダーを読み込むためのディレクトリを設定
-
src
ディレクトリを読み込み
ソース内でPythonに関する記述をしていない場合でも、
内部的に参照しているため、Pythonのヘッダーやライブラリの指定が必要になります
/src/CMakeLists.txt
- リンクするライブラリやヘッダーの設定
- ライブラリの作成
-
plugInfo.json.in
をplugInfo.json
に変換 - インストールするファイルの設定
/src/debugCodes
TF_DEBUGを利用可能にするための設定
/src/pathmapResolver.json
Houdiniでライブラリやリソースを読み込むためのパッケージ
Houdiniパッケージ こちらも参考に
Linuxだとパッケージ内で PXR_PLUGINPATH_NAME が有効にならないので
代わりに HOUDINI_USD_DSO_PATH を設定しています
/src/plugInfo.json.in
プラグインの登録に必要な情報を記述するためのファイルのテンプレート
最終的に @...@
で囲まれた部分の変数は値に置き換わります
参考 : plugInfo.json
| configure_file
/src/resolver
アセットパスを解決するための処理をここに記述
今回は単純なデバッグメッセージを表示しているだけです
ビルド
早速ビルドしていきますが、
ビルドする前に HFS の環境変数を設定する必要 があるので忘れないようにしましょう
# cmd
set HFS=C:\Program Files\Side Effects Software\Houdini 20.0.653
# sh
export HFS=/opt/hfs20.0.653
cmakeを使ってビルドします USD_PathmapResolver_Step1
に移動して
mkdir build
cd build
cmake --fresh ..
cmake --build . --config Release --clean-first
cmake --install .
cmakeは下記のように一度に実行する事もできます
cmake --fresh .. && cmake --build . --config Release --clean-first && cmake --install .
ビルドができない場合
- HFS の環境変数はセットされているか
echo
コマンドなどで確認してみて下さい
その時に "..."
のように "
が一緒に含まれていないか注意して下さい
# Windows
echo %HFS% # C:\Program Files\Side Effects Software\Houdini 20.0.653
# Linux
echo $HFS # /opt/hfs20.0.653
- ジェネレーターは有効なものが指定されているか
ビルドディレクトリにある、CMakeCache.txt
にジェネレーターに関する情報が保存されているので、そちらを確認して下さい
また、-G
や -DCMAKE_CXX_COMPILER
を使ってジェネレーターを明示する事ができます
cmake -G "Visual Studio 16 2019" ..
cmake -DCMAKE_CXX_COMPILER="C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.28.29333\bin\Hostx64\x64\cl.exe" ..
- ライブラリやヘッダーの指定が合っているか
-DCMAKE_VERBOSE_MAKEFILE
--trace
--debug-output
--verbose
などで詳細を確認してみてください
cmake -DCMAKE_VERBOSE_MAKEFILE=TRUE ..
cmake --trace ..
cmake --debug-output ..
cmake --build . --verbose
- ビルドタイプがReleaseではなく、Debugになっていないか
cmakeのコマンドラインオプションでも明示的に指定する事ができます
cmake -DCMAKE_BUILD_TYPE=Release ..
ただ、 Visual Studioを使っている場合は上記のオプションが効かない可能性もあるので、ビルド時に下記を設定する事でビルドタイプを強制することができます
cmake --build . --config Release
- 過去にbuildしたキャッシュなどが残っていないか
CMakeCache.txt
が残ったまま再度ビルドすると、前回の設定が再利用されてしまうので、--fresh
オプションを使って CMakeCache.txt
をクリアにしましょう
cmake --fresh ..
また、ビルド時に --clearn-first
を使う事で、一度クリーンにしてからビルドを実行する事ができるので、こちらも合わせて使用しましょう
cmake --build . --clean-first
確認
ビルドが完了したら、dist
ディレクトリ以下が下記のようになっていると思います
USD_PathmapResolver_Step1/dist
└── pathmapResolver
├── lnx # Linux環境でビルドした場合
│ ├── lib
│ │ └── pathmapResolver.so
│ ├── packages
│ │ └── pathmapResolver.json
│ └── resources
│ └── plugInfo.json
└── win # Windows環境でビルドした場合
├── lib
│ ├── pathmapResolver.dll
│ └── pathmapResolver.lib #インポートライブラリ
├── packages
│ └── pathmapResolver.json
└── resources
└── plugInfo.json
それでは確認していきます
環境変数の設定
先程書き出した、pathmapResolver.json
のパッケージを読み込めるように
HOUDINI_PACKAGE_DIR の環境変数を設定します
また、デバッグ用に TD_DEBUG、HOUDINI_PACKAGE_VERBOSE もセットします
dist
直下の pathmapResolver
フォルダは移動してもらっても構いませんが、それ以下の階層は変更しないように注意して下さい
# cmd ※HOUDINI_PACKAGE_DIRは適宜変更して下さい
set HOUDINI_PACKAGE_DIR=C:\path\to\USD_PathmapResolver_Step1\dist\pathmapResolver\win\packages
set HOUDINI_PACKAGE_VERBOSE=1
set TF_DEBUG=AR_*
# sh ※HOUDINI_PACKAGE_DIRは適宜変更して下さい
export HOUDINI_PACKAGE_DIR=/path/to/USD_PathmapResolver_Step1/dist/pathmapResolver/lnx/packages
export HOUDINI_PACKAGE_VERBOSE=1
export TF_DEBUG=AR_*
Houdiniで確認
セットしたら、続いて Hython を起動します
※ Houdiniを立ち上げてもらっても大丈夫です
# Windows
"C:\Program Files\Side Effects Software\Houdini 20.0.653\bin\hython.exe"
# Linux
/opt/hfs20.0.653/bin/hython
その後、Pythonで下記コマンドを実行しましょう
from pxr import Ar
resolver = Ar.GetResolver()
resolver.Resolve("Hello!")
コンソール上に下記のようなログがでていれば、正常にビルドされています
※...は省略
Loading: .../pathmapResolver/lnx/packages/pathmapResolver.json
...
ArGetResolver(): Found primary asset resolver types: [ArPathmapResolver, ArDefaultResolver]
ArGetResolver(): Using asset resolver ArPathmapResolver from plugin .../pathmapResolver/lnx/lib/pathmapResolver.so for primary resolver
...
[Resolve] "Hello!"
Step2. ArDefaultResolverを改めて実装してみる
無事にビルドする事ができたので、次は
ArDefaultResolver
ArDefaultResolverContext
クラスを
改めて実装してみたいと思います
全てではなく、必要な関数のみをオーバーライドしていきます
Gitからリポジトリを読み込む
git clone -b learning/jp_step2_reimplement https://github.com/yu-kita89/USD_PathmapResolver.git USD_PathmapResolver_Step2
上記のコマンドで USD_PathmapResolver_Step2
をクローンするか、
ここ からダウンロードして下さい
フォルダ構成
前回から resolverContext
ファイルが増えました
主に、変更箇所がある部分のみ説明していきたいとおもいます
USD_PathmapResolver_Step2
!├── CMakeLists.txt
└── src
! ├── CMakeLists.txt
! ├── debugCodes.cpp
! ├── debugCodes.h
├── pathmapResolver.json
├── plugInfo.json.in
! ├── resolver.cpp
! ├── resolver.h
+ ├── resolverContext.cpp # AssetResolverContextのメイン処理
+ └── resolverContext.h
CMakeLists.txt
- ライブラリやヘッダーのディレクトリに boost を追加
/src/CMakeLists.txt
- リンクするライブラリやヘッダーに boost を追加
- ライブラリのソースに
resolverContext
を追加
boost ライブラリは直接使用していませんが、
resolverContext
で内部的に参照しているため、
boost のヘッダーやライブラリの指定が必要になります
/src/debugCodes
TF_DEBUGに AR_PATHMAPRESOLVER_CONTEXT を追加
/src/resolver
関数などを改めて実装しています、
デバッグメッセージのみを追加して、挙動は ArDefaultResolver
と同じ結果となるようにしています
-
下記関数などを追加
- static:
- _IsFileRelative
- _IsRelativePath
- _IsSearchPath
- _ParseSearchPaths
- _ResolveAnchored
- _ArPathmapResolverFallbackContext
- public:
- SetDefaultSearchPath
- protected:
- _Resolve
- _CreateDefaultContext
- _CreateDefaultContextForAsset
- _CreateContextFromString
- private:
- _GetCurrentContextPtr
- static:
/src/resolverContext
こちらも、関数などを改めて実装しています
-
下記関数などを追加
- public:
-
==
オペレータ - GetAsString
- hash_value
- ArGetDebugString
-
- public:
Resolveのフローチャート
ArDefaultResolver
で Resolve
関数が呼ばれた時の流れをフローチャートにしました
ビルド
Step1 と手順は同じなので、そちらを参考に
確認
Step1 でHoudiniを立ち上げるまでの手順は同じですが、
HOUDINI_PACKAGE_DIR の場所は、今回のビルドで書き出された場所へと適宜変更をお願いします
今回は下記Pythonコマンドを実行してみます
from pxr import Ar
resolver = Ar.GetResolver()
resolver.Resolve("Hello!")
resolver.Resolve("bin")
コンソール上に下記のようなログがでていれば、正常にビルドされています
※...は省略
Loading: .../pathmapResolver/lnx/packages/pathmapResolver.json
...
ArGetResolver(): Found primary asset resolver types: [ArPathmapResolver, ArDefaultResolver]
ArGetResolver(): Using asset resolver ArPathmapResolver from plugin .../pathmapResolver/lnx/lib/pathmapResolver.so for primary resolver
...
[Resolve] Trying to resolve the path. : "Hello!"
[Resolve] The path is relative.
[Resolve] The path is search path.
[Resolve] Searching from "/opt/hfs20.0.653".
[Resolve] The path could not be resolved, returning an empty path.
Ar.ResolvedPath()
...
[Resolve] Trying to resolve the path. : "bin"
[Resolve] The path is relative.
[Resolve] The path is search path.
[Resolve] Searching from "/opt/hfs20.0.653".
[Resolve] The path is resolved : "/opt/hfs20.0.653/bin".
Ar.ResolvedPath('/opt/hfs20.0.653/bin')
この段階では、Pythonでコンテキストを作成しようとしても、C++で派生したコンテキストのクラスがPythonで使える状態ではないためエラーになります。
from pxr import Ar
resolver = Ar.GetResolver()
resolver.CreateDefaultContext()
# TypeError: No to_python (by-value) converter found for C++ type: ...
Step3. Pythonモジュールを作成する
関数を改めて実装する事ができたので、次は
Pythonからモジュールを呼び出して、
コンテキスト等を作成できるようにしていきたいと思います
Gitからリポジトリを読み込む
git clone -b learning/jp_step3_python-module-setup https://github.com/yu-kita89/USD_PathmapResolver.git USD_PathmapResolver_Step3
上記のコマンドで USD_PathmapResolver_Step3
をクローンするか、
ここ からダウンロードして下さい
フォルダ構成
今回からさらにファイルが増えました
USD_PathmapResolver_Step3
!├── CMakeLists.txt
└── src
! ├── CMakeLists.txt
+ ├── __init__.py # Pythonモジュールを定義してラップされたクラスをインポート
├── debugCodes.cpp
├── debugCodes.h
+ ├── module.cpp # Pythonで使用するためのクラスや関数を宣言、呼び出し
+ ├── moduleDeps.cpp # Pythonで使用するためのライブラリを登録
! ├── pathmapResolver.json
├── plugInfo.json.in
├── resolver.cpp
├── resolver.h
├── resolverContext.cpp
├── resolverContext.h
+ ├── wrapResolver.cpp # Resolverをラップするための関数
+ └── wrapResolverContext.cpp # ResolverContextをラップするための関数
CMakeLists.txt
- Pythonモジュールを作成するための変数を追加
/src/CMakeLists.txt
- Pythonモジュールで使用するためのライブラリを作成
/src/__init__.py
- Pythonモジュールを定義してラップされたクラスをインポートするためのファイル
/src/module
- Pythonで使用できるように、ラップするための関数を宣言、呼び出し
- 関数は wrapResolver | wrapResolverContext 内で実装します
/src/moduleDeps
- Pythonモジュールが依存しているライブラリを適切に読み込めるようにするための処理
/src/pathmapResolver.json
-
PYTHON_PATH
を追加
/src/wrapResolver
- boost::python
で Resolver
クラスを登録するための関数を定義
/src/wrapResolverContext
- boost::python
で ResolverContext
クラスを登録するための関数を定義
ビルド
Step1 と手順は同じなので、そちらを参考に
確認
ビルドが完了したら、dist
ディレクトリ以下が下記のようになっていると思います
USD_PathmapResolver_Step3/dist
└── pathmapResolver
├── lnx
│ ├── lib
│ │ ├── pathmapResolver.so
+ │ │ └── python
+ │ │ └── usdCustom # Pythonパッケージ
+ │ │ └── PathmapResolver
+ │ │ ├── __init__.py
+ │ │ └── _pathmapResolver.so
│ ├── packages
│ │ └── pathmapResolver.json
│ └── resources
│ └── plugInfo.json
└── win
├── lib
│ ├── pathmapResolver.dll
│ ├── pathmapResolver.lib
+ │ └── python
+ │ └── usdCustom # Pythonパッケージ
+ │ └── PathmapResolver
+ │ ├── __init__.py
+ │ ├── _pathmapResolver.lib
+ │ └── _pathmapResolver.pyd
├── packages
│ └── pathmapResolver.json
└── resources
└── plugInfo.json
Pythonに関係するファイルが追加されています
それでは確認していきます
Step1 でHoudiniを立ち上げるまでの手順は同じですが、
HOUDINI_PACKAGE_DIR の場所は、今回のビルドで書き出された場所へと適宜変更をお願いします
今回は下記Pythonコマンドを実行してみます
import os
from pxr import Ar
Ar.GetResolver()
from usdCustom import PathmapResolver
resolver = Ar.GetUnderlyingResolver()
ctx = resolver.CreateContextFromString(os.environ["HFS"])
with Ar.ResolverContextBinder(ctx):
resolver.Resolve("houdini/usd/assets/rubbertoy/rubbertoy.usd")
コンソール上に下記のようなログがでていれば、正常にビルドされています
※...は省略
Loading: .../pathmapResolver/lnx/packages/pathmapResolver.json
...
ArGetResolver(): Found primary asset resolver types: [ArPathmapResolver, ArDefaultResolver]
ArGetResolver(): Using asset resolver ArPathmapResolver from plugin .../pathmapResolver/lnx/lib/pathmapResolver.so for primary resolver
...
[Resolve] Trying to resolve the path. : "houdini/usd/assets/rubbertoy/rubbertoy.usd"
[Resolve] The path is relative.
[Resolve] The path is search path.
[Resolve] Searching from "/opt/hfs20.0.653".
[Resolve] The path is resolved : "/opt/hfs20.0.653/houdini/usd/assets/rubbertoy/rubbertoy.usd".
Ar.ResolvedPath('/opt/hfs20.0.653/houdini/usd/assets/rubbertoy/rubbertoy.usd')
Step4. ArPathmapResolverを作成する
これで、ArDefaultResolver
の機能はある程度確認できたので、最後に
ArPathmapResolver を作成していきたいと思います
仕様
今回作成するカスタムリゾルバーの仕様を決めたいと思います。
まずは、環境変数で設定されたパスマップを
USDのアセット解決時に、利用できるようにします。
また、柔軟に対応できるように、リゾルバーには直接組み込まず、
コンテキストによって変更できるようにします
使用する環境変数はデフォルトだと HOUDINI_PATHMAP
ですが、
AR_PATHMAP_ENVIRONMENT
という環境変数、または
SetDefaultPathmapEnvironment
という関数を使って変更出来るようにします
さらに、CreateContextFromString
で直接パスマップを指定できるようにします
書き方は ,
を区切り文字としてそれ以降をパスマップとして扱うようにします
まとめると
-
パスマップの設定:
- デフォルトでは
HOUDINI_PATHMAP
環境変数を使用してパスマップを設定 -
AR_PATHMAP_ENVIRONMENT
環境変数や、
SetDefaultPathmapEnvironment
関数を使って、
使用する環境変数を変更できるように
- デフォルトでは
# cmd
set ANY_PATHMAP={'C:':'D:'}
set AR_PATHMAP_ENVIRONMENT=ANY_PATHMAP
# sh
export ANY_PATHMAP="{'C:':'D:'}"
set AR_PATHMAP_ENVIRONMENT=ANY_PATHMAP
from pxr import Ar
Ar.GetResolver()
from usdCustom import PathmapResolver
resolver = Ar.GetUnderlyingResolver()
resolver.SetDefaultPathmapEnvironment("ANY_PATHMAP")
-
コンテキストに応じたパスマップの変更:
- パスマップの設定は、コンテキストに基づいて
柔軟に切り替えられるようにする
- パスマップの設定は、コンテキストに基づいて
-
CreateContextFromString
によるパスマップ指定:-
CreateContextFromString
関数に渡された文字列でもパスマップは指定可能 -
文字列の
,
以降をパスマップとして扱い、それに基づいてリゾルバーがパスマップを設定
-
from pxr import Ar
Ar.GetResolver()
from usdCustom import PathmapResolver
resolver = Ar.GetUnderlyingResolver()
resolver.CreateContextFromString("hoge:fuga,{'C:':'D:'}")
"""
Search path: [
hoge
fuga
]
Pathmap dict: [
C: : D:
]
"""
Gitからリポジトリを読み込む
git clone -b learning/jp_step4_create-arpathmapresolver https://github.com/yu-kita89/USD_PathmapResolver.git USD_PathmapResolver_Step4
上記のコマンドで USD_PathmapResolver_Step4
をクローンするか、
ここ からダウンロードして下さい
フォルダ構成
USD_PathmapResolver_Step3
├── CMakeLists.txt
└── src
├── CMakeLists.txt
├── __init__.py
├── debugCodes.cpp
├── debugCodes.h
├── module.cpp
! ├── moduleDeps.cpp
├── pathmapResolver.json
├── plugInfo.json.in
! ├── resolver.cpp
! ├── resolver.h
! ├── resolverContext.cpp
! ├── resolverContext.h
! ├── wrapResolver.cpp
! └── wrapResolverContext.cpp
/src/moduleDeps
- 依存するライブラリに
vt
js
を追加
/src/resolver
-
下記関数を調整
- static:
- _ParseSearchPaths
- _ResolveAnchored
- _ArPathmapResolverFallbackContext
- public:
- SetDefaultSearchPath
- protected:
- _Resolve
- _CreateContextFromString
- static:
-
下記関数を追加
- static:
- _ParsePathmapDict
- public:
- SetDefaultPathmapEnvironment
- static:
/src/resolverContext
- パスマップ辞書を引数に持つコンストラクタを追加
-
下記関数を調整
- public:
-
==
オペレータ - GetAsString
- hash_value
-
- public:
-
下記関数を追加
- public:
- GetPathmapDict
- public:
/src/wrapResolver
-
SetDefaultPathmapEnvironment
静的関数の追加
/src/wrapResolverContext
- パスマップ辞書を引数に持つコンストラクタや、
GetPathmapDict
関数の追加
パスマップのフローチャート
結果 ArDefaultResolver
の Resolve
関数の途中に処理を入れた形になりました
ビルド
Step1 と手順は同じなので、そちらを参考に
確認
環境変数の設定
今回はパスマップを適用するための環境変数も追加したいと思います
# cmd ※HOUDINI_PACKAGE_DIRは適宜変更して下さい
set HOUDINI_PACKAGE_DIR=C:\path\to\USD_PathmapResolver_Step1\dist\pathmapResolver\win\packages
set HOUDINI_PACKAGE_VERBOSE=1
set TF_DEBUG=AR_*
set CUSTOM_PATHMAP={'foo':'var'}
set AR_PATHMAP_ENVIRONMENT=CUSTOM_PATHMAP
# sh ※HOUDINI_PACKAGE_DIRは適宜変更して下さい
export HOUDINI_PACKAGE_DIR=/path/to/USD_PathmapResolver_Step1/dist/pathmapResolver/lnx/packages
export HOUDINI_PACKAGE_VERBOSE=1
export TF_DEBUG=AR_*
export CUSTOM_PATHMAP="{'foo':'var'}"
export AR_PATHMAP_ENVIRONMENT=CUSTOM_PATHMAP
Houdiniで確認
セットしたら、続いて Hython を起動します
※ Houdiniを立ち上げてもらっても大丈夫です
# Windows
"C:\Program Files\Side Effects Software\Houdini 20.0.653\bin\hython.exe"
# Linux
/opt/hfs20.0.653/bin/hython
その後、Pythonで下記コマンドを実行しましょう
import os
from pxr import Ar
# Initialize
Ar.GetResolver()
# Moduleの読み込み
from usdCustom import PathmapResolver
# パスマップのキーとバリューをセット
k = os.path.join(os.environ["HFS"],"houdini/usd/assets/hoge")
v = os.path.join(os.environ["HFS"],"houdini/usd/assets/rubbertoy")
# 間違ったパスをセット
path = os.path.join(k,"rubbertoy.usd")
# Resolverの取得
resolver = Ar.GetUnderlyingResolver()
resolver.Resolve(path) # Unresolve
# パスマップの環境変数を変更
os.environ["HOUDINI_PATHMAP"] = "{'%s':'%s'}"%(k,v)
resolver.SetDefaultPathmapEnvironment("HOUDINI_PATHMAP")
resolver.Resolve(path) # Resolve
# 再度パスマップを変更
resolver.SetDefaultPathmapEnvironment("CUSTOM_PATHMAP")
resolver.Resolve(path) # Unresolve
# コンテキストを作成、バインドして解決
ctx = resolver.CreateContextFromString(",%s"%(os.environ["HOUDINI_PATHMAP"]))
with Ar.ResolverContextBinder(ctx):
resolver.Resolve(path) # Resolve
コンソール上に下記のようなログがでていれば、正常にビルドされています
※...は省略
Loading: .../pathmapResolver/lnx/packages/pathmapResolver.json
...
ArGetResolver(): Found primary asset resolver types: [ArPathmapResolver, ArDefaultResolver]
ArGetResolver(): Using asset resolver ArPathmapResolver from plugin .../pathmapResolver/lnx/lib/pathmapResolver.so for primary resolver
...
[DefaultPathmapEnvironment] Set : "CUSTOM_PATHMAP"
Search path: [
/opt/hfs20.0.653
]
Pathmap dict: [
foo : var
]
[Resolve] Trying to resolve the path. : "/opt/hfs20.0.653/houdini/usd/assets/hoge/rubbertoy.usd"
[Resolve] The path could not be resolved, returning an empty path.
Ar.ResolvedPath()
[SetDefaultPathmapEnvironment] Set : "HOUDINI_PATHMAP"
Search path: [
/opt/hfs20.0.653
]
Pathmap dict: [
/opt/hfs20.0.653/houdini/usd/assets/hoge : /opt/hfs20.0.653/houdini/usd/assets/rubbertoy
]
[Resolve] Trying to resolve the path. : "/opt/hfs20.0.653/houdini/usd/assets/hoge/rubbertoy.usd"
[Resolve] Mapped path from "/opt/hfs20.0.653/houdini/usd/assets/hoge" to "/opt/hfs20.0.653/houdini/usd/assets/rubbertoy".
[Resolve] The path is resolved : "/opt/hfs20.0.653/houdini/usd/assets/rubbertoy/rubbertoy.usd".
Ar.ResolvedPath('/opt/hfs20.0.653/houdini/usd/assets/rubbertoy/rubbertoy.usd')
[SetDefaultPathmapEnvironment] Set : "CUSTOM_PATHMAP"
Search path: [
/opt/hfs20.0.653
]
Pathmap dict: [
foo : var
]
[Resolve] Trying to resolve the path. : "/opt/hfs20.0.653/houdini/usd/assets/hoge/rubbertoy.usd"
[Resolve] The path could not be resolved, returning an empty path.
Ar.ResolvedPath()
[CreateContextFromString] Creating context from string. : ",{'/opt/hfs20.0.653/houdini/usd/assets/hoge':'/opt/hfs20.0.653/houdini/usd/assets/rubbertoy'}"
[CreateContextFromString] Search path : ""
[CreateContextFromString] Pathmap : "{'/opt/hfs20.0.653/houdini/usd/assets/hoge':'/opt/hfs20.0.653/houdini/usd/assets/rubbertoy'}"
Search path: [ ]
Pathmap dict: [
/opt/hfs20.0.653/houdini/usd/assets/hoge : /opt/hfs20.0.653/houdini/usd/assets/rubbertoy
]
[Resolve] Trying to resolve the path. : "/opt/hfs20.0.653/houdini/usd/assets/hoge/rubbertoy.usd"
[Resolve] Mapped path from "/opt/hfs20.0.653/houdini/usd/assets/hoge" to "/opt/hfs20.0.653/houdini/usd/assets/rubbertoy".
[Resolve] The path is resolved : "/opt/hfs20.0.653/houdini/usd/assets/rubbertoy/rubbertoy.usd".
Ar.ResolvedPath('/opt/hfs20.0.653/houdini/usd/assets/rubbertoy/rubbertoy.usd')
GUI上でも確認してみましょう
Rubber Toy
ノードからアセットを読み込んで、リファレンスパスを
$HH/usd/assets/rubbertoy/rubbertoy.usd
から
$HH/usd/assets/hoge/rubbertoy.usd
に変更します
ここで Rubber Toy
が読み込めなくなります
Configure Stage
ノードを作成して Rubber Toy
のインプットに接続
Number of Resolver Context Strings
のパラメータを1にセットして
Value
パラメータに下記をセット
,{"$HH/usd/assets/hoge":"$HH/usd/assets/rubbertoy"}
Rubber Toy
ノードの Reload File
ボタンを押す
Rubber Toy
が読み込めたら正常に動作しています
おわりに
お疲れ様でした!
色々と書いていく内に凄く長くなってしまいました...
今回は Houdini を使って ArPathmapResolver
を作成しましたが
他のDCCツールでも置き換えたりすれば、同じようにビルドできるかと思います
これはシンプルなカスタムリゾルバーの一例でしたが、
カスタムリゾルバーを作成したい!という人の一助になれば幸いです
僕自身も、色んな人の記事で凄く勉強させてもらっているので
こういった情報の共有をこれからも続けていければなと思います!
ありがとうございました!