チュートリアル / 読んで触ってよくわかる!Mayaを使いこなす為のAtoZ
第77回:Mayaで複雑なツールを作る時のコツ – 実行内容のブレイクダウン

  • Maya
  • ゲーム
  • コラム
  • スクリプト・API
  • チュートリアル
  • 中級者
Mayaで複雑なツールを作る時のコツ – 実行内容のブレイクダウン

Mayaのコードやプラグイン、PythonやMELのツールを眺めたり読んだり作ったりしていると、意外と知られていない、もしくは認知されていないのでは?というコツに出くわします。折角なので忘れないうちにメモがてら、皆様にご紹介出来ればということで、複数回に分けて中級者向けの開発の話をしたいと思います。

スクリプトやC++などでツールを作っていると、Mayaのツールとしてのデザインのパターンが出てきます。使っている言語によって違いがあるものの、3DCGならではのアプローチを理解することで、上手にツールが作れるようになります。

今回注目したいのは「実行内容のブレイクダウン」と「関数で使うデータの取り扱い」、そして「独自のコンポーネント」についてです。

機能を実行する2つのスタイル

ツールを作り始めると、ループで何かを実行する事が多いですよね。操作した内容がスクリプトエディタに出てきますので、それをまとめて一つの機能を作ります。作った機能を選択したオブジェクトやコンポーネントに対して繰り返し実行します。

今回は次のようなツールの作成を想像しながら話をしていきます。選択したメッシュオブジェクトで、上の方向(Y方向)を向いたフェースを細分化するツールを作るとしましょう。実行すると次のような結果を得られるとします。

選択したメッシュオブジェクトで、上の方向(Y方向)を向いたフェースを細分化する

ツールの作り方として大きく分けて二通りあり「一連の作業を繰り返す方法」と「ステップごとに処理する方法」があります。

それぞれの方法について詳しく見ていきましょう。

一連の作業を繰り返す方法

Y方向を向いたフェースを細分化するのに、次の手順で実行する方法がこれに当たります。

1. 一つのフェースで、Y方向を向いているか確認。
2. 向いていれば細分化する。
3. 1と2を全てのフェースで繰り返す。

Y方向を向いたフェースを細分化するのに、実行する方法1つ目

実行結果をマクロにしたような感じです。多くの場合で、手動でやっていることとコードの内容が同じ様になるため、想像しやすいですね。

Yを向いているかどうか判定するところは少々複雑になります。次の段階としては、複雑な部分は関数として、機能としてくくりだすことになります。次のような構成になります。

複雑な部分は関数として、機能としてくくりだす時の構成

この実装方法は、実装が早くて簡単です。単純なツールではこれで十分なことが多いです。実行途中で失敗した時、実行の流れが止まるのはまさに今処理をしようとしていたコンポーネントやオブジェクトの部分です。そのため原因箇所が一目瞭然です。(止まったときの状態を見れば、何が問題だったかわかりやすいですし。)

また、実行途中で失敗しても、そこまでの成功した結果はシーンに残るため、うまく行ったところはそのまま使うことができます。うまく行かなかったところは手作業でどうにかする、というアプローチも可能です。

デメリットとしては、単純な処理を繰り返している場合は問題にならないのですが、色々なデータや、他の実行結果を使ってなにかをするようになると、うまく管理できなくなります。

例えば、前のコンポーネントの処理ループ時に実行した内容を、次のループで使用するなどし始めると、段々ややこしくなって管理しきれなくなります。もしメッシュのフェースを順に削除していくような処理をしたなら、前のループ時にフェースを削除すると、メッシュ全体のフェースIDが変わってしまうため、次のループでは対象となるフェースのIDが変わっているかもしれません。

複雑で長い処理になると「一連の作業を繰り返す方法」では手に負えなくなってきます。

ステップごとに処理する方法

実行内容をブレイクダウンして、処理をステップごとに分けて順に実行する方法がこの方法です。今回のツールは次のように実行できます。

1. Y方向を向いたフェースを全てリストアップする。
2. 対象となったフェースに対して細分化を実行。

ステップごとに処理する方法
ステップごとに処理する方法

