1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Universal Scene DescriptionAdvent Calendar 2024

Day 14

[USD/C++] ArPathmapResolverを作ろう [Github]

Posted at

はじめに

この記事は Universal Scene Description Advent Calender 2024 の14日目の記事です

今回は Asset Resolution 2.0ArPathmapResolver を作成した話をしたいと思います!
せっかくなのでビルドも試せるように、ソースコードも 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 ContextAsset Resolver に関連付ける事で、
特定の動作を変更したり、異なる検索パスを指定したりする事ができます


より詳しく知りたい方は、いつもお世話になっている @fereria さんのページや、先程の LucaScheller さんのページもご覧下さい


という事で、今回に関しては Asset Identifier を特に変えなくてもよさそうだったので、
Asset ResolverAsset 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.inplugInfo.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 に移動して

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_DEBUGHOUDINI_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を立ち上げてもらっても大丈夫です

Hython
# 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

/src/resolverContext

こちらも、関数などを改めて実装しています

  • 下記関数などを追加
    • public:
      • == オペレータ
      • GetAsString
      • hash_value
      • ArGetDebugString

Resolveのフローチャート

ArDefaultResolverResolve 関数が呼ばれた時の流れをフローチャートにしました

ビルド

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::pythonResolver クラスを登録するための関数を定義

/src/wrapResolverContext

- boost::pythonResolverContext クラスを登録するための関数を定義

ビルド

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
Python
from pxr import Ar
Ar.GetResolver()
from usdCustom import PathmapResolver
resolver = Ar.GetUnderlyingResolver()
resolver.SetDefaultPathmapEnvironment("ANY_PATHMAP")

  • コンテキストに応じたパスマップの変更:
    • パスマップの設定は、コンテキストに基づいて
      柔軟に切り替えられるようにする

  • CreateContextFromString によるパスマップ指定:
    • CreateContextFromString 関数に渡された文字列でもパスマップは指定可能
    • 文字列の , 以降をパスマップとして扱い、それに基づいてリゾルバーがパスマップを設定
Python
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:
      • _ParsePathmapDict
    • public:
      • SetDefaultPathmapEnvironment

/src/resolverContext

  • パスマップ辞書を引数に持つコンストラクタを追加
  • 下記関数を調整
    • public:
      • == オペレータ
      • GetAsString
      • hash_value
  • 下記関数を追加
    • public:
      • GetPathmapDict

/src/wrapResolver

  • SetDefaultPathmapEnvironment 静的関数の追加

/src/wrapResolverContext

  • パスマップ辞書を引数に持つコンストラクタや、
    GetPathmapDict 関数の追加

パスマップのフローチャート

結果 ArDefaultResolverResolve 関数の途中に処理を入れた形になりました

ビルド

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を立ち上げてもらっても大丈夫です

Hython
# 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ツールでも置き換えたりすれば、同じようにビルドできるかと思います

これはシンプルなカスタムリゾルバーの一例でしたが、
カスタムリゾルバーを作成したい!という人の一助になれば幸いです

僕自身も、色んな人の記事で凄く勉強させてもらっているので
こういった情報の共有をこれからも続けていければなと思います!

ありがとうございました!

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?