チュートリアル / プラグインを作ってみよう!ゲーム開発のためのツール製作講座
第2回:Softimage編 最初のプラグイン”HelloWorld”
- ゲーム
- コラム
- スクリプト・API
- チュートリアル
- 上級者
- 中級者
前回はSDKの話で終わってしまったので、今回はちゃんとしたプラグインを作ってみましょう。今回作成するのはScriptEditorに"HelloWorld"と表示するだけの、一番シンプルなプラグインです。Pythonでは一瞬で終わってしまうので、ここではC++APIで作ってみます。このあたりはSoftimageの日本語ヘルプにも説明がありますので、そちらも読んでおいてください。また、このコラムではVisualStudio2008とSoftimage2011を使用してプラグインを作っていきます。
Softimageにはプラグインのひな形を作成してくれるウィザードが用意されているので、こちらを使ってもよいのですが、今回は説明のために1から作っていきます。まずVisualStudioを起動して、「VisualC++プロジェクト」→「Win32コンソールプロジェクト」を選びます。アプリケーションの設定では「アプリケーションの種類」で「DLL」を、「追加のオプション」では「空のプロジェクト」を選びます。これでdllを作るための空のプロジェクトができました。このままでは空なのでmain.cppというファイルを作って追加します。以下のコードはこちらに追加してください。
ソースコード中でSoftimageSDKのクラスを使うためには、C++APIのヘッダファイルが必要です。以下のヘッダファイルをインクルードしてください。
ここまでで一度コンパイルしてみましょう。SoftimageSDKのインクルードファイルが見つからないとエラーがでるはずです。これはSoftimageSDKの場所がインクルードパスに追加されていないからです。パスを直接指定してもよいのですが、そうするとSoftimageのバージョンが変わった時に毎回変更する必要があり大変面倒です。
Softimageは起動時に環境変数の設定を行うので、こちらをVisualStudioから利用すると便利でしょう。スタートメニューの「Autodesk Softimage 2011」から「Command Prompt」を実行すると、環境変数の設定が終わった状態でDOSプロンプトが起動します。こちらからVisualStudioを起動すれば、Softimageの環境変数を利用することができます。
毎回コマンドプロンプトからVisualStudioを起動するのが面倒な方は、環境変数の設定を行うバッチファイルを複製して、最後にVisualStudioを起動するコマンドを追加しておきましょう。Softimageをインストールしたフォルダの「Application\bin」の「setenv.bat」をコピーして適当な名前にリネームします。そして最後の行にVisualStudioを起動するコマンドを追加します。こちらの例では「sample.sln」というソリューションを開いています。こちらを実行すると、Softimageが必要とする環境変数の設定を行った後でVisualStudioを起動して「sample.sln」を開きます。
この環境変数の設定は「非常に」重要です。この設定を行うと環境変数が利用できるだけでなく、VisualStudioからSoftimageを起動してデバッグすることができるようになるからです。後ほどプラグインが完成したら、実際にデバッグ実行してみましょう。
これでVisualStudioからSoftimageの環境変数が利用できるようになりました。環境変数「XSISDK_ROOT」を使ってインクルードパスを設定しましょう。「XSISDK_ROOT」は名前の通り、SoftimageSDKのルートフォルダを指します。プロジェクトのプロパティから「追加のインクルードディレクトリ」に「$(XSISDK_ROOT)¥include」を追加してください。
これでインクルードファイルが見えるようになったと思います。それではプラグイン本体のコードを追加しましょう。まず先頭に「using namespace XSI」を追加します。C++APIのクラスは「XSI」というネームスペースに入っているので、これを省略するためです。C++APIのクラスには「Geometry」や「Material」といったありふれたクラス名が入っているので、ユーザー側のクラス名とぶつからないように注意してください。
Softimageのプラグインには以下の4つの関数が最低限必要です。下2つの関数の名前は作成するプラグインの名前が先頭に付きます。
XSILoadPlugin()とXSIUnloadPlugin()の中身は毎回同じなのであまり気にすることはないと思います。私が作るプラグインでは、ロード時にプラグインのバージョンを表示するようにしています。プラグインを更新したつもりが更新されていなかった、というトラブルがゲーム開発の現場ではよく起こるからです。本当によく起こるんですよ……。必ずプラグインを使っている人がバージョンを確認できるようにしておきましょう。dllのファイル本体の更新日時はバージョン管理ツールなどを経由すると変わってしまうので、このように表示したほうが安全です。表示するバージョンは手動で設定するとよく忘れるので、ビルドした日時が自動で入るようにしています。
HelloWorld_Init()はプラグインが初期化されるときに呼ばれる関数ですが、今回は何もしていません。HelloWorld_Execute()がこのプラグインの実行部分ですが、今回はHelloWorldと表示するだけです。文字列の表示はApplicationクラスのLogMessage()で行います。ApplicationクラスはSoftimageのアプリケーション自体に相当するクラスで、どこでも定義して使うことができます。LogMessage()の引数は表示したい文字列ですが、先頭にLが付いていることに注意してください。C++APIでは基本的にワイド文字列を扱います。
実は通常の文字列(char)もLogMessage()に渡すことができます。先ほどのバージョン情報を表示しているところがそうですね。これはLogMessage()の引数であるCStringクラスが文字列の変換を行ってくれるからです。
ここまでコードを追加したところでビルドしてみましょう。リンクエラーが出るはずです。プラグインで使用しているSoftimageSDKの「sicppsdk.lib」がリンクされていないからです。まずVisualStudioの「追加のライブラリディレクトリ」へ「$(XSISDK_ROOT)¥lib¥nt-x86」を追加します。これでSoftimageSDKのライブラリが見えるようになったので、「追加の依存ファイル」に「sicppsdk.lib」を追加しましょう。これでビルドが通るようになります。
完成したプラグインはビルドイベントで自動的にSoftimageのプラグインフォルダへコピーされるようにしておくと楽です。環境変数「XSI_USERHOME」がユーザーホーム(デフォルトではC:¥Users¥(UserName)¥Autodesk¥Softimage_20XX)を指しているので、こちらを使うとSoftimageのバージョンに依存せずに書けます。dllの出力場所によって多少変わりますが、このようなコマンドをVisualStudioの「ビルド後のイベント」に追加しておくと自動的にdllのコピーが行われます。こちらの例では「リンカ」の「出力ファイル」を「$(ProjectName).dll」に変更して、プロジェクトファイルと同じフォルダにdllが出力されるようにしています。
コピーができたらVisualStudioからSoftimageを起動してみましょう。「デバッグ」の「コマンド」に「$(XSI_BINDIR)¥xsi.exe」を設定するとSoftimageを起動できます。環境変数「XSI_BINDIR」はその名の通り実行ファイルが置いてある場所を指します。
実行するとSoftimageが立ち上がります。ScriptEditorを起動してプラグインが正しくロードされているかどうか確認しましょう。今回はロードされたプラグインの名前とバージョンを表示しています。
プラグインのロード状況はプラグインマネージャーからも確認できます。プラグインマネージャーの「プラグイン」タブを選ぶと、HelloWorldプラグインがロードされていることがわかります。
それではScriptEditorからHelloWorldプラグインを実行してみます。右上のコンボボックスで使用するスクリプト言語をPythonに切り替えます。スクリプト画面に以下のコードを書いて実行してください。
うまくいけば「HelloWorld!」と表示されるはずです。VisualStudioからSoftimageを起動しているので、そのままプラグインのデバッグも可能です。HelloWorld_Execute()の中身にブレークポイントを設定して、デバッグが行えることを確認してください。
SoftimageSDKのヘルプではVisualStudioのプロセスへのアタッチ機能を使ってデバッグする方法が紹介されています。この方法では毎回アタッチする必要がありますが、アタッチを解除するとプラグインを修正することができます。どちらも便利な方法なので好きなほうを使ってください。ここで紹介したように環境設定を正しく行えばプラグインをデバッグできます。これはSoftimageに限らず他のツールでも同じなので覚えておくと役に立つと思います。
今回の紹介した方法でプラグインを作成すると、「VisualStudio上でソースを編集」→「ビルド」→「プラグインの自動コピー」→「VisualStudioからSoftimageを起動」→「デバッグ」という一連の作業が最小限の手間で行えます。またSoftimageの環境変数を使用しているので、Softimage本体のバージョンアップにも楽に対応できます。プラグイン開発というと比較的面倒なイメージがありますが、このように作業を効率化しておくことで、開発速度を上げられるのではないでしょうか。
だいぶ長くなってしまいましたが、今回はここまでです。次回からはColladaのエクスポーターを作りつつ、SoftimageSDKのクラスを見ていくことにしましょう。
Softimageにはプラグインのひな形を作成してくれるウィザードが用意されているので、こちらを使ってもよいのですが、今回は説明のために1から作っていきます。まずVisualStudioを起動して、「VisualC++プロジェクト」→「Win32コンソールプロジェクト」を選びます。アプリケーションの設定では「アプリケーションの種類」で「DLL」を、「追加のオプション」では「空のプロジェクト」を選びます。これでdllを作るための空のプロジェクトができました。このままでは空なのでmain.cppというファイルを作って追加します。以下のコードはこちらに追加してください。
ソースコード中でSoftimageSDKのクラスを使うためには、C++APIのヘッダファイルが必要です。以下のヘッダファイルをインクルードしてください。
#include <xsi_pluginregistrar.h>
#include <xsi_application.h>
#include <xsi_command.h>
#include <xsi_application.h>
#include <xsi_command.h>
ここまでで一度コンパイルしてみましょう。SoftimageSDKのインクルードファイルが見つからないとエラーがでるはずです。これはSoftimageSDKの場所がインクルードパスに追加されていないからです。パスを直接指定してもよいのですが、そうするとSoftimageのバージョンが変わった時に毎回変更する必要があり大変面倒です。
Softimageは起動時に環境変数の設定を行うので、こちらをVisualStudioから利用すると便利でしょう。スタートメニューの「Autodesk Softimage 2011」から「Command Prompt」を実行すると、環境変数の設定が終わった状態でDOSプロンプトが起動します。こちらからVisualStudioを起動すれば、Softimageの環境変数を利用することができます。
毎回コマンドプロンプトからVisualStudioを起動するのが面倒な方は、環境変数の設定を行うバッチファイルを複製して、最後にVisualStudioを起動するコマンドを追加しておきましょう。Softimageをインストールしたフォルダの「Application\bin」の「setenv.bat」をコピーして適当な名前にリネームします。そして最後の行にVisualStudioを起動するコマンドを追加します。こちらの例では「sample.sln」というソリューションを開いています。こちらを実行すると、Softimageが必要とする環境変数の設定を行った後でVisualStudioを起動して「sample.sln」を開きます。
"C:¥Program Files¥Microsoft Visual Studio 9.0¥Common7¥IDE¥devenv.exe" "D:¥sample.sln"
この環境変数の設定は「非常に」重要です。この設定を行うと環境変数が利用できるだけでなく、VisualStudioからSoftimageを起動してデバッグすることができるようになるからです。後ほどプラグインが完成したら、実際にデバッグ実行してみましょう。
これでVisualStudioからSoftimageの環境変数が利用できるようになりました。環境変数「XSISDK_ROOT」を使ってインクルードパスを設定しましょう。「XSISDK_ROOT」は名前の通り、SoftimageSDKのルートフォルダを指します。プロジェクトのプロパティから「追加のインクルードディレクトリ」に「$(XSISDK_ROOT)¥include」を追加してください。
これでインクルードファイルが見えるようになったと思います。それではプラグイン本体のコードを追加しましょう。まず先頭に「using namespace XSI」を追加します。C++APIのクラスは「XSI」というネームスペースに入っているので、これを省略するためです。C++APIのクラスには「Geometry」や「Material」といったありふれたクラス名が入っているので、ユーザー側のクラス名とぶつからないように注意してください。
using namespace XSI;
Softimageのプラグインには以下の4つの関数が最低限必要です。下2つの関数の名前は作成するプラグインの名前が先頭に付きます。
// プラグインロード時に呼ばれる関数
XSILoadPlugin()
// プラグインアンロード時に呼ばれる関数
XSIUnloadPlugin()
// 初期化関数
HelloWorld_Init()
// 実行する関数
HelloWorld_Execute()
XSILoadPlugin()
// プラグインアンロード時に呼ばれる関数
XSIUnloadPlugin()
// 初期化関数
HelloWorld_Init()
// 実行する関数
HelloWorld_Execute()
XSILoadPlugin()とXSIUnloadPlugin()の中身は毎回同じなのであまり気にすることはないと思います。私が作るプラグインでは、ロード時にプラグインのバージョンを表示するようにしています。プラグインを更新したつもりが更新されていなかった、というトラブルがゲーム開発の現場ではよく起こるからです。本当によく起こるんですよ……。必ずプラグインを使っている人がバージョンを確認できるようにしておきましょう。dllのファイル本体の更新日時はバージョン管理ツールなどを経由すると変わってしまうので、このように表示したほうが安全です。表示するバージョンは手動で設定するとよく忘れるので、ビルドした日時が自動で入るようにしています。
XSIPLUGINCALLBACK CStatus XSILoadPlugin( PluginRegistrar& in_reg )
{
in_reg.PutAuthor( L"Tatefuku Hiroshi" );
in_reg.PutName( L"HelloWorld" );
in_reg.PutVersion( 1, 0 );
Application app;
// 既にロードされていたら削除。
if( app.GetCommands().GetItem( L"HelloWorld" ).IsValid() ) {
app.RemoveCommand( in_reg.GetName() );
}
// コマンド登録
in_reg.RegisterCommand( L"HelloWorld", L"HelloWorld" );
// コマンドロード時にメッセージ表示
app.LogMessage( CString("load plug-in:") + in_reg.GetName() );
// ビルド時間をバージョン情報として表示
app.LogMessage( "Version: " __DATE__ " " __TIME__ );
return CStatus::OK;
}
// プラグインアンロード時に呼ばれる関数
XSIPLUGINCALLBACK CStatus XSIUnloadPlugin( PluginRegistrar& in_reg )
{
Application app;
// コマンドアンロード時にメッセージ表示
app.LogMessage( CString("unload plug-in:") + in_reg.GetName() );
return true;
}
{
in_reg.PutAuthor( L"Tatefuku Hiroshi" );
in_reg.PutName( L"HelloWorld" );
in_reg.PutVersion( 1, 0 );
Application app;
// 既にロードされていたら削除。
if( app.GetCommands().GetItem( L"HelloWorld" ).IsValid() ) {
app.RemoveCommand( in_reg.GetName() );
}
// コマンド登録
in_reg.RegisterCommand( L"HelloWorld", L"HelloWorld" );
// コマンドロード時にメッセージ表示
app.LogMessage( CString("load plug-in:") + in_reg.GetName() );
// ビルド時間をバージョン情報として表示
app.LogMessage( "Version: " __DATE__ " " __TIME__ );
return CStatus::OK;
}
// プラグインアンロード時に呼ばれる関数
XSIPLUGINCALLBACK CStatus XSIUnloadPlugin( PluginRegistrar& in_reg )
{
Application app;
// コマンドアンロード時にメッセージ表示
app.LogMessage( CString("unload plug-in:") + in_reg.GetName() );
return true;
}
HelloWorld_Init()はプラグインが初期化されるときに呼ばれる関数ですが、今回は何もしていません。HelloWorld_Execute()がこのプラグインの実行部分ですが、今回はHelloWorldと表示するだけです。文字列の表示はApplicationクラスのLogMessage()で行います。ApplicationクラスはSoftimageのアプリケーション自体に相当するクラスで、どこでも定義して使うことができます。LogMessage()の引数は表示したい文字列ですが、先頭にLが付いていることに注意してください。C++APIでは基本的にワイド文字列を扱います。
// 初期化関数
XSIPLUGINCALLBACK CStatus HelloWorld_Init( CRef& in_ctxt )
{
return CStatus::OK;
}
// 実行する関数
XSIPLUGINCALLBACK CStatus HelloWorld_Execute( CRef& in_ctxt )
{
Application app;
app.LogMessage( L"HelloWorld!." );
return CStatus::OK;
}
XSIPLUGINCALLBACK CStatus HelloWorld_Init( CRef& in_ctxt )
{
return CStatus::OK;
}
// 実行する関数
XSIPLUGINCALLBACK CStatus HelloWorld_Execute( CRef& in_ctxt )
{
Application app;
app.LogMessage( L"HelloWorld!." );
return CStatus::OK;
}
実は通常の文字列(char)もLogMessage()に渡すことができます。先ほどのバージョン情報を表示しているところがそうですね。これはLogMessage()の引数であるCStringクラスが文字列の変換を行ってくれるからです。
ここまでコードを追加したところでビルドしてみましょう。リンクエラーが出るはずです。プラグインで使用しているSoftimageSDKの「sicppsdk.lib」がリンクされていないからです。まずVisualStudioの「追加のライブラリディレクトリ」へ「$(XSISDK_ROOT)¥lib¥nt-x86」を追加します。これでSoftimageSDKのライブラリが見えるようになったので、「追加の依存ファイル」に「sicppsdk.lib」を追加しましょう。これでビルドが通るようになります。
完成したプラグインはビルドイベントで自動的にSoftimageのプラグインフォルダへコピーされるようにしておくと楽です。環境変数「XSI_USERHOME」がユーザーホーム(デフォルトではC:¥Users¥(UserName)¥Autodesk¥Softimage_20XX)を指しているので、こちらを使うとSoftimageのバージョンに依存せずに書けます。dllの出力場所によって多少変わりますが、このようなコマンドをVisualStudioの「ビルド後のイベント」に追加しておくと自動的にdllのコピーが行われます。こちらの例では「リンカ」の「出力ファイル」を「$(ProjectName).dll」に変更して、プロジェクトファイルと同じフォルダにdllが出力されるようにしています。
copy HelloWorld.dll $(XSI_USERHOME)¥¥Application¥Plugins
コピーができたらVisualStudioからSoftimageを起動してみましょう。「デバッグ」の「コマンド」に「$(XSI_BINDIR)¥xsi.exe」を設定するとSoftimageを起動できます。環境変数「XSI_BINDIR」はその名の通り実行ファイルが置いてある場所を指します。
実行するとSoftimageが立ち上がります。ScriptEditorを起動してプラグインが正しくロードされているかどうか確認しましょう。今回はロードされたプラグインの名前とバージョンを表示しています。
プラグインのロード状況はプラグインマネージャーからも確認できます。プラグインマネージャーの「プラグイン」タブを選ぶと、HelloWorldプラグインがロードされていることがわかります。
それではScriptEditorからHelloWorldプラグインを実行してみます。右上のコンボボックスで使用するスクリプト言語をPythonに切り替えます。スクリプト画面に以下のコードを書いて実行してください。
Application.HelloWorld()
うまくいけば「HelloWorld!」と表示されるはずです。VisualStudioからSoftimageを起動しているので、そのままプラグインのデバッグも可能です。HelloWorld_Execute()の中身にブレークポイントを設定して、デバッグが行えることを確認してください。
SoftimageSDKのヘルプではVisualStudioのプロセスへのアタッチ機能を使ってデバッグする方法が紹介されています。この方法では毎回アタッチする必要がありますが、アタッチを解除するとプラグインを修正することができます。どちらも便利な方法なので好きなほうを使ってください。ここで紹介したように環境設定を正しく行えばプラグインをデバッグできます。これはSoftimageに限らず他のツールでも同じなので覚えておくと役に立つと思います。
今回の紹介した方法でプラグインを作成すると、「VisualStudio上でソースを編集」→「ビルド」→「プラグインの自動コピー」→「VisualStudioからSoftimageを起動」→「デバッグ」という一連の作業が最小限の手間で行えます。またSoftimageの環境変数を使用しているので、Softimage本体のバージョンアップにも楽に対応できます。プラグイン開発というと比較的面倒なイメージがありますが、このように作業を効率化しておくことで、開発速度を上げられるのではないでしょうか。
だいぶ長くなってしまいましたが、今回はここまでです。次回からはColladaのエクスポーターを作りつつ、SoftimageSDKのクラスを見ていくことにしましょう。