【Maya】Mayaの相対パスの挙動とファイルの実際のパスを取得する方法

Mayaでテクスチャの参照があるシーンを作成時と異なるパスに配置した状態で開く、みたいなことってあると思うんですが、このときプロジェクトがちゃんとセットされていれば相対パスでテクスチャが参照されますよね。
このときの挙動の詳細や、それによって起こる問題の解決法を書いてみます。

Mayaの相対パスの挙動

Mayaでプロジェクトをセットした状態でMaterialを作成してファイルノード作ってワークスペースのsourceimagesにあるファイルを参照した場合を考えてみます。
f:id:tm8r:20180403130445p:plain
AttributeEditorを見るとこのように「sourceimages」から始まっています。

このとき、シーンファイルには以下のように記載されています。

createNode file -n "file2";
    setAttr ".ftn" -type "string" "/Users/tm8r/Documents/maya/projects/default//sourceimages/chara01_tex.png";

sourceimagesの前が「//」になってるのがミソです。
これがMayaにおける相対パスを示し、「//」以前のパスが存在しない場合に限り、「//」以前のパスがシーンを開いた際のワークスペースに置き換わる形になるわけです。

このとき、ImageNameのテキストフィールドを同じパスを示す別の形に直接書き換えても、参照が解決出来る限りシーンファイルに記載されたパスは変わりません。
ただし、これを別のワークスペースで開いて保存した瞬間、「//」は「/」に置き換わります。

ちなみに、パスが「D:/maya/projects/hoge/sourceimages/chara01_tex.png」になっている状態で、このパスが存在しない、かつワークスペースが「/Users/tm8r/Documents/maya/projects/hoge」になっていて、このワークスペースの「sourceimages」などに同名ファイルが存在する場合、勝手にこれを参照します。なるほど?

テクスチャのパスを参照してみる

Windowsでシーンを作成してテクスチャのパスが「D:/maya/projects/hoge//sourceimages/chara01_tex.png」のパターンを考えてみます。
このシーンをMacで適切にプロジェクトをセットした状態で開くとテクスチャはちゃんと参照できます。

というわけでこのテクスチャのパスをgetAttrで取得してみます。

for f in cmds.ls(type="file"):
    print(cmds.getAttr(f + ".fileTextureName"))

すると結果はシーンのファイルに保存されているパス、つまり「D:/maya/projects/hoge//sourceimages/chara01_tex.png」が返ってきます。
ようはgetAttrでfileTextureNameアトリビュートからパスを取得を試みても、必ずしも実際に参照しているパスが返ってくるわけではないということです。

じゃあどうやればよいかというと、filePathEditorをごにょればいけます。

こんなかんじ。やったぜ。
何で実際のパス取得するだけにこんなコード書かないといけないんや…。

テクスチャのパス参照をするコードの説明

軽く説明すると、10行目の以下のコマンドでファイルのあるディレクトリが返ってきます。

cmds.filePathEditor(q=True, status=True, relativeNames=True, listDirectories="")

ただこいつはちょっと使いづらくて、「[パス, パスの解決状況, パス, パスの解決状況,…]」という感じで結果が返ってきます。
ので、2項目ごと処理をすればおっけーです。

具体的には以下のような感じです。

[u'/Users/tm8r/Documents/maya/projects/default/sourceimages', u'1']

解決状況は1が解決済み(存在する)、0が未解決(存在しない)という感じです。
型がintじゃなくてunicodeなので比較のときは注意。

また、relativeNamesは相対パスで解決できるものは相対パスで返却するフラグです。
したがって、プロジェクトが適切にセットされていて、相対パスで解決できるディレクトリが存在する場合は以下のような結果が返ってきます。

[u'../sourceimages', u'1']

次に上のディレクトリ情報を用いて17行目で配下のファイル情報を取得しています。

cmds.filePathEditor(q=True, status=True, withAttribute=True, listFiles=dirs[i])

この結果も同じような感じで「[パス, アトリビュート, パスの解決状況, パス, アトリビュート, パスの解決状況,…]」みたいなのが返ってきます。
ので3項目を1セットとして判定していけばよいわけです。

おまけ

相対パスで解決できてる、かつシーンに保存されたファイルのパスが存在するとき一番上の画像の通りAttributeEditorで「sourceimages」から始まっています。
そしてこの表示はconnectControlの仕様になっています。

したがって以下のようにすればAttributeEditorの表示と同じ結果を取得できます。

cmds.window()
cmds.columnLayout()
texf = cmds.textField()
nodeName="file2"
cmds.connectControl(texf,nodeName + ".fileTextureName",fileName=True)
print(cmds.textField(texf,q=True,tx=True))

しかし、相対パスで解決できていようと、シーンに保存されたファイルのパスが存在しない場合はフルパスで始まる形になります。
ので、ここの値を使っても相対パスで解決できているかどうかは判定できない場合があります。罠。

おわり

相対パス便利だけど厄介。

上のコードをちょっと変えればファイルが相対パスで解決できてるかどうかもチェックできると思うので、そのあたりで困っている方はご活用くださいませ。
ちなみに、そもそもシーンに相対パスとして保存されているかどうかは今調べた限りだとシーンをパースするしかなさそうな雰囲気です。つらみ。

スポンサーリンク