チュートリアル / プラグインを作ってみよう!ゲーム開発のためのツール製作講座
第3回:Softimage編 Pythonを使ったプラグイン作成

  • ゲーム
  • コラム
  • スクリプト・API
  • チュートリアル
  • 上級者
  • 中級者
前回のコラムではC++を使ったdllタイプのプラグインを作ってみました。今回はPythonを使ったプラグインを作ってみましょう。

こちらのコラムでは数回に分けてゲーム開発向けのCOLLADAのエクスポーターを作っていきます。この手のエクスポーターの作り方はいくつか考えられますが、私が好きなのはエクスポーター本体とインターフェースを分離して作る方法です。エクスポーター本体をコマンドとしてスクリプトから呼び出せるようにしておくと、汎用性が高くなって便利です。このように分離しておくと、エクスポーターを使用しているプロジェクトごとにインターフェース部分をカスタマイズすることができます。逆に全部まとめて作ってしまうと、個別に対応することになり、エクスポーター作成者の負担が大きくなってしまいます。

このコラムで作成していくエクスポーターは本体部分をC++で作り、インターフェースの部分をPythonで作ります。今回はこちらのインターフェース部分の作り方を説明していきます。こちらを先に作っておかないと、エクスポーター本体のテストをするときに面倒なのです。

とはいえ、いきなりメニューに組み込むタイプを作るのは大変なので、まずは先週のHelloWorldプラグインのPython版を作ってみましょう。こちらのファイルをダウンロードして展開してください。今回使用するPythonのプラグインが入っています。

[AJ_SISDK_201109.zip]

”HelloWorldPython.py”がSoftimage上で動作する最少のPythonプラグインです。プラグインマネージャーのウィザードで作ったものとほとんど同じ内容になっています。特定の関数を用意しておくところは前回と同じですね。内容に関しては特に説明することもないと思います。Pythonなのでインデントに気を付けるぐらいでしょうか。

このファイルを"$(XSI_USERHOME)/Application/Plugins"にコピーして、Softimageを起動してください。このプラグインはSoftimageの起動時に自動的に読み込まれます。まずSoftimageの起動時にXSILoadPlugin()が呼ばれます。Softimageの起動後にスクリプトエディタを開くと、XSILoadPlugin()が実行されていることが分かります。

今度はスクリプトエディタ上でApplication.HelloWorldPython()と入力して、このプラグインを実行してみましょう。最初に実行したときはHelloWorldPython_Init()が呼ばれてから、HelloWorldPython_Execute()が呼ばれます。2回目以降はHelloWorldPython_Execute()だけ呼ばれることがわかります。

XSIUnloadPlugin()はSoftimageの終了時に呼ばれますが、プラグインマネージャーから再ロードして呼び出すこともできます。プラグインマネージャーの「ツリー」タブの「ユーザールート」「プラグイン」からHelloWorldPythonを探して、右クリックで「再ロード」を実行すると、このプラグインを再読み込みします。このときはXSIUnloadPlugin()が呼ばれてから、再度XSILoadPlugin()が呼ばれることがわかります。



また、プラグインを書き換えて保存すると自動的に再読み込みが行われます。このときプラグインに必要な関数が見つからないと、プラグインマネージャーのアイコンが赤くなります。このときはスクリプトエディタにエラーメッセージが出ているので、それを元に修正します。


次にメニューに組み込むタイプのPythonプラグインを作ってみましょう。
“ HelloWorldPythonInMenu.py”を"$(XSI_USERHOME)/Application/Plugins"にコピーしてください。

メニューに追加するので、先ほどのプラグインとはXSILoadPlugin()が少し違います。今回はサンプルなので「カスタムメニュー」を追加するところはどこでもいいのですが、エクスポーターと同じく「ファイル」の「書き出し」に追加してみます。

メニューにカスタムメニューを追加するときはRegisterMenu()関数を使います。最初の引数で追加する場所を指定します。今回は「書き出し」に追加したいので"constants.siMenuMainFileExportID"を指定しています。

in_reg.RegisterMenu( constants.siMenuMainFileExportID, "HelloWorldPythonInMenu_Menu", false )

"constants"というのはSoftimage側の定数です。これを使うためにスクリプトの先頭に

from win32com.client import constants

と追加してあります。ここら辺はSoftimageとPythonを使うときの「お約束」なので、あまり気にせずに使ってください。RegisterMenu()の2番目の引数は追加する「カスタムメニューの名前」です。Softimageのウィザードに倣って、プラグイン名に"_Menu"と付けたものにしておきましょう。

こちらのプラグインをロードしてメニューにアクセスすると、初回のみ「カスタムメニューの名前」+"_Init"という名前の関数が呼ばれます。今回は「カスタムメニューの名前」が"HelloWorldPythonInMenu_Menu"なので、HelloWorldPythonInMenu_Menu_Init()という関数が呼ばれます。"Menu"が続いてややこしいですね。すいません。

この中ではAddCallbackItem()という関数を使ってメニュー項目の追加と、メニューが選ばれた時の関数を指定します。この辺はちょっと複雑ですが、これも「お約束」なのでそのまま使っておけば問題ないと思います。ここではメニューが選択されるとOnHelloWorldPythonInMenu()という関数が実行されるようになっています。

menu.AddCallbackItem( "HelloWorldPythonInMenu...", "OnHelloWorldPythonInMenu" )

OnHelloWorldPythonInMenu()の中では前回C++で作成したHelloWorldプラグインを呼び出すようになっています。実際に呼び出す場合は、前回作成したHelloWorldプラグインを入れてから、呼びだしている部分のコメントアウトを外してください。

