graphics.hatenablog.com

技術系テクニカルアーティストのあれこれ

Substance Designer の動的な構成管理。

ざっくり触ってみてこりゃ無理だなと思ったので。

なお、Substance Designer は Maya なんかと比べると色々な箇所が速く変わっていくソフトウェアなので、ここで書いてあることが数カ月後には通用しなくなっている可能性もある。その場合はご了承を。*1

ヒューマンエラーに対する考え方

 まず最初にこれを書いておく必要がある。

 ヒューマンエラーを扱う文脈では、"99%" と "0%" はまったく同じ意味 であり、"100%" か "それ以外" かという考え方が適用される。エラーが "絶対に起きない" か "起きる可能性がある" かの二択 ともいえる。*2

 なぜわざわざこんなことを書いたかは、このエントリを読みながら察していただければ幸い。なおこのエントリ、8割がたは Substance Designer に対する愚痴であることもあらかじめお断りしておく。

設定の階層化

Pipeline and Project Configuration - Substance Designer

 Substance Designer (以下「SD」)の設定は 複数の SBSPRJ を階層的に構成する かたちで行う仕組みになってる。

 これはつまり、まずルートプロジェクトとしての Default Project というものがあって、それを User Project で上書きする。更にいくつもの Project を優先度付きで設定することができて、優先度の低い順に設定値(設定ファイルに書かれた値)が適用されている。

 たとえば Default Project > User Project > Company Project > Team Project という順番で SBSPRJ を構成した場合、以下のように連鎖的に設定値が適用されていく。

  1. Default の設定を User が上書き(Default+User)する。
  2. Default+User の設定を Company が上書き(Default+User+Company)する。
  3. Default+User+Company の設定を Team が上書き(Default+User+Company+Team)する。

 このように SBSPRJ の優先度を記述するためのファイルが SBSCFG *3で、基本的には、制作チームごとに SBSCFG を用意する かたちになる。

相対パスによるファイル指定

SBSPRJ の相対パス指定

 さて、一定規模以上のパイプラインエンジニアリングの経験があれば、ここでふと思うことになる。「SBSCFG に SBSPRJ を書き込むってことは、SBSPRJ 自体は相対パスで指定しておいて、開発環境と本番環境の切り替えはパブリッシュ時に解決すればいいのかな?」と。

 つまり、こんなかんじの SBSCFG の記述をまずは試すことになる。

<root>
  <projects>
    <projectfiles>
      <size>1</size>
      <_1 prefix="_">
        <path>../../myconfig.sbscfg</path>
      </_1>
    </projectfiles>
  </projects>
</root>

 結論からいうと、このかたちで SBSCFG する方法はそう遠くないうちに破綻する。SD の Preferences Editor が、相対パス絶対パスに展開した上で SBSCFG を上書きしてしまう可能性があるからだ。

相対エイリアス

 更に SBSPRJ には「相対エイリアス」という機能があり、以下のような設定を記述することができる。

<urlaliases>
  <size>2</size>
  <_2 prefix="_">
    <path>file:Base</path>
    <name>BaseAlias</name>
  </_2>
  <_1 prefix="_">
    <path>file:Tools</path>
    <name>ToolsAlias</name>
  </_1>
</urlaliases>

 こうすると、プロジェクト内でパスを記述する際に「BaseAlias://foo/bar.png」という形式を利用でき、うまく使えば非常に便利な機能になりうる。そしてこの機能は親フォルダを参照する相対パスがサポートされており、以下のような記述が可能になっている。*4

<urlaliases>
  <size>1</size>
  <_1 prefix="_">
    <path>file:../Tools</path>
    <name>ToolsAlias2</name>
  </_1>
</urlaliases>

 SBSPRJ 内では環境変数を利用することができないので、あるいはその代替として用意されている機能なのかもしれない。*5

 ただしこの場合も、「SBSPRJ の相対指定」と同じく、SD 自体がこれを絶対パスに展開した上で SBSPRJ を上書きしてしまう可能性がある。

 なお、相対パスで親ディレクトリを参照していない場合に限り、絶対パスに展開されることはない。これは上記 SBSCFG の場合でも同じだけど、そもそも親を参照してようがいまいが、相対パス相対パスだろう。ドキュメントには it's strongly recommended to put your sbsprj files next to the folders you want to watch! と書かれてはいるものの、そんな単純な想定ですべてがうまくいくわけがない。*6