一見複雑に見える処理でも、実行のステップが存在します。複雑なツールは自分が理解できる単純なステップに分解して実行することで実現出来ます。手動でやってみて、やったことをステップに分けてみて、ステップごとに処理していくことになります。

プログラム的に言えば、自分が理解できるステップごとに関数を用意します。「一連の作業を繰り返す方法」のところでも実行内容の関数化を行っていましたが、こちらの方法はより関数がアルゴリズムとして分けられるようになります。

この様にしっかり機能を分けると、やりたいこと、やっていることが明確になります。各機能では実行する時にどういうデータが必要なのか、どういう結果が得られるかが明確になります。

他のツールでもこの方法について考えてみましょう。

例えば、エッジ同士をつなげてブリッジを作る機能を自分で作ることを想像してみてください。このツール、結構ややこしいですよね・・・。

ブリッジ処理のステップをノード化したもの

手動でやってみると、「繋がりそうなエッジ同士をつなげればいいだけ」なのですが、これをプログラム化しようとすると途端にややこしくなります。ややこしいと思ったなら、単純なステップに分解すればよいのです!次のように分解して考えることができそうです。

・ 選択しているエッジを見つける(エッジが選択されているかの確認)
・ 一連のエッジをA側、B側という風に分ける。
・ A側B側のエッジ一つずつで、ブリッジ先として対応するエッジを見つけてリストを作る
・ エッジとエッジの間をどうやって補間するか決める
・ これまでの情報をもとにポリゴンを作る

実は、コードを書くと分かりますが、ステップに分けると「一連の作業を繰り返す方法」と比べて、大抵の場合コードが若干重複し、メモリを多く消費します。各ステップで何度もコンポーネントをループすることになりますし、次のステップのためのデータを一時的にとっておく必要があるためです。

一方で、まとめて処理することにより効率よく実行出来ることもよくあります。何よりもステップを分けるということはアルゴリズムごとに分解出来るということですから、後からコードを読んで意味がわかる状態にできます。不具合やボトルネックを見つけやすくなります。結果として、大掛かりなツールを作るときには実装が早くて安全な方法だったりします。

ステップに分けた状態は、さながらノードのグラフとして想像できます。テキストではわかりにくいですが、こうしてイメージ化すると全体像も詳細も人に理解しやすい状態になります。

ブリッジ処理のステップをノード化すると次のようになります。

実際、MayaやHoudiniの様にノードグラフで処理をするソフトウェアでは、ノードがステップに当たります。ステップには必要なデータを与え、結果を得ます。一つのステップで完全なツールの結果を得るのではなく、複数のステップの実行により最後にツールの結果を得ます。遠いところまで行くには、ちょっとずつ基本をきっちり順にやっていくべし!という感じですね。

「一連の作業を繰り返す方法」よりも複雑ですが、ステップに分ければ必要に応じてステップを付け足していくだけですので、ツールを完成させるための確実性が上がります。どこがうまくいかないのか、全体なのか部分なのかも把握しやすくなります。どうしても上手くいかないステップがあれば、それは別のアプローチで考えたり、プログラマにちょっと手伝ってもらったりということも出来ますし、色々な面で有利です。

ちなみに、テレビで工場の生産ラインを見ると、なんとなくこの図が思い浮かびます・・・。まずもち米を蒸す、次に練る、次に伸ばす、冷やす、三日月型にカットする、焼く、味をつける、という感じで。世の中効率化を考えると、なんでもこのスタイルになるようです。

まとめ

「一連の作業を繰り返す方法」の実装方法でメリットが十分に出ているなら、そのままで何も変える必要はありません。もし、なんだか管理しづらくなってきた、と感じたら「ステップごとに処理する方法」に移って、処理をブレイクダウンするタイミングが来ているということです。

始めは効率悪く感じるかもしれませんが、ツールを完成させればメンテナンスのしやすさを感じられると思います。きっとプログラミングのスキルがステップアップ出来ること間違いなし!ですので、気になったらぜひチャレンジしてみてください。

製品購入に関するお問い合わせ
オートデスク メディア&エンターテインメント 製品のご購入に関してご連絡を希望される場合は、こちらからお問い合わせください。