これでメニューの「ファイル」「書き出し」から追加したメニューを選んで、C++で作成したdllのプラグインを呼び出せるようになりました。この段階では追加したメニューを選んでも直接コマンドを呼び出すだけで、エクスポーターに必要なオプションが設定できません。またファイルの出力場所も指定する必要があります。

最後はこれらを盛り込んだプラグインを作ってみます。
“SIColladaExporter.py”を"$(XSI_USERHOME)/Application/Plugins"にコピーしてください。

こちらもいくつか実装方法が考えられますが、今回は最初にオプション設定画面を開いて、それから出力先を入力してもらう実装になっています。この辺はユーザーの使い勝手に影響してくるので、後でカスタマイズしてみるとよいでしょう。

先ほどのサンプルから大きく変わったのは、メニューが選ばれた時に実行されるOnSIColladaExporterProc()です。この中でダイアログを開いてオプションを表示し、そこからファイルダイアログを開いて出力ファイル名を設定するようになっています。

まずはオプションダイアログの部分を説明します。オプションを設定するためのダイアログを出す方法はいろいろありますが、ここではSoftimageの「カスタムプロパティ」を使っています。「カスタムプロパティ」は「任意の変数を複数まとめたもの」と思っておいてください。

OnSIColladaExporterProc()では最初にCreateCustomProperty()を呼び出して、カスタムプロパティをシーンのルートに追加しています。CreateCustomProperty()の内部では、カスタムプロパティを追加する前に存在チェックを行っています。これは同じものを重複して追加しないためです。今回はカスタムプロパティをSoftimageのルート上に作成するので、ルート上にカスタムプロパティが存在するかどうかチェックします。チェック方法はいくつか考えられますが、ここではSoftimageのルート上から"SIColladaExporter"という名前の「プロパティ」を取得して、そのクラス名が"CustomProperty"かどうかでチェックしています。

カスタムプロパティが存在しなかった場合はAddCustomProperty()を使って、ルート上に新しく追加します。最初の引数は「追加するカスタムプロパティの名前」です。2番目の引数は使わないので0にしておいてください。

cpset = root.AddCustomProperty( "SIColladaExporter", 0 )

AddCustomProperty()の戻り値が新しく作成したカスタムプロパティです。こちらはまだ入れ物しかないので、中身の変数を追加します。カスタムプロパティは"CustomProperty"クラスなので、そのAddParameter()というメンバ関数で変数を追加します。

cpset.AddParameter( "ExportAll", constants.siBool, constants.siClassifUnknown,constants.siPersistable, "ExportAll", "ExportAll", "", 1 )

今回追加するのはブール型が6つ、文字列型が1つです。AddParameter()の引数の詳細はヘルプを参照してください。ヘルプのキーワード"AddParameter"で"CustomProperty"を選び、いくつか表示される中のObjectModelの項目を選ぶと表示されます。

これでエクスポーターのオプション用のカスタムプロパティが作成されました。Explorerで表示するとルート上に作成されていることが確認できます。



作成したカスタムプロパティはShowPropertyDialog()の中で、Application.InspectObj()を使ってダイアログ表示しています。ここの使い方も「お約束」に近いのであまり気にしないでください。InspectObjの最後の引数がtrueの場合、キャンセルボタンが押された時にエラーが発行されます。今回は邪魔なのでエラーを出さないようにfalseにしています。

result = Application.InspectObj( in_customparam, None, in_title, constants.siModal, false )



ここまででカスタムプロパティを画面に表示して、ユーザーに設定してもらうところまでできました。次にファイルブラウザを開いて出力先のファイル名を指定するようにします。ここでは"XSIUIToolkit"というSoftimageのユーザーフェースインターフェースを使っています。"XSIUIToolkit"から"FileBrowser"のインスタンスを取得し各種パラメータを設定します。

fileBrowser = XSIUIToolkit.FileBrowser
fileBrowser.DialogTitle = "SIColladaExporter"
fileBrowser.FileBaseName = ""
fileBrowser.Filter = FileFilter

ここでは前回出力したフォルダをカスタムプロパティのパラメータに格納しておいて、"FileBrowser"の"InitialDirectory"にセットするようにしています。こうしておくと毎回フォルダを選ばないでよいので大変便利ですし、エクスポーター本体のデバッグを行うときにも役に立ちます。

fileBrowser.InitialDirectory = Application.GetValue( SIColladaExporterPSet + ".OutputPath" )

カスタムプロパティの値を取得するときはGetValue()を使います。こちらは取得したいパラメータの名前を文字列で指定して、値を戻り値として受け取ります。サンプルコードではSIColladaExporterPSetに"Scene_Root.SIColladaExporter"という文字列が入っているので、その後ろにパラメータ名を連結してパラメータの完全な名前を作り、GetValue()で値を取得しています。

値を取得するGetValue()に対して、値を設定するSetValue()という関数もあります。サンプルではファイルブラウザが閉じた後で、指定されたファイルのパスを取得してカスタムプロパティの変数に設定しています。

# 出力先を格納
Application.SetValue( SIColladaExporterPSet + ".OutputPath", fileBrowser.FilePath )

ファイルブラウザを表示するときはFileBrowserのShowSave()かShowOpen()を使います。今回はエクスポーターの出力先ファイル名をユーザーに指定してほしいので、ShowSave()を使っています。

fileBrowser.ShowSave()



これでエクスポーターのインターフェース部分が出来上がりました。次回からは、このインターフェースから呼び出されるエクスポーターの本体をC++で作っていきます。ようやく本題に入れますね……。


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