どうも、星姫です。
モデルデータのフォーマットも策定していないのに、エフェクトファイル(.fx)を勉強するなんて
フライングもいいところでした。
何よりもまず、エフェクトファイルの活用を見越したモデルデータフォーマットを策定しないといけません!
ということで、ここに一例を示します。良かったら参考にしてね。
髪の毛と肌のマテリアルは別々…、スキンでそれぞれの頂点に影響を与えるボーンは
共通だったり、そうじゃなかったりします。
モデルデータフォーマットには悩むところ…そこで、これから示すフォーマットはどうでしょう? というのが今回のレッスンです。
また、実際にゲーム中でどのように描画されるのかを確認しながらモデルデータを編集できるようなツールも同時に考えていきましょう。
ではさっそく本題に入ります。
コチラから、エクスポーターを入手します。
同梱されているReadMe.txt に書かれているインストール方法でインストールしてください。
使い方は、Blenderに最初から付いているDirectX のエクスポーターとまったく同じです。
Blenderの使い方については、Blender2.5入門セット翻訳3点の内容を押さえていれば問題はありません。
さて、お次は出力したXMLデータから実際にゲームで使用するモデルデータに変換するツールを考えましょう。
なんという項目名でしょうか…欲張りですね。でも必要な機能かなぁと思うんですよ。
なんてったって、エフェクトファイルには頂点レイアウトを記述しなければなりませんからね。
頂点レイアウトって、データ作成時に決まるものですけど、数字から判断するのは正直厳しいです。
決定してしまったら、しまったで、これを編集することができないのもおかしいと思います。
よし!エディター兼コンバーターを作ろう!…という訳です。
GUI作成になりますが、今度はC++言語でGUIを作成してみましょう!(理由:前回のライブラリを使いたいので)
キーワードは[Visual C++]です。
作成方法はMFCを使うか、CLRを使うかの2通りです。ここはCLRでやってみましょうか。
理由は、シンプルスター先生が仕事でMFCを使っているからです。(やったことないのに挑戦してみたくて…)
まずは、VisualStudioを起動してください。
新規プロジェクトで下図のように、CLRでフォームアプリを選択します。
最初からフォームが作られていて、これをどんどこ自分の好きなように編集していきます。(下図が初期状態)
GUIの実装はだいたい直感操作でいけるはずです。すばらしい開発環境ですよね。
さて、ここで大きな間違いを犯していることに気づきました。
実は、 C++/CLI またはその他の .NET 言語 (C#、Visual Basic など) で使用できる
ライブラリを作成する場合、ライブラリはマネージド アッセンブリでなければならないのです。
つまり、前々回に作ったSimpleDX10ライブラリは、アンマネージド アッセンブリのため CLR のアプリケーションに組み込めません。
情報元: 再利用可能なコードの作成 (C++)
どうしても使いたい場合、方法が無いわけではありませんが、それなりに作業をしなくてはなりません。
詳細↓
今回はSimpleDX10ライブラリをそのまま使いたいと思うので、MFCを選択しました。(CLRは今度勉強しようね)
作業の前に、VisualStudio2008の表記がまだService Pack 1でない方は
次のリンク先からインストーラをゲットして、更新しておいてください。
Microsoft Visual Studio 2008 Service Pack 1 (インストーラ)
まず、次のページを参考にアプリケーションのスケルトンプログラムを作成します。
(コーディングは一切なし、だれでも簡単に作れます。)
はい、ということで、らしく動くけど実際は仕事をしないアプリケーションができました。
初期デザインはOffice2007の黒です。
そのほか、SDI、MFC標準、プロパティ、ファイルビュー、クラスビュー、出力ウィンドウを用意しました。
さぁ、難しくなるのはここからです。とりあえず、当初の目的であるSimpleDX10をメインのビューに組み込みます。
具体的には、プリコンパイル済みヘッダーファイルでSimpleDX10.hをインクルードするだけです。
詳細は前回のレッスンの冒頭に書いたので、わからない方はそちらを参照してください。
組み込んだ結果がこちら↓
中央のメインビューがクリアされたのが確認できます。
この画面にモデルのプレビューを表示する予定。
続いて、モデルの読み込み部分を作成していきましょう。
いつかC#を使ってXMLファイルを読み込む方法を書きました。(詳細は 第30話 を参照)
基本的にルートのドキュメントから、タグ名や属性名を頼りに値を取ってくる操作ができれば
問題なかった気がします。
さて、MFCでは標準でXMLのパーサーは用意されていないので(…よね?)、使用するXMLパーサーを
選ぶところから始めましょう。
まぁ、「MFCでXML読み込み」なんてキーワードで調べれば、「MSXML」がまず目につくと思います。
サンプルとかすぐに実行してテストできるモノがあるかなぁと調べると、次のページが見つかりました。
hiramine.com様 いつもお世話になっております。
さて、ここのサンプルを参考にXMLファイルを読み込むことにしました。(覚えるべきは次の関数くらい?)
・XMLファイルからドキュメントを作成する
IXMLDOMDocumentPtr pXMLDOMDocument;
pXMLDOMDocument.CreateInstance(CLSID_DOMDocument);
VARIANT_BOOL varbResult;
pXMLDOMDocument->load( CComVariant(_T("Simplestar.xml")), &varbResult );
・タグ名からテキストを取得する
IXMLDOMNodeListPtr pXMLDOMNodeList = NULL;
pXMLDOMDocument->getElementsByTagName( _T("タグ名"), &pXMLDOMNodeList );
// ノードリストのうちの一つのノードの取得
IXMLDOMNodePtr pXMLDOMNode = NULL;
pXMLDOMNodeList->get_item( index, &pXMLDOMNode );
// エレメント型への変換
IXMLDOMElementPtr pXMLDOMElement = NULL;
pXMLDOMNode->QueryInterface( IID_IXMLDOMElement, (void**)&pXMLDOMElement );
// データ値の取得
CComBSTR bstrText;
pXMLDOMElement->get_text( &bstrText );
・タグ名と属性名から属性値を取得する
IXMLDOMNodeListPtr pXMLDOMNodeList = NULL;
pXMLDOMDocument->getElementsByTagName( _T("タグ名"), &pXMLDOMNodeList );
// ノードリストのうちの一つのノードの取得
IXMLDOMNodePtr pXMLDOMNode = NULL;
pXMLDOMNodeList->get_item( index, &pXMLDOMNode );
// エレメント型への変換
IXMLDOMElementPtr pXMLDOMElement = NULL;
pXMLDOMNode->QueryInterface( IID_IXMLDOMElement, (void**)&pXMLDOMElement );
// 属性値の取得
IXMLDOMAttribute* pAttributeNode = NULL;
CComVariant varValue;
pXMLDOMElement->getAttribute( _T("属性名"), &varValue );
varValue.bstrVal ←値の文字列
まずはどのタイミングでXMLファイルを読むべきなのか決めましょう。
まぁ、やっぱり「ファイルを開く」かな。
XMLファイルを読み込み、モデルデータを解析したところで、実際にゲームで使うデータに変換するには
頂点レイアウトを決定しなければなりません。頂点レイアウトを決定すると、頂点バッファのストライドや
エフェクトファイルに書かれる頂点レイアウトの記述が変わります。
大前提として、Blenderで作成したモデルデータにおいて、全ての三角形はマテリアルを持ちます。
これは、私が決めたことなのでみなさんは知らないことです。そのマテリアルに1対1で対応するように
エフェクトファイルを用意しようと思います。これが前提です。絶対的なルールね。
Blenderから出力したファイルには複数のオブジェクトのデータが含まれており、なおかつ
オブジェクトには複数のマテリアルが設定されることになります。つまり、エフェクトファイルがそれだけ作られます。
このエフェクトファイルごとに、頂点レイアウトが設定されるわけですが、毎度ファイルを解析・変換するごとに
エフェクトファイルの数だけ頂点レイアウトを指定させるのは、めんどうです。(想像しただけでもやりたくない。)
そこで、最初は自動で頂点レイアウトを決定し、何の設定もせずにプレビューを見られるようにします。
また、任意のタイミングで頂点レイアウトを編集して、その都度エフェクトファイルとモデルデータが自動で書き換わり
ほぼノータイムでプレビューを見られるようにします。
とりあえず上記の仕様を満たすツールを作ってみましょう。(まだまだ追加したい要望はたくさんありますが…)
動作は「ファイルを開く」でxml形式ファイルを読み込み、ツールがあるフォルダに一時的に変換後のファイルを作り
プレビューにオブジェクトを表示します。フォルダ階層とかは私がすべて決定します。(やっぱりこういうの決めていくのは楽しいね!)
決定して作られたファイル・フォルダ構成をツールのファイルビューに表示させるようにしましょう。
そのファイルビューで選択した項目の詳細・データクラス階層などはクラスビューに表示させます。
さらに、そのクラスビューで選択した項目に関連する面や点がプレビューで点滅するようにします。
コレで行きましょう! ということで、作業開始♪
まず、MFC初心者のみなさんは、ファイルを開く動作のコードを編集するとっかかりがつかめていないと
思います。ディフォルトでたくさんソースコードが作られましたが、注目すべきコードは次の箇所です。
ドキュメントの Serialize() 関数
MFCは最初、ドキュメント、ビュー、アプリ、メインフレームのクラスを作ります。
ドキュメントとは、このドキュメントのことです。
Serialize() 関数に書かれているコメントに従って編集します。
まぁ、まずはファイル選択ダイアログの拡張子フィルターを編集しますか。
編集場所は「リソースビュー」→「String Table」→「IDR_MAINFRAME」の4番目と5番目の文字列です。
そこを次のように修正します。
「SimpleConverter2\n\nSimpleData\n変換プロジェクト\n.conv\nSimpleConverter2.Document\nSimpleConverter2.Document」
結局、拡張子は.xmlにしませんでした。理由はゲームで使用するモデルは複数あるためです。
xmlを読み込むタイミングは、プロジェクトにモデルデータを追加するときにします。詳細は後述します。
フィルタ文字列の編集が済んだら次は、選択したファイルパスの取得です。
それはこんな感じ↓ まだ、保存と読み込みの関数を作っていないのでコメントアウトしておきます。
仕様の詳細を決めます。
最初に起動した状態では、ファイルビューが表示され、一時的なルートフォルダが一つ、その下に
モデルデータごとのフォルダ、その下にエフェクトファイルのフォルダとアニメーションのフォルダがあり
それぞれ対応するフォルダの中に、変換したモデルデータファイル、エフェクトファイル、アニメーションファイルが
あり、一番上のモデルをプレビューに表示します。
ルートのフォルダを右クリックすると、ポップアップメニューが現れ「追加(A)」が有効になっていて
そこをクリックすると、xmlファイルの読み込みダイアログが開き、読み込みに成功後、自動でプレビューを表示する。
とまぁ、まずはそこまで作ってみましょう。
最初、クラスビューが前に出てますよね、これをファイルビューに直すには…
↑こうしました。結果、最初ファイルビューが表に出るようになります。
ああ、前回の構成が保存されちゃうようなら、そうならないようにしておいてください。
こう↓です。
私はメインフレームのコンストラクタに追加しました。
一時的なルートフォルダは、アプリの実行ファイルがあるフォルダの中の、Temporary フォルダとします。
フォルダパスやアイテムの情報など、どうしましょう?
とりあえずEXEファイルのパスは…
これで取得できます。そこからフォルダパスを取得し、一時的なTemporaryフォルダを作成するには…
こんな感じ↑、で実装しました。
次に、一時保存フォルダ以下のアイテム(ファイルやフォルダ)をファイルビューに表示させます。
指定したフォルダパス以下のアイテムを追加して、アイテムがフォルダだったら、そのフォルダパスで再帰処理
をするという流れで作ってみましょう。
で、作ったのがこんな感じ↓
Temporary フォルダに適当にファイルやフォルダを置いてテストします。
実行結果がこちら↓
これらは空のファイルなので、アイテムを選択しても情報は得られません。
次は、ファイルビューにてポップアップメニュー(右クリックメニュー)を開いた時に
メニューに「モデルの追加(A)」の項目があり、これを選択するとxmlファイルの選択を促すダイアログが現れる
という動作を実装してみましょう。
編集場所は、「リソースビュー」→「Menu」です。右クリックでメニューを挿入します。
プロパティにてIDを「IDR_POPUP_FILE_VIEW」に設定し、次のように項目を追加します。
ファイルビューで右クリックしたときに呼ばれるイベントハンドラはすでに実装されているので
それをマネして、次のように追加・修正します。
実装後、ビルドしてテストを行った結果↓
「モデルの追加(A)」の項目が現れました。
これをクリックした時にXMLファイル選択ダイアログを表示するには
まず、リソースの項目を右クリックしてイベントハンドラの追加を行います。
コマンドかつ追加先クラスをファイルビューにして追加します。
すると、次のようなコードが勝手に追加されるので、この関数の中にファイル選択ダイアログを
表示させるコードを追加します。
ファイル選択ダイアログは
こちら↓を参考に実装してみましょう。
読めば誰でも実装できる説明ですね。
こちら↓私が実装したイベントハンドラです。
ちょっと長くなったので
中間データのxmlファイルを解析してデータを保持するクラスと
データを変換出力するクラス
は次回に持ち越します。
2010/12/18 初記。
2011/01/09 追加。
あけましておめでとう!
年末は実家で家族麻雀をするのが、恒例行事なのです。
久しぶりに役満であがりました。「大三元」です。
しばらく先になるかと思いますが、物理エンジンの講座の時に麻雀パイを
使用してみようかなぁと構想してます。