相対パスが展開されることの弊害

 まず真っ先に思いつくのは 開発環境用の絶対パスが書き込まれてしまう ことだろう。

 たとえばテキストエディタなりで作成した開発環境の SBSCFG を SD に読み込んで、適切に反映されているのを確認するために SD の Preferences Editor を開く。すると SBSPRJ の設定が漏れていたことに気付いて、GUI 上で SBSPRJ の指定を追加する。「これでよし」と思って OK ボタンを押すと、その瞬間にすべての SBSPRJ のパスが絶対パスに展開されて SBSCFG に保存される。そのまま本番リリースされてしまえば、立派なデータバグの完成だ。

 もちろんすべての編集をテキストエディタスクリプトで行うよう徹底していれば、GUI 上で OK や APPLY ボタンを押すこともなくなり、バグが入り込む余地はない。ただ少なくとも自分は、いついかなるときでもそれを 100% 徹底できる自信はない。

 さらに凶悪なのは ユーザが気付かないうちに SBSPRJ を上書きしてしまう ことだ。

 上に書いたとおり、Preferences Editor で OK か APPLY をクリックした瞬間に SBSCFG が書き換わってしまうのだが、これは SBSPRJ にも同じことがあてはまる。つまり、制作チームのアーティストが自分のチーム向けの SBSPRJ を Preferences Editor で編集しているとする。無事編集を完了して OK ボタンを押すと、すべての SBSCFG と SBSPRJ 内の相対エイリアス絶対パスに展開された上で、それらが上書き保存される。本人はそれを意図していないにも関わらずだ。これはもう避けようがない。

相対パスが展開されないために

運用でカバー

 一番簡単なのはこれだろう。

  • 開発用の SBSCFG や SBSPRJ が本番に紛れ込まないような確認フローを組む。
  • 複数のパスの切り替えが想定される場合、切り替え先候補のパスをすべて列挙しておく。
  • SBSPRJ を編集する場合は、チーム内で声を掛け合いながら、適宜テクニカルアーティストなどに相談しながら行う。

 具体的な対策はいくらでも考えられるけど、小規模なチームだったり、制作ラインの数が十分に少なければ、こういった対処が一番コストが安くなりうる。あるいは、大規模制作で間々見かける「限られたごく少数の人間のみが SD を利用する」フローが確立されていて、かつ、SBSCFG と SBSPRJ が他の制作ラインと共有されていないのであれば、うまくいくかもしれない。

 あるいは、制作ルールがガチガチに決められていて、そこから逸脱することが一切許されないような状況を常に維持できるのであれば、制作規模やライン数に関わらず有効だろう。もっとも、まっとうな人間がそんな環境で生きていけるとは思えないが。

フェールセーフな構成管理フローの設計

 「失敗しても安全な状況を担保する」設計のことをフェイルセーフと呼ぶ。ヒューマンエラーを扱うパイプラインエンジニアリングの基本設計のひとつとも言える。*7*8

 今回の場合、そもそもの問題は SD の Preferences Editor を経由して SBSCFG と SBSPRJ が書き換わってしまう点にある。つまり SD のシステム的な部分であって、フールプルーフを実現することができない。また、ファイルの書き換え自体を防ぐことはできない上に書き換え内容次第では事故を防ぐ術が無いので、完全なフェイルセーフも難しい。であれば、ファイルが書き換わってしまったときの復旧コストを如何に抑えることができるか、つまり、どこに復旧ポイントを置くことができるか がこの問題に対する回答となりうる。

 そうなると、やっぱり一番無難なのは SD 起動時だろうか。「なんかおかしくなったら再起動してね!」というのは、多くのアーティストにとって馴染みのある対応だ。また、何かランチャーなどを介して SD が起動されることも考えられるが、たとえば SD 起動用バッチを配布するなどして SD の起動自体をフックすることができれば、たいていのケースに対応できる。*9*10

 とりあえず今回は、ざっとこんな流れで構成管理フローを考えてみた。

  1. SBSCFG と SBSPRJ 内で、相対パス(とできれば環境変数)を使えるようにしたい。
  2. ユーザーが意図せず SBSCFG と SBSPRJ を書き換えてしまっても問題ないようにしたい。
  3. SD 起動時の時点で上記を担保したい。
  4. てことは SBSCFG と SBSPRJ を SD 起動時に自動生成すれば良い?
  5. アーティストが SBSCFG を編集できなくなるが大丈夫か?
    1. SBSCFG 自動生成に適切に介入できる仕組みがあれば大丈夫だろう。
  6. アーティストが SBSPRJ を編集できなくなるが大丈夫か?
    1. 自動生成する SBSPRJ と既存の SBSPRJ を同列に扱うことができれば大丈夫だろう。

Substance Designer の動的な構成管理

 ここまで見えてくれば、もはや難しいことは何もない。

SBSCFG の自動生成

 まずこれには、「こちらが管理したい構成を書き込んだ SBSPRJ のファイルパス」と「ユーザーが用意した SBSPRJ のファイルパス」を XML として書き込んでやればいい。Compatibility Display の設定は、デフォルトでは指定なし、指定する場合は独自の環境変数や構成ファイルを別途用意して、そこから読み取るようにすればいい。

 SBSPRJ ファイルの列挙順がそのまま設定値適用の優先順位になるので、ここだけは気を遣う必要がある。「Default Project」「User Project」「自動生成した Project」「それ以外の Project」の優先順位をきちんと整理しておこう。ポリシーにもよるけど、基本的には Default > User > Autogen > Others の順になることが多いのだと思う。

SBSPRJ の自動生成

 こちらも大枠では SBSCFG の生成と変わらない。設定すべき内容を環境変数や構成ファイルに用意しておいて、それを読み取って XML に書き込んでいく。それなりに大きなファイルになる可能性もあるので、XML をイチから生成するか、何かしらのテンプレートエンジンを利用するかは状況次第だろう。いずれにせよ、既存の SBSPRJ を上書きするよりは、多少面倒でも新規に SBSPRJ ファイルを書き出すようにしたほうが、生成処理を再入可能にする必要がないのでメンテコストが低くなりやすい。

自動生成した SBSCFG で SD を起動する

 これは Substance Designer.exe の --config-file オプションを利用すべきだろう。独自の SBSCFG ファイルを指定する方法として 公式 でも勧められている。ここは素直に従ってよさそうだ。

余談

 まぁなんていうか、環境変数が利用できず相対パスもまともに機能しない時点で、諸々の管理は自前で動的に行う以外の選択肢はないかなとは思った。まだ自宅の環境でしか試してないし、多少脳筋なやり方でもあるけど、他にまともなやり方は(少なくとも現時点では)思いつかない。

*1:現時点ではまだ個人的な検証結果にすぎないのでこうしてブログに書いているのだけど、逆にいえば今回のエントリーの内容は実戦投入されているものでもないので、その点もご了承を。

*2:もちろんその後でリスク評価を行い、事前対処コストや事後対処コストをふまえた上で対応を行うのだけど、それはあくまで、"100%" か "それ以外" かの判断を行ったあとの話。

*3:レンダリングエンジンの指定もここで一緒に行う。

*4:少なくとも、このように書かれた設定値は SD に正しく反映される。

*5:個人的な想像だけど。でもぶっちゃけこんな機能よりも普通の環境変数を展開してくれるほうがずっとありがたい。

*6:おそらくだけど、制作ライン間で相応のパイプライン共有が行われていて、全社横断的なパイプラインエンジニアリング組織を持っているようなスタジオでは、経験上なかなか厳しいだろうと思う。

*7:あとは、「そもそも失敗できないようにする」設計もあって、それはフールプルーフと呼ぶ。他にもフェイルオーバーとかフェイルバックとか色々。

*8:基本的な発想として、ユーザーインタラクションが絡むパイプラインはフールプルーフを目指すべきだと個人的には思っている。

*9:そして何より、この対応を行うにあたってアーティストは小難しいことを一切考えずに済む。

*10:あるいは監視デーモンを用意してもいいかもしれないけど、開発メンテのコストが不当に高いので却下。