Twitter @HigenekoTwitter #XNA
あけましておめでとうございます!おかげさまで昨年はXbox Liveインディーズゲームの作品登録数が全世界で2,200本を超えました。
2012年も沢山の面白いゲームを登録していただけるように、皆様から要望の多かったゲームサイズや登録数の制限数を上げることとなりました。
ゲームのサイズ上限はCCGAMEファイル(圧縮ファイル)のサイズによって決まりますが、この上限が以下のようになりました。
値段
旧
新
240, 400MSP
150MB
500MB
80MPS
50MB
また、登録できるゲームの数が以前は10タイトルまででしたが、この上限が20タイトルまでとなりました。
今年も沢山の面白いゲームを是非Xbox LIVE インディーズゲームへと是非登録してください!
公式発表(英文) http://blogs.msdn.com/b/xna/archive/2012/01/04/happy-new-year-xbox-live-indie-games.aspx
前回の投稿からものすごーく間があきましたが、乗算済みアルファの話がTwitterの方で盛り上がったので、思い出したように続きを書いてみます。
前回は今まで多く使われてきた補間アルファの問題とそれを解決するための乗算アルファの紹介をしました。今回は乗算済みアルファの真骨頂である半透明を使ったコンポジションを紹介します。
レースゲームでは、ゲーム内で複数の車を購入でき、さらに購入した車の各パーツを変更することができるという機能は一般的なものです。中には自分で描いた絵を車に張るなんて言うこともできるものもあります。こういったレースゲームでは、購入した車の一覧はガレージメニュー内でサムネイル表示され、車を選択すると3Dモデルが読み込まれ、自分がチューンナップした車のモデルを見ることができます。
では、このサムネイル画面はどうやって表示するのでしょうか?
こういった3Dモデルをカスタマイズできるゲームでは、あらかじめサムネイル画像を用意するということはできません。なぜなら、その組み合わせは膨大な数になってしまうのと、ユーザーが描いた絵までは用意することはできないからです。そこで良く用いられるのが、3Dモデルを変更した時にセーブデータ領域などに3Dモデルをレンダリングした結果をサムネイル画像として保存し、それをメニュー画面で使用するという手法です。
単に矩形型のサムネイルを用意するだけだったら問題は無いのですが、このサムネイル画像をビルボードとして使い、メニュー画面の背景の上に重ね合わせて描画したい場合、例えば車のボディ部分のような不透明部分は不透明に、車のウィンドウ部分のような半透明部分はメニュー画面が透けて見えたりするといった重ね合わせ処理をコンポジション(Composition、日本語で「合成」)と呼びます。
コンポジョン処理をする場合の基本として、描画するオブジェクトA,B,Cがあった場合、以下の式が成り立たないといけません。
A + B + C = (A + B) + C = A + (B + C)
この式のA+B+Cという部分はオブジェクトA,B,Cの順に描画するという意味で、(A+B)+CはAとBをまとめて描画した結果を描画した後にCを描画、A+(B+C)はAを描画した後にBとCをまとめて描画した結果を描画するという意味になります。言い換えると()で囲まれたオブジェクトは別のレンダーターゲットに描画し、そのレンダーターゲットの描画結果を他のオブジェクトの描画と合成(コンポジット)できるということです。もしくは前述のレースゲームの中のサムネイル画像がカッコ内の部分に相当します。
結論から言うと、上記の式は補間アルファでは成り立たず、乗算済みアルファでは成り立ちます。つまり、補間アルファではできなかったコンポジションが乗算済みアルファではできるということです。
実際に上の式に補間アルファと乗算済みアルファのブレンディング計算式を当てはめると証明できるのですが、長くなるし、読んでもつまらないし、本題から外れるので、ここでは割愛します。
では、実際に乗算済みアルファと補間アルファでコンポジションした場合の結果を見比べてみましょう。まずは、レンダーターゲットを使わずに背景を描画した後に赤い不透明の四角形、半透明の緑色の四角の順に描画してみましょう。
乗算済みアルファ、補間アルファ、どちらも同じ結果になっていますね。
では、次に赤と緑の四角形をレンダーターゲットへ描画し、その結果をテクスチャとして使って背景を描画した後に描画してみましょう。
補間アルファを使った方は緑の半透明部分がより薄くなっており、不透明であるはずの赤い部分も半透明になってしまっています。対照的に乗算済みアルファの方は全く同じ描画結果となっています。つまり、補間アルファではコンポジッションが上手くいかなかったのが、乗算済みアルファではコンポジションができるということです。
では、実際にXNA 4.0でコンポジション処理をする時にどんなコードを書くのか見ていきましょう。
まずは、コンポジション用のレンダーターゲットの生成と、そこへ描画するコードです。通常のレンダーターゲットを使った描画と殆ど同じものですが、ここではColor.Transparentでクリアするのがポイントとなっています。このTransparent(透明色)はRGBA値が(0,0,0,0)になっています。
// コンポジション用のレンダーターゲットの生成 RenderTarget2D layer = new RenderTarget2D(GraphicsDevice, 1280, 720); // **** コンポジション用のレンダーターゲットへの描画 **** // レンダーターゲットをグラフィクスデバイスへ設定する GraphicsDevice.SetRenderTarget(layer); // 透明色でクリアする (ここがポイント) GraphicsDevice.Clear(Color.Transparent); // 描画したいシーンを描画する RenderScene();
そして、実際のコンポジションはレンダーターゲットを半透明テクスチャと同じように描画するだけです。
// **** コンポジション処理 **** // バックバッファを設定する GraphicsDevice.SetRenderTarget(null); // クリア GraphicsDevice.Clear(Color.CornflowerBlue); spriteBatch.Begin(); // 背景や自分の好きなシーンを描画する spriteBatch.Draw(bg, GraphicsDevice.Viewport.Bounds, Color.White); // あらかじめレンダリングした結果を描画する(コンポジション) spriteBatch.Draw(layer, GraphicsDevice.Viewport.Bounds, Color.White); spriteBatch.End();
このように乗算済みアルファは非常に優れた方式なのでXNA 4.0では乗算済みアルファが基本となっています。ですから、Visual Studio上でコンテントプロジェクトに2D画像や3Dモデルを追加している場合、その存在を気づかずに乗算済みアルファの恩恵を受けることができます。
さて、ここまで利点のみを書いてきましたが、次回は乗算済みアルファの注意点をいくつか紹介したいと思います。
以前、カスタム・コンテント・プロセッサーを使って日本語表示する方法を紹介しました。
XBLIGやWindows Phone 7に配信することを考えてゲームを作る場合、カスタム・コンテント・プロセッサーを作ることが殆どなので、この方法でも問題無いのですが、初めてXNAをさわり始めた人や、ちょっとしたサンプルを作るときに
「ようこそ、XNAの世界へ♪」
と、いった一文を表示するだけのプログラムなのに、カスタム・コンテント・プロセッサーを使うのは初心者には難易度が高いし、プロジェクトが複雑になってしまいます。
そこで今回はカスタム・コンテント・プロセッサーを使わずに日本語表示をする方法を紹介します。
XNAで文字を表示する場合、プロジェクトにSpritefontファイルを追加しますが、このSpritefontファイルには使用するフォントの種類やサイズ、そしてテクスチャへ変換する文字を指定できるようになっています。この文字の指定はファイルの最後の方にあるCharacterRegionsエレメントで行います。Spritefontを追加した場合、あらかじめ英数字のコードが指定されています。
<CharacterRegions> <CharacterRegion> <Start> </Start> <End>~</End> </CharacterRegion> </CharacterRegions>
この中のStartとEndエレメントに使用する文字の開始と終了文字コードをユニコードで指定されています。
CharacterRegions内にはCharacterRegionエレメントを複数宣言できるので、ひらがなを表示したい場合、ひらがなのユニコードはこうなっているので、以下の様なCharacterRegionを追加します。「&#x番号;」と言うのはXMLファイル内で16進数を指定する方法です。
<!-- ひらがな --> <CharacterRegion> <Start>ぁ</Start> <End>ゖ</End> </CharacterRegion>
カタカナや全角英数字なども同様にして追加することができます。以下はそれぞれのユニコード表PDFへのリンクです。
この方法でひらがなやカタカナといった、あらかじめ文字コード領域がハッキリしているものを追加することができます。
では、漢字の場合はどうでしょう?ユニコードではCJK、つまり中国語、日本語、そして韓国語の文字が混合して定義されているので、ひらがなと同じように指定することはできないし、コード表から一文字毎にコードを探し出すのは現実的ではありません。
実はSpritefontファイルには直接文字を指定することができます。例えば「日本語」という文字を表示したい場合、以下のようにして表示したい文字を追加することができます。
<CharacterRegions> <CharacterRegion><Start>日</Start><End>日</End></CharacterRegion> <CharacterRegion><Start>本</Start><End>本</End></CharacterRegion> <CharacterRegion><Start>語</Start><End>語</End></CharacterRegion> </CharacterRegions>
この方法を使うことによって、カスタム・プロセッサーを書かずに日本語を表示することができます。
確かに、上記の方法でも文字数が少なければ手動で良いのですが、やはり一文字づつコードを指定するのは面倒です。
そこで、今回は入力した文字列から使用している文字を抜き出してCharacterRegions宣言部分を生成するツール、ChracterRegionジェネレーターを作ってみました。
実行ファイル: http://higeneko.net/hinikeni/tool/CharacterRegionGenerator-bin.zip ソースファイル: http://higeneko.net/hinikeni/tool/CharacterRegionGenerator-src.zip
このツールはWPF 4.0を使って作られています。XNA Game Studio 4.0をインストール時に.Net 4.0もインストールされているので、XNAの開発環境があるPCでは、そのまま動作します。
このツールの使い方は以下のとおりです。
また、英数字、ひらがな、カタカナ、全角英数字、そして全角スペースといったよく使われる文字をあらかじめ追加することもできます。
このツールが使える場面としては:
と、いった場合には有用です。但し、RPGやテキストアドベンチャーといった大量のテキストを扱う場合は、独自のコンテント・プロセッサーを作った方が効率的でしょう。
今まで何度か動的頂点バッファについて触れてきましたが、実際のコードがどうなるのかは記事の中では紹介していませんでした。実は今までに紹介してきたサンプルの中でWritableVertexBuffer<T>というクラスがすでに実装されているので、このクラスを紹介します。
「GPUはいつ描画するのか?」の記事の中でSetDataOptions.NoOverwriteの説明をしました。この記事の中でNoOverwriteというのはプログラムがドライバへ伝えるヒントで、GPUが頂点バッファをアクセスしている領域にはSetDataで上書きすることはありませんよということを述べました。
では、実際にプログラムの中でこの処理をどうやったら良いでしょう?真っ先に思いつくのは以下のようなコードでしょう。
// 動的頂点バッファの生成 DynamicVertexBuffer vb = new DynamicVertexBuffer( graphicsDevice, typeof(MyVertexType), 100, BufferUsage.WriteOnly); // 書き込み先 int currentPosition = 0; int strideSize = vb.VertexDeclaration.VertexStride; // バッファの最後まで来たら、バッファの先頭へ戻る if (currentPosition + myVertices.Length > vb.VertexCount) currentPosition = 0; // 現在の書き込み先へNoOverWriteオプションを使って書き込む vb.SetData(currentPosition * strideSize, myVertices, 0, myVertices.Length, strideSize, SetDataOptions.NoOverwrite); // 書き込み先を更新する currentPosition += myVertices.Length;
考え方としては
となります。
このコードはこれで動作するのですが以下の点に注意する必要があります。
これらの問題を解決する方法の一つとして、十分に大きいバッファサイズを確保することですが、ゲーム開発の初期の段階でその数を決めるのは難しいことですし、むやみに大きな数字を設定するのはメモリの無駄になってしまいます。また、複数の頂点バッファを確保しておき、それらを切り替えながら使うという方法もありますが、管理が面倒になってしまいます。もう一つの方法は、書き込みが多すぎる場合をチェックして例外を投げるという手もありますが、友達のところで作ったゲームを自慢しようとしたら、たまたま最大確保数を超えてしまって例外発生、ゲームが停止というのも避けたいものです。
そこで便利なのがDataSetOptions.Discardです。ヘルプを読んだだけでは、なんのことを言っているの理解しずらいですが、これもドライバへのヒントで
書き込んだデータを読み込んだりしないから、GPUを待たずにとくにかくパパッと書き込みませてよ
と、いう要求をしていることになります。通常、動的頂点バッファを使う場合、既にゲーム側で書き込むデータを持っているので書き込んだ頂点バッファからデータを読み込む必要はありません。というより、GetDataメソッドは全てGPU待ちが発生するのでゲーム中は使うべきではありません。
ドライバ内部では、このヒントを元に以下の処理がなされます。
XNA Game Studio 3.1までは、Windows版の場合は問題無く動作したのですがXbox 360版にはドライバが存在しないので、こういった処理は自分でする必要がありました。しかし、XNA Game Studio 4.0ではこの機能を実装したので、どのプラットフォームでも同じ手法を使うことができます。
このDiscardとNoOverwriteオプションの組み合わせを使うと、以下のようなコードでGPU待ちなしで動的頂点バッファへの書き込みができるようになります。
// ドラ���バへのヒント、通常はNoOverwrite SetDataOptions hint = SetDataOptions.NoOverwrite; // 最大要素数を超えるようであれば、頂点バッファの先頭に移動し、Dicardオプションを使う。 if (currentPosition + elementCount > vb.VertexCount) { currentPosition = 0; hint = SetDataOptions.Discard; } // 頂点データを頂点バッファへ書き込む int strideSize = vb.VertexDeclaration.VertexStride; vb.SetData(currentPosition * strideSize, vertices, startIndex, elementCount, strideSize, hint); // 書き込み先を更新する currentPosition = currentPosition + elementCount;
さて、上記の処理自体は難しくなくとも、複数の動的頂点バッファを扱う時にはそれぞれに現在の書き込み位置を用意しないといけないので面倒です。そこで、4.0用にアップデートしたGameFest Japan 2008デモプログラムではWritableVertexBuffer<T>クラスを作り、簡単に扱えるようにしてあります。
http://higeneko.net/hinikeni/sample/xna40/WritableVertexBuffer.cs
使い方は簡単で、以下のコードのように生成、データの書き込み、GraphicsDeviceへの設定をすることができます。通常の頂点バッファとの違いはSetDataメソッドが書き込んだ先のオフセットを返すということです。
// 初期化 WritableVertexBuffer<VertexPositionColor> writableVB = new WritableVertexBuffer<VertexPositionColor>(GraphicsDeivce, 1000); // データの書き込み int offset = writableVB.WriteData( ... ); // GraphicsDeviceへの設定 GraphicsDevice.SetVertexBuffer(writableVB.VertexBuffer, offset);
動的頂点バッファを使っているけど、SetDataOptions列挙体のNoOverwriteやDiscardの意味を知らずにGPU待ちが発生していてゲームが遅くなってしまうケースもあると思うので、これを機にSetDataへの引数を再確認してみてはどうでしょうか?
今年もDream Build Play 2011が開催されます。
http://www.dreambuildplay.com/
賞金総額75,000ドル、優勝者には賞金の他にXbox LIVEアーケードタイトルとして発売する権利も与えられます。
大会への登録期限は5月17日までで、すでに受付は開始されています。そして、作品の受け付けは5月17日~6月14日までとなっています。この日付はいずれも米国中部標準時(GMT-06:00)なので日本時間(GMT+08:00)との時差があることに注意してください。その後、応募された作品の中からトップ20までの作品が8月までに発表され、8月末に受賞者が発表される予定です。
毎年、世界中からの参加者があり、去年の受賞者には日本人の作品が2位になったので、今年も日本から受賞者がでることを期待しています。
登録する作品はXNA Game Studio 4.0で作られたXbox 360用のゲームである必要があります。
作品登録は6月14日までとなっていますが、その前の5月17日までの参加登録をするのを忘れないようにしてください。
まずは、このページの「Register Now」を押して登録しましょう。
英文ですが、XNA 3.0からXNA 4.0への更新についてのまとまった情報があるので紹介します。
http://www.nelxon.com/blog/xna-3-1-to-xna-4-0-cheatsheet/
前回はメタセコイアのモデルファイルであるMQOファイルを直接読み込むことのできるインポーターを含んだメタセコイア・パイプラインを紹介しました。
モデルが読み込めたら、次はアニメーションデータを使いたくなります。メタセコイア自体にはアニメーション機能は付いていないのですが、プラグインによってアニメーションを付けてしまおうというのがKeynoteです。Keynoteを使っている時にモデルデータをセーブすると、.mqoファイルと一緒に.mqxというプラグイン用のファイルが出力されます。
理想的には、この.mqxファイルにあるアニメーションデータをメタセコイア・パイプラインで直接読み込めると良いのですが、以下の問題がありました。
これらの情報はKeynote内でモデルデータから生成されているのですが、その生成方法が判らないとインポートすることができません。同じ理由でMqoファイルインポーターでも一般に良く知られているCatmull-Clark曲面は実装できましたが、曲面タイプ1と2は実際にメタセコイアがどのような計算をしているのかが判らないと実装できないので、これらの曲面タイプはサポートされていません。
さて、これは困ったなぁと、数日間試行錯誤することとなりました。幸い、Keynoteには他のプラグインからKeynoteで生成した情報にアクセス出るAPIが提供されていたので、それを使うためにメタセコイア用のプラグインを作り、そこからメタセコイア・パイプラインで読めるファイル形式の形にして出力する方法が使えると言うことが判りました。
ただ、独自ファイルフォーマットを作るには時間が掛かるし、アニメーションデータを読むだけの為にわざわざ新しいファイルフォーマットを作るのには抵抗がありました。そこで、メタセコイア・パイプライン内にはMqoファイルから読み込んだ情報を一旦DOM(データ・オブジェクト・モデル)形式として保持するようになっているので、このDOM自体をXNAコンテント・パイプラインのIntermediateSerializerを使ってデシリアライズする方法をとることにしました。こうすることでMqoファイルを読むときもDOM形式でデシリアライズするときも全く同じ処理をすることができるので作業量が減り、メンテナンス性が上がり、バグの可能性も大幅に減らすことができるようになります。
と、いう経緯でできたのがMkxファイルフォーマットです。MkxはMetasequoia,Keynote,XNAの略でデータの流れを表しています。実際にはXMLファイル形式となっています。
前置きが長くなりましたが、今回はMkxエクスポーターを紹介します。以下のURLからダウンロードできるようになっています��ファイルの使い方に関する情報は付属しているReadme.txtファイルを参照してください。
プラグインのインストール方法はメタセコイアのマニュアルを参照してください。このプラグインはWindows XP SP2以降のOS標準の機能しか使っていないので、プラグインを使用する際はXNA Frameworkランタイムを始め、VC++用のランタイムなどは必要ありません。
Mkxエクスポーター本体(MkxExporter.dll) http://higeneko.net/hinikeni/sample/xna40/MkxExporter-1.0.101222.0-bin.zip
Mkxエクスポーターのソースコード(Visual Studio 2010用プロジェクト) http://higeneko.net/hinikeni/sample/xna40/MkxExporter-1.0.101222.0-src.zip
これらは私個人で仕事時間外に作ったものなので、Microsoft社やXNAチームは一切関与してません。ですから、バグあってもConnectとかに連絡しても相手にしてくれないでしょう。バク報告や要望などがあればAppHub内のフォーラム(XNA開発者によるコミュニティフォーラムです)かsupport@higeneko.comへメールしてください。
Mkxエクスポーターには以下の機能があります。
Keynoteで作成した情報を出力するにはKeynoteをアクティブの状態、つまり「ボーン」コマンドボタンが押された状態で「ファイル/上書き保存」を選び、ファイル種類を「MKXファイル(*.mkx)」を選んで保存することでできます。
Keynoteによる名前変更が原因で名前衝突が起きる場合、Mkxエクスポーターは名前衝突が起きない名前へと変更します。この処理が発生した場合、エクスポート終了後に下図のようなメッセージが表示され、どの名前を変更したのかが表示判るので容易に修正できるようになっています。
また、設定ミスによってできてしまう、どのボーンにも属さない頂点を見つけたときには、XNA側で正しくインポート出来るように孤立した頂点用のボーンを自動生成するようになっています。この場合もエクスポート終了後に下図のようなメッセージが表示され、どのオブジェクトに孤立した頂点があるのかが表示されるので容易に修正できるようになっています。
オブジェクト出力機能は私がデバッグ時に使用していた物で、Keynoteを非アクティブ、もしくはインストールされていない状態でMkxファイルを出力すると、このモードでファイルが出力されます。この時に出力されるのはMqoファイル形式で出力されるものと同じ物が出力されます。メタセコイア・パイプラインにはMqoファイルを直接読み込む機能があるので、必要性は殆どありません。強いて言うならMqoファイルで出力するより15~50%程ファイルサイズが小さくなることくらいです。
Mkxファイルをゲームプロジェクトへ追加する方法は前回紹介したMqoファイルのインポート方法と同じように
だけです、この時、自動的にMkx形式メタセコイア モデルインポーター(MkxImporter)が設定されます。
前回紹介したサンプルの中にはMkxファイルをインポートしてアニメーションさせるサンプルが同梱されています。このプロジェクトを実行すると、下図のようにeynoteに付属しているサンプルのキャラクターアニメーションを見ることができます。
このプロジェクトはAppHubにあるSkinned Modelサンプル(英語版)のコメントを日本語に訳し、以下の2つの変更を加えたものです。
SkinnedEffectはテクスチャなしの状態だと実行時にエラーとなるので、それを回避する為に1x1の白いテクスチャを生成して設定するようにしました。
以上のように既存のサンプルからの変更点は皆無に等しいので、簡単にMkxファイルフォーマットへと移行することが判ると思います。
今回のメタセコイア特集連載(第一弾?)の最後に、この場を借りてメタセコイアの作者である水野様、サンプルで使用したモデル制作者であるKT爺様、そしてKeynoteの作者でありエクスポーター制作時には私の不躾な質問に快く答えてくださったmqdl様に感謝の意を表します。
さて、前々回のまとめではメタセコイアでモデルを出力する際にはFBXエクスポーターを使い、幾つかの注意点に留意する必要があると述べました。この注意点はメタセコイア・パイプラインとMkxエクスポーターの組み合わせを使った場合にどうなるか見てみましょう。
と、なります。私がテスト用にダウンロードした中で曲面タイプ1や2を使っているケースは100個中3個と少なく、キャラクターモデリングの場合はCatmull-Clark曲面を使用する傾向にあるようです。ですから、この注意点が大きな問題となることは殆どないと思われます。また、問題が起きた場合、それはメタセコイア・パイプラインとMkxエクスポーターのバグである可能性が高く、その場合でもソースコードが公開されているのでデバッグ、修正することができます。もちろん、バグが出た場合は私の方でもできうる限りの対応はするようにしますので気軽に連絡ください。
XNAを使って3Dゲームを作りたい、3Dゲーム制作というのはどんな物なのか知りたいという人にとって、初めての3Dゲーム制作の為にいきなり高額な3Dモデリングツールを買うというのは敷居が高すぎます。そんな人達の多くが一度は触れるのがメタセコイアなのではないでしょうか?今までの記事で述べてきたように、以前はメタセコイアで作られたモデルをXNAで使うには細かい注意点が必要でした。この細かな注意点に貴重な時間を奪われてしまうのは勿体ないことです。
メタセコイア・パイプラインとMkxエクスポーターがそんな人達の力に少しでもなれることを願います。
前回は「問題箇所を特定するのが難しい」という問題を解決する為にメタセコイアファイルとXNAデータの間に入る変換プロセスはなにか?というところで終わりました。
プロのゲーム開発でもこの「問題箇所を特定するのが難しい」というのは非常に大きな問題です。なぜならこの問題を解決するのに時間が掛かるのはもちろん、いつ問題が発生するのか判らないという、スケジュールへの悪影響があるからです。ですから、ゲーム制作の中で重要な3Dモデルデータの場合、使用するモデリングツール専用のプラグインや変換ライブラリを作ることが多くなります。他社で提供されたものを使う場合でも、慎重に検証するのはもちろん、そのソースコードとコンパイル環境があるかが採用する際の重要な決め手となります。
XNAでは、この「モデリングツール専用の変換ライブラリ」に相当するのがインポーターです。
もちろん、インポーターを作るのにも時間が掛かりますが、一旦完成させると開発効率が飛躍的に向上します。私がGame Buildingの時に5日間でゲームっぼい物を作ることができたのも、自作したLightwaveインポーターによるところが大きいです。
そこで、今回はメタセコイアファイルを直接読み込むことのできるインポーターを含んだコンテント・パイプライン用アセンブリ、メタセコイア・パイプラインを紹介していきます。
今回紹介するメタセコイア・パイプラインは以下のURLからダウンロードできるようになっています。XNA Game Studio 4.0向けに書かれています。ファイルの使い方に関する情報は付属しているReadme.txtファイルを参照してください。
メタセコイア・パイプラインを使ったサンプル(アセンブリファイルも含む) http://higeneko.net/hinikeni/sample/xna40/MetasequoiaPipeline-1.0.101222.0-sample.zip
メタセコイア・パイプライン: コンテント・パイプライン用アセンブリファイル http://higeneko.net/hinikeni/sample/xna40/MetasequoiaPipeline-1.0.101222.0-bin.zip
メタセコイア・パイプライン: ソースコードとプロジェクト http://higeneko.net/hinikeni/sample/xna40/MetasequoiaPipeline-1.0.101222.0-src.zip
このパイプライン・アセンブリには以下のインポーターとプロセッサーが含まれています。
メタセコイア モデルインポーター(MqImporter)では以下のメタセコイアファイル内情報をインポートします。
このインポーターはMQOファイルに書かれている文字列をSJISとして処理するので、オブジェクト名、マテリアル名、そしてテクスチャ名全てに日本語文字列を使うことができます。Windows、Windows Phone 7では日本語ファイル名をサポートしているのでMQOファイルやテクスチャファイル名に日本語があっても問題ありません。Xbox 360は日本語ファイル名をサポートしていませんが、テクスチャファイル名はコンテント・パイプライン内ではモデルから参照されているテクスチャファイル名を英数字へ変換するので問題ありません。日本語ファイル名のMQOファイルをインポートする場合、プロパティのアセット名を英数字にするだけで元のファイル名はそのままでインポートすることができる、つまりコンテント生成時にはなにも気にせずに日本語を使うことができるということです。
インポート自体は可視オブジェクトのみをインポートするので、ゲームに関係の無いオブジェクトを不可視設定にするだけで同じMQOファイルをそのままゲームプロジェクトへ追加することができます。
メッシュ分割機能はReachプロファイルでもモデルを表示できるようにするのが主な目的ですが、HiDefでも32Bitインデックスより16Bitインデックスの方が描画効率が良いので常に16Bitインデックスバッファへ変換するようになっています。
MKX形式メタセコイアモデルインポーターの機能については次回説明します。
メタセコイア モデルプロセッサー(MqModelProcessor)は標準のModelProcessorから派生したもので、以下のメタセコイア特有の情報を処理します。
通常、ゲーム内では不透明のメッシュを描画してから、半透明のメッシュを描画するようにして不透明、半透明のメッシュ間での視覚的問題がでないようにします。この処理をする為にはどのメッシュが不透明で半透明なのかが判らないとできません。そこで、このプロセッサー内ではアルファ値の使用状況をマテリアルのアルファ値、頂点カラー、そしてテクスチャのピクセル情報から自動的に判定するようになっています。
半透明処理が必要なアルファ値、つまり255以外の値を使っている場合、このプロセッサーはModelMeshPart.TagへInt32値で1を格納するようになっています。ですから、ゲーム内で(ModelMeshPart.Tag != null)という判別式でこのメッシュが半透明処理が必要かどうかを判定することができるようになっています。サンプルプロジェクト内のDrawModelメソッドではこの処理を行っているので、そのコードが参考になると思います。
サンプルパッケージには以下のものが含まれています。
メタセコイア・パイプライン アセンブリファイルはバイナリパッケージにあるもと同じものです。アニメーションサンプルについては次回説明します。
モデルインポートサンプルでは実際にインポートしたメタセコイアモデルを表示するサンプルとなっています。ここではKT爺様(「萌えろ!CG道場+」http://ktg.sblo.jp/)からダウンロードしたものを使用させてもらいました。このモデルは見た目も素晴らしく、データ的にもオブジェクト階層構造、ミラーリング、Catmull-Clark曲面、そして透明テクスチャとメタセコイアの主要な機能のデモには最適のモデルでした。この場を借りてKT爺様に感謝の意を表します。
サンプルを実行させると以下のような画面になります。モデルファイルがダウンロードできるページの最後にある画像と比べると、XNA上でも同じものが表示されているのがわかると思います。また、Windows, Xbox 360, Windows Phone 7の全てのプラットフォームで動作し、Windows Phone 7のプロジェクトは実機とエミュレーター上で動作しているのを確認しました。
このサンプルの中では、前述のように半透明メッシュであることを表す(ModelMeshPart.Tag!=null)という判別式を使って、不透明メッシュを描画してから、半透明メッシュを描画するようになっています。この処理で不透明メッシュと半透明メッシュ間の描画順による視覚的問題は解決しています。また、このモデルでは笹の葉部分に半透明メッシュ同士の重なった部分があるので、実行時に半透明メッシュをAlphaTestEffectへと変換することで対応しています。このモデルの場合は特に問題にはなりませんが、AlphaTestEffectにはライティング設定ができないので、実際のゲームではライティングが必要な半透明メッシュと区別する必要があります。
では、実際に自分作ったゲームにメタセコイアファイルを追加するにはどうしたら良いのでしょうか?
だけです。これだけで下図のようにインポーターやプロセッサーがメタセコイア・パイプライン用のものが自動的に設定されます。テクスチャファイルを使っている場合はプロジェクトに追加するのではなく、コンテントフォルダ内へファイルをコピーするのを忘れないでください。
今回はメタセコイア・パイプラインを紹介しました。この60KB足らずのアセンブリファイルを追加するだけで、メタセコイアで生成したモデルを簡単にゲーム内で使えるようになりました。その利点としては
が挙げられるでしょう。
さて、モデルがインポートできるようになったら、次はアニメーションです。
つづく……
それでは実際にメタセコイアで作られたモデルをXNAで使用する場合の注意点を紹介していきます。メタセコイアで生成したモデルをXNAで使う場合、現状では3種類の方法があります。
1はメタセコイアに付属しているXファイル出力機能を使う方法ですが、これには以下の注意点があります。
ファイルサイズが大きくなるという問題ですが私がテストしたケースでは7MBのMQOファイルが165MBのXファイルになるケースがありました。
続いて2のFBXエクスポーターを使う場合の注意点です。
日本語を使わないことにさえ注意しておけば最も安定している方法なのですが、マテリアル情報変換が正しく行われず、モデルの見た目が変わるケースが見受けられました。
透明テクスチ��情報はマテリアルのTextures[“Transparency”]の中に格納されます。
最後にKeynoteに付属しているXファイル出力機能(Direct X with Animation)を使う場合の注意点です。ここではXファイルフォーマットに関する注意点とKeynoteの注意点の二つに分かれます。まずはXファイルフォーマットに関する注意点としては
最後の注意点ですが、XNAはインポート時にボーンウェイトが設定されているメッシュから参照されているボーンをスケルトン用のボーンとして扱います。この予測は多くの場合は正解なのですが、スケルトン階層のなかにどのメッシュからも参照されていないボーンがある場合に、そのボーンはスケルトンに属するボーンと認識されずにビルドエラーの原因となります。
Keynoteを使う際特有の注意点としては以下の二つがあります。
Keynoteはオブジェクト名にスケルトンに関する情報を格納します。ですから、この命名規約に従わないオブジェクト名を使うとKeynoteによって名前が変更され、場合によっては同じ名前のオブジェクトが複数存在することになってしまい、コンテントビルド時の「ノードに複数の BoneContent の子があります。どれをスケルトンのルートにするか決定できません。」というエラーメッセージの原因となります。
また、Keynoteはどのボーンにも属さない頂点を生成することができ、これは実行時に正しく表示されない原因となります。運良くというか運悪く、この孤立した頂点と通常の頂点が同じポリゴン内に混在していた状態だとコンテントビルド時に「頂点のボーンの重みを正規化しているときにエラーが発生しました。BoneWeightCollection に重みの値が含まれていません。」という謎のエラーメッセージとして表示されます。
この問題の頂点はKeynoteをアクティブにした状態でモデル全体を移動させて発見することができます。どのボーンにも属さない頂点は移動しないので、モデル全体を動かすと下図のように引き延ばされることになります。この移動しない頂点が孤立した頂点だということが判ります。問題の頂点が判れば、ボーンの影響範囲を調整することで修正することができます。
これまでの注意点をまとめる前に、ゲーム内での3Dモデルデータの使われ方について考えてみましょう。この用途には以下のものがあります。
恐らくゲーム用の3Dモデルというと真っ先に思い浮かべるのは1なのは間違いないと思います。ですが、ゲーム制作では実際にゲーム中に描画する以外にも、3Dモデルデータ必要になる場面が多数あります。その主なものが2~3になります。まずは下図を見てください。メタセコイアで3分程で作ったものなのでモデリングのクオリティは気にしないでください(汗)。ゲーム内で実際に描画するのは地面とビルですが、それ以外にも赤い三角錐モデルはプレーヤーのスタート地点、黄色い点は敵の出現ポイント、そして赤い半透明の箱はプレイヤーが触れると次のマップへ移動するトリガーを表しています。
このように図で表すと色んな事が視覚的に判りやすくなります。例えば、このマップでは、プレーヤーのスタート地点は手前で3つの出口があり、敵の数は後になる程多くなり、中にはビルの屋上に出現する敵もいるということが判ります。さて、このゲームデザインをどうやって実装しますか?これらの情報をソースコードに一つ一つ数値として書いていきますか?それともレベルエディターを作りますか?個人や小規模な人数でゲーム制作という視点で考えると、どちらも時間と労力が必要になるのであまり現実的ではありません。ではどうしたらいいでしょうか?
最も簡単な手段はモデルデータにこれらのゲーム特有の情報を追加してファイルにセーブ、後はコンテントパイプラインでモデルデータ処理と同時にゲーム特有の情報を抽出することです。例えば、「敵出現位置」と名付けたマテリアルを使ったオブジェクト位置を敵の出現位置、「出口」と名付けたモデルはそのメッシュデータを判定範囲としたトリガーとして変換することで実現することができます。この方法であればメタセコイアをレベルエディターとして流用することができるので、視覚的にマップデザインすることができ、時間と労力も節約できるのでゲーム本来の部分の作業に集中することができます。
このマップを3分間程度で作ることができたことを考えるとその効率の良さが判ると思います。もちろん、面白いゲームを作るにはもっと時間を費やして優れたレベルデザインに仕上げる必要があります。ですが、ここで重要なのは、短時間でゲーム自体の面白みを出す部分に集中できる作業環境を作り出すことができるかということです。
以上の事から、ゲームで使うことを考えると、名前や透明テクスチャ情報が欠落してしまうXファイルを使うのは避けた方が良いでしょう。となると、残ったFBXエクスポーターを使用することになると思います。この場合、以下の注意点に留意する必要があります。
と、いうのが理論的な結果となりました。
なんですが、理論と実現実は違う物です。私自身、ゲーム開発時にモデルファイルフォーマット変換に起因する問題を多く経験してきたので、実際に試してみないと納得できません。そこでネットでダウンロードできるメタセコイアのモデルファイルを100個程集め、どんなデータになっているのかを実際に調べてみました。
この調査で判ったのは大半のモデルデータが日本語を使用しており、XファイルにしろFBXファイル形式にしろ、日本語を使っているファイルは読み込めませんでした。ですから、仮に日本語問題が解決したとしても、今までは日本語問題で隠れていた他の問題が浮上することもあり得ます。
後はやはり前回の記事で問題点とした「問題箇所を特定するのが難しい」と言うのは、個人や小規模な人数でゲーム制作する人にとって貴重な開発時間を奪ってしまうものでもあります。
理想的なのはメタセコイアで作ったファイルが直接XNAに読み込める、つまり、メタセコイアファイルとXNAのデータ構造の間に1つの変換プロセスしか存在しないという形で、下図のようになります。この場合、何か問題が合った場合は「?」の部分に問題があることになるので、XファイルやFBXファイルへ一旦変換するより効率的に問題点を見つけ出すことができます。
この「?」に入るものとは、いったいなんなのでしょうか?
Game Building日誌の「3Dモデリングツール選び」の時にコメントで「メタセコイアを取り上げて欲しい」というコメントが寄せられました。実はXNA 1.0の時にメタセコイアはLE版を試してみて、シェアウェア版を購入しようとしたのですが、購入するには日本の銀行に振り込まないといけないということでそのままになっていました。今回、改めて見てみるとPayPalでの支払いにも対応していたので購入したのが2ヶ月程前でした。
そこで、今回から数回にわたってメタセコイアを使って作ったモデルをXNA上で使うための情報を紹介していきたいと思います。
XNAは標準でXファイルとFBXファイルから3Dモデルを読み込む事ができます。メタセコイアのモデルファイルフォーマットはMQOファイルに格納されるので、メタセコイアで作ったモデルをXNA上で使用するにはXファイルかFBXファイルへ変換する必要があります。
結論から言うと、メタセコイアに限らず、どの3Dモデリング��ールでもツール向けのファイルフォーマット以外へ変換する時には幾つかの問題点があります。それらの問題点は以下の4つに分類されます。
1の日本語問題はネイティブ、特にC/C++で作られている多くのアプリケーションは多言語をサポートしていないという問題に起因します。特に古くからある3Dモデルファイルフォーマットは多言語サポートしていないものが多く、サポートしていても環境依存なマルチバイト文字(SJISなど)のみであったりと、言語の違うOSでは使えないことが多くあります。例えばFBXファイルは多言語サポートしていないので日本語文字を使うことはできません。使えても文字化けするケースがあります。
メタセコイアは日本製ツールでUIも全て日本語なので、自然とオブジェクト名やマテリアル名に日本語を使うことが多くなりますが、そのままでは他の3Dモデルフォーマットへ変換するときに問題となってきます。
2の情報欠落問題はファイルフォーマット変換時には必ずといって起きる問題です。3Dモデルファイルフォーマットにはそれぞれに設計意図があるので、その設計意図が異なるファイルフォーマットへ変換する時にはどうしても変換しきれない情報があります。例えばゲーム系のファイルフォーマットはポリゴンデータを使うことが前提とされているので、3Dモデリングツールでサポートされている曲面データは無視するものが多いのが現状です。
3のアプリケーション未対応データ問題ですが、モデルデータを読み込む側で未対応のモデルデータを使おうとしたときに起きる問題です。XNAの場合、あくまで最近のGPU上で効率的に動作するゲームを作ることを目的としているので、そういった知識が無い状態でモデルデータを作ってしまうと、非効率であり、時にはゲームが実行できない、強制終了してしまうということになってしまいます。よくある問題としてはXNA 4.0のReachプロファイルで3Dモデルに使うテクスチャサイズは2のn乗である必要がありますが、このことを知らないで100x200といったテクスチャを使用するとコンテントビルド時にエラーとなります。
4の問題箇所を特定するのが難しいというのは下図のデータの流れをみると判りやすくなります。例えば、あなたがあるモデルをXNAで表示させたいと思い、メタセコイア標準のXファイル出力機能を使ったとします。これで問題無くXNA上で表示されれば良いのですが、問題はうまく表示されなかった時です。この時、何が原因だったのかを究明するにはどうしたら良いでしょう?
問題になりそうな箇所はいくらでもあります。Xファイル変換にバグがあるのか、Xファイル変換が対応していないデータを作ったのか、Xファイルインポート時の問題なのか、はたまたXNAが対応していないデータだったのか、もしかしたら、単純にモデルデータが悪かったのかもしれません。これらの問題点を探していて原因を見つけたら、単にファイルのコピーし間違いだったなんてことも良くあります。要するにコンテント生成するポイントから実際にコンテントを使うまでの道のりが長ければ長いほど開発効率が下がってしまうことになります。
このように、3Dモデリングツールを使う場合、そのツールの標準フォーマット以外のフォーマットを扱う場合にはいろいろな問題点に注意しないといけません。
久々に徹夜したので眠気覚ましにシャワー浴びて出社。早速、同僚を三人呼んで一人ではできなかった4人同時プレイのテストプレイをしました。プレイ終了後、同僚からは「どの照準が自分のか判らない」「スコアが変化しないね」「パンツァードラグーンの用にボタン連打で通常弾で、溜めるとホーミングレーザーの方が良いかも」といった意見を聞く事ができました。
早速、プレイヤー毎に照準の色を変える処理を追加し、敵を倒したときの点数加算処理を追加、ついでに敵編隊を全部撃破を連続でした時にコンボ数が増えていく簡単なボーナススコアシステムを追加しました。
スコアリングシステムを追加した段階で「こんなもんで良いかなぁ?」と気が抜けたのと、徹夜の反動で非常に眠くなりました。新しいことを考える余裕が無くなり、テストプレイをしては細かい修正をするというのを繰り返していたら、いつの間にか午後2時すぎ。発表まで後2時間を切ったので、この段階で思い切った機能追加はとても危険です。
と、普通の状態だったら、これ以上の変更は加えなかったのでしょうけど、ふと「爆発欲しいな~」と思い立ち、しかもインポーターに変更を加える必要があるトリガーシステム(ゲーム内で任意のイベントを発生させる時等につかう仕組みのこと)を追加し始めました。
追加したトリガーシステムの仕組み自体は単純で、Lightwave内でNullオブジェクト(モデルデータの無いノードのこと)を追加し、その名前を「trigger-」で始まるようにし、アニメーションデータにX軸のスケール値が0から1に変わったフレームをトリガー発生の時間とし、その時間が来るとアニメーションプレイヤーのイベントオブジェクトを「このノードでイベントが発生」と呼び出すようになっています。
普段だったら、識別子とパラメーターの混同した命名規約や、アニメーションを特定の状態にするといった判りづらい仕組みは後で混乱の元になるので追加しません。変わりにゲーム専用のレベルエディタ上でちゃんとしたトリガーとした仕組みを提供するべきと判断したことでしょう。
ですが、徹夜明けのボーっとした頭ではそこまで考えが及ばずに、これまたボーっとしながら黙々とコーディングし、Lightwave上で必要なデータを生成、ゲームプレイを繰り返しながら爆発の大きさなどを調整し終わったのは実に発表の5分前でした……。
結果的に爆発エフェクトを追加することができたのは良かったのですが、今思い起こすとかなりきわどかったことをしたなぁと思います。
そして遂にGame Building 2010の発表の時となりました。前回はYouTube版の動画を貼ったので、今回はニコニコ動画の方を貼っておきます。
と、言うわけで8回に渡ってXNAチーム内で行われたGame Building 2010向けに作ったゲーム製作の過程を紹介してきました。Game Buildingの目的としてはゲームを楽しく作ろうという他に、このようにして自分達で作ったフレームワークを使って実際にゲームを作ることでフレームワーク設計時には見えなかった問題や改善点を洗い出し、より良いフレームワークを作ろうという目的があります。
私は今まではフレームワークの新機能のテストを兼ねたゲームを作ってきましたが、今回はゲーム製作におけるコンテント製作の難しさの実態を把握するためにコンテント部分の製作に多くの時間を割くようにしました。改めて実感したのはコンテント製作自体、特にモデリングは楽しい作業だったのですが、作ったコンテントを実際にゲームの中で使えるようにするにはまだまだ時間と労力をかけないといけないということでした。
今回学んだことを将来のXNA フレームワーク開発に役立ていきたいと思います。
今までの投稿へのリンク Game Building日詩 その1「はじめに」 Game Building日詩 その2「3Dモデリングツール選び」 Game Building日詩 その3「1日目、モデリング日和」 Game Building日詩 その4「2日目、モデリング終了?」 Game Building日詩 その5「3日目、プログラム開始」 Game Building日詩 その6「4日目、ゲームシーン製作中」 Game Building日詩 その7「5日目、ゲームらしくする」 Game Building日詩 その8「最終日、発表会5分前に……」
日曜からずっと寝不足なので疲れ気味ですが、Game Buildingも残すところ今日一日、厳密に言えば明日の午後四時までに完成させれば良いのですが、直前でバグが入ってしまって発表中に止まってしまうのは避けたいので、やはり今日中に仕上げるよう頑張ります。
さて、今まで背景にはなにも無かったので、この段階でキューブマップテクスチャを使った背景を追加します。キューブマップテクスチャの作り方の一つとしてはカスタムモデルエフェクトサンプル(4.0版は英語版のみ)についているCubemapProcessor.csを使うことで一枚の背景テクスチャからキューブマップテクスチャをコンテントパイプライン内でコンパイル時に生成することができます。
この方法は反射マッピングなどの見た目の整合性が多少とれていなくても気づかないような用途では問題ないのですが、背景テクスチャとして使う場合には、上下のテクスチャ部分が歪んでいるのが判りやすくなってしまうという問題があります。
そこで、今回はLightwaveを使ってキューブマップテクスチャを作るのに必要な6枚のテクスチャを生成します。やり方は簡単でアスペクト比が1:1になるカメラを作り、6フレームのアニメーションを作ってイメージファイルへ書き出します。
今回の舞台は宇宙なので、星雲とかをパーティクル使って出来たら良いとは思いましたが、時間が無いのでLightwaveのバックドロップ機能を使います。この機能を使うと背景にフラクタルなどを使ったテクスチャを張ることができるので、複数のテクスチャを設定すると簡単に宇宙っぽい背景をつくることができます。
こうして出来た6枚のテクスチャからDirectX SDKに付属するテクスチャツールなどを使ってDDSファイルを生成します。
さて、キューブマップの背景を追加し終えたのが午後3時頃。この時点で手来ているのはいままで作ってきたシーンを再生するだけでゲームプレイ的なものは全くありませんでした。残り時間が25時間となったので、本来であればゲームプレイ部分を作るべきですが、せっかく半日かけてモデリングしたキャノンシードは見せたいという欲求が勝って最悪ゲームプレイができなくても良いというリスクを承知で最後のシーンを追加することにしました。
最後のシーンは惑星上なので、地上部分のモデリングをしました。カメラから見える部分だけをモデリングしていきます。
岩山は分割数を多くした立方体にfractalizeという機能を使えば、一つ一つの頂点を修正するより手軽にそれっぽいモデルを作ることができます。ただし、やり過ぎると表裏が反対になってしまうこともあるので注意が必要でした。左下の図をみるとポリゴンが重なり合っているのが判ると思います。修正したいところですが、この岩山がゲーム内で表示されるのは一瞬なので気づく人は居ないだろうということで、こままにしておくことで時間節約。
そして、メインディッシュであるキャノンシードと、その前の地上砲台を設置し、カメラパスを作って完成。
帰宅して夕食をとって午後10時、ここでようやっとゲームプレイ部分を作り始めることになります。敵の移動パターンもLightwave上で作っていきます。敵の飛行経路はワールド座標ではなく、ビュー空間で指定します。つまり、カメラをどんなに激しく動かしても、その動きが敵の飛行経路に影響を与えることはありません。と、書くと変に思えますが、実際に出来たものを見てみると特に大きな問題はないことが判ります。
ビュー空間で飛行経路を作るのにはいくつかの理由があります。第一にツール上で再生したときに実際にゲーム上で動かしているときと同じように見えるのでデザインや調整がしやすいのが一つ。次にカメラの移動に左右されないので使い回しが効くと言った利点があります。もちろん、カメラの移動経路とあまりにもかけ離れたものを作ると見た目が破綻してしまう事に注意する必要があります。また、建物の間を縫って飛ぶような経路を作りたい場合にはビュー空間ではなくワールド空間で作った方が良い場合もあります。
大事なのは短い時間で敵の飛行経路を繰り返し調整が簡単にできることがゲームのクオリティアップへつながるということです。
と、言うわけで幾つかの飛行パターンを作った後はゲーム上で再生するコードを書きます。これもシーンを再生させるコードの再利用で、再生中に撃破されるように変更を加えるだけで済みます。
さて、敵の動きができたので、次は実際に撃ってみたくなります。オリジナルのゲームではゲーム画面上にある照準を移動させてボタンを押すとレーザーがでるというものでした。ですから、堅い敵が出てきたりしたときにはボタンを連打する必要がありました。今時ボタン連打もアレだし、ネットワークプレイに対応したときに大変そうだということで、ホーミングレーザー形式を試してみることにしました。
ホーミングレーザーは今まで何度か作ったことがあるし、XNA上でもWindows Phone 7のマルチタッチのテストする時にタッチした場所に沿って線を描くプログラムがあったので、そのコードを流用して3D用に修正を加えて使いました。
レーザーを撃って、敵が消えるまでできたので、次は爆発エフェクトです。ここまで来たら爆発エフェクトも作りましょう(徹夜でハイになってる)ということで、Lightwaveのパーティクル機能を使って爆発するシーンを作ります。ここでは100個のパーティクルをHyperVoxelsと呼ばれるボリュメトリックレンダリング機能を使ってそれっぽいものを作っていきます。
で、複数のフレームをレンダ��ングしたものを下図のようにまとめたスプライトシート(4.0用プロジェクトは英語版のみ)を作りました。
そして、パーティクルサンプル(4.0用プロジェクトは英語版のみ)を流用したものを使ってゲームの中に組み込みます。
これで、移動する敵、レーザー発射、撃墜、爆発エフェクトとゲームプレイの基本部分ができました。下のスクリーンショットを見てもだいぶゲームらしくなったのが判ると思います。
この段階で周りはすっかり明るくなってしまいました。
Game Buildingの発表会まであと8時間18分……
つづく
昨日、一昨日と二日間に渡ってMicrosoftキャンバス内で開催されたPDC10の中で行われた多数のセッションはストリーミング配信され、記録された動画も公開されています。そのセッションの中には二つのXNA関連のセッションがありました。
「Things You Need to Know Before Building XNA Games for Windows Phone 7(Windows Phone 7でXNAゲームを作る前に知っておきたいこと)」 http://player.microsoftpdc.com/Session/b8100382-1fdf-482e-b4ec-2b1f0315987f
「Real-World Analysis and Optimization of XNA Framework Games on Windows Phone 7(Windows Phone 7のXNAゲームにおける分析と最適化の実践)」 http://player.microsoftpdc.com/Session/6a4f4c01-5984-4b33-9e27-e725791980b1
オリジナル音声は英語ですが、日本語同時通訳のオーディトラックを選択できるようになっています。プレイヤーの右下にあるAudioボタンを押すとリストが以下のように表示されるのでJapaneseを選択することで日本語音声で視聴することができます。
「Things You Need to Know Before Building XNA Games for Windows Phone 7(Windows Phone 7でXNAゲームを作る前に知っておきたいこと)」のセッションの中ではShawn Heargreavesがゲーム制作の過程をIdea(発想)、Implement(実装)、Optimize(最適化)、Polish(仕上げ)、そしてSell(セールス)の5つに分け、そのうちのOptimize、Polish、そしてSellについて話しています。
Optimize(最適化)の中ではゲームの中で大半を占めるコンテントの最適化をすることで、ゲームが始まるまでの時間短縮、コンテント自体の読み込みの高速化などに触れています。Polish(仕上げ)の中ではWindows Phone 7向けのゲームを快適にプレイする為の手法を紹介しています。
このセッションの中ではApp Hubサイトにあるサンプルコードであるゲーム状態の管理(Windows Phone向けのサンプルは英語版のみ)と、複数の画像ファイルを一つにまとめることで読み込みや描画の高速化(テクスチャの切り替えが少なくなるため)に役立つスプライトシート(4.0用プロジェクトは英語版のみ)を紹介しています。
「Real-World Analysis and Optimization of XNA Framework Games on Windows Phone 7(Windows Phone 7のXNAゲームにおける分析と最適化の実践)」のセッションではガーベージコレクション、低フレームレートの代表的な問題の分析方法と最適化方法が紹介されています。
Windows Phone 7のゲームは.Net Compact Framework 3.7上で動作しているので、Xbox 360と同じようにガーベージコレクションには気をつける必要があります。殆どの場合は不必要なメモリ確保をしてしまうのが問題の原因となっています。その不必要なメモリ確保が起きている場所を特定するのにXbox 360の場合はRemote Performance Monitorがありますが、Windows Phone 7では対応していないのと、どのコードが原因なのかまでは突き止めることはできませんでした。
そこで、このセッションではVS2010のPremium/Ultimate版についている分析ツールを使うことによってどのコードが不必要なメモリ確保をしているのかを素早く発見する手法を紹介しています。
後半はフレームレート低下の原因の発見方法を最適化の手法を紹介しています。この内容はこのサイトで紹介した手法と殆ど同じものとなっています。
CPUバウンドとGPUバウンド コード探偵 ファイル01「パフォーマンス殺害事件」 コード探偵 ファイル02「FPSで犯人割り出し」 コード探偵 ファイル03「タイムルーラーで現場測定」 コード探偵 ファイル04「CPUは正直者」 コード探偵 ファイル05「無口なGPU」 コード探偵 ファイル06「暗闇にさす光」
これらのセッションはWindows Phone 7向けとなっていますが、同じ.Net Compact Framework 3.7を使っているXobx 360には同じ手法がそのまま使えますし、Windowsでもコンテント読み込みの最適化などの手法はそのまま当てはまるので、それらのプラットフォーム向けのゲーム制作をしている人にとっても有意義な情報です。
日本語のXNA Game Studio 4.0Language Packがリリースされました。これでVisual Studioのメニューやプロジェクトテンプレートが日本語化されるのはもとより、日本語のヘルプドキュメントも付いているので英語を読むのが苦手という人でも安心してXNA 4.0を使えるようになりました。
注意点としてはLanguage Packとしての提供になるので一旦英語版をインストールした後にLanguage Packをインストールする必要があります。英語版のインストール方法については以前の記事が参考になると思います。また、英語版を既にインストールしている場合はLanguage Packをインストールするだけで日本語化されます。
Windows Phone Developer Toolsのダウンロード (Windows Phone開発キットに含まれている) XNA Game Studio 4.0スタンドアロン版をダウンロードする (Xbox 360/Windowsのみ開発できる)
XNA Game Studio 4.0 Language Pack (日本語) のダウンロード
詳細は以下のニュースリリースを見てください。 http://create.msdn.com/ja-JP/home/news/xnags40jpnlangprel
そんな訳で、またまたやらなければいけない仕事が発生、午前中はGame Building作業はお休みとなってしまいました。
仕事を終わらせたので、Game Building作業再開。まずはロウンチシーンから作ります。といっても、ここは友人が作ってくれたシーンを再生するだけなので簡単に済むはずです。
と、思ってたりすると必ず発生するのが問題。このシーンを再生してみると、シーンのところどころでモデルがカクッとなったり、一瞬消えたりすることがありました。LightWave上で再生させると問題ないのですがゲーム内で再生するとこの問題が発生します。
実はこのシーン、戦闘機モデルはひとつではなく、複数あり、そのモデルを切り替えながらアニメーション再生をしています。そして今回の問題の原因はその切り替え方法にありました。例えばモデルAからモデルBに10フレーム目で切り替えたいときにはモデルAのスケールを0~9フレーム目まで1に設定し、10フレーム以降は0に設定します。そしてモデルBの方は逆に0~9フレームまで0、それ以降を1という風に設定するといった感じです。
この1フレームの間にスケール値を極端に変更するというのが原因でした。下図はスケール値が0から1に変更している部分を拡大したものです。この二つのキーフレームの間隔は1フレームなので30FPSで再生しているときには問題がありませんが、60FPSで再生すると間のフレームを補間してスケール値が0.5になってしまうので表示がおかしくなってしまいます。
ですから、キーフレームの補間方法をステップに変更することで修正することができます。また、問題を人の目で見てから修正するのでは無駄な時間が掛かってしまうので、プロセッサ内で1フレームで値が変わっていて、補間方法がステップになっていない場合は警告メッセージを表示するといったことをした方が良いでしょう。
と、言うのが正しい方法なのですが、今回は他の人が作ったシーンを把握して問題のキーフレームを探し出して修正という作業をしないといけないので面倒もとい時間が掛かりそうだなぁと考えたので別の方法を考えることにしました。今回の問題は
「見せたいシーンの中に見せたくない問題が発生」
だったので、見せたくないというのを基点に逆の発想にして
「見せたくない問題が発生するんだったら、問題が発生している場所を見せなければ良い」
と、考えました。幸い、友人からもらったシーンでは母艦内部しか出てこないので、せっかくのカッコいい母艦も表示させたいなぁと思っていました。そこで、母艦内部のシーンと母艦を外から見たシーンのカメラを問題が起きるタイミングで切り替えるようにすることにしました。こうしておけば、見せたい母艦も見せることができ、見せたくない問題部分を隠すこともできる、そして時間の節約にもなると、一石三鳥です。
そんな訳で、母艦外部のカメラパスを設定し、
カメラパスの切り替えタイミングはカーブエディターを使って作りました。
カーブエディターが出力するXMLファイルはそのままプロジェクトに追加でき、読み込みもCurveオブジェクトとして読み込むことができるので、今回のGame Buildingでこのカメラの切り替えの他にも簡易パーティクルシステムで使いました。
ワープシーンのエフェクトはLightWaveで上図のモデルを作ってテクスチャを貼り、UV座標をスクロールさせるシェーダを適用して作ることにしました。これぐらいのモデルだったらプログラムでもできますが、すぐにモデルを作ることができるのと、実際のゲームに近い環境で見た目の修正をリアルタイムできるツール上の方が微調整が効くのでモデリングする方法を選びました。
最初に試したものは下図のようなもので、ちょっと大人しい感じのワープシーンでした。
どうせワープしてるシーンでは他のモデルも出てこないんだから、半透明処理のモデルをもっと重ねてみようということで、元のモデルをコピーして半透明四枚重ねにした結果は下図のようになりました。
ここでも最初に作ったマテリアルバッチの効果がありました。別々のUV座標スクロールさせたいモデルにLightWave上で別々のマテリアルを割り当てておくことでプログラムの方で簡単に処理することができました。
このワープシーンには隕石がでてくるので、そのモデリングをしました。テクスチャはハイキングに行ったときに撮っておいた岩の写真を以前紹介した方法で加工して使いました。
ワープシーンエフェクトで既に前に進んでいる状態を表現しているので、ここではカメラは固定位置で隕石がカメラの前を通るパスを作るだけで終わりです。
このシーンでは沢山の隕石が出てきますが、一つ一つの隕石が別々に動く必要はないのでモデラー上で隕石一つをコピーして二つにし一方を適当に回転、 出来た二つの隕石をコピーし…というのを6回繰り返して64個の隕石群をひとつのモデルとしてシーンエディターで以下のように配置し、ゆっくりとした移動と回転をさせるとそれっぽいシーンができあがります。
後はDeath Ball(宇宙機雷)を適当に配置し、カメラパスを作って完成です。
このシーンは戦艦が二隻出てきて、その至近距離をすれ違うように飛行するという経路なんで簡単そうなシーンだと思っていました。ですが、オリジナルの動画を見ながら作ってみると二番目の戦艦に接近したときの背景に見える星と戦艦の位置関係を正しくすると、一隻目の戦艦に近づくときに二隻目の戦艦が視界に入ってしまうという問題がありました。
そこで、一隻目の戦艦に近づくにつれ二隻目の戦艦が所定位置に見えないところで定位置にスタンバってくれるようにアニメーションさせるようにしました。
さて、空母シーンを作るわけですが、既に午前4時を過ぎているので眠い目をこすりながら作ってみるもののカメラパスがかなり怪しい挙動になってしまいました。修正したいところですが、こう頭が回らなくては修正作業もままならないので今日は寝ることにしました。
そんな訳で、今日一日は各シーンの生成に費やしたのでコーディングはお休みの一日でした。
Game Building発表まであと2日……
これからXNA Game Studio Connect正式リリースするまでの流れを時系列に沿って紹介します。
まとめると、
情報元: http://blogs.msdn.com/b/xna/archive/2010/10/12/xna-game-studio-4-0-submissions-for-xbox-live-indie-games.aspx
お待たせしました。数日間のメンテナンス期間を経て、Creators Club OnlineサイトがAPP HUB(アップ・ハブ)として生まれ変わりました。これを機にURLアドレスも新しくなりました。
APP HUB 英語版 http://create.msdn.com/
APP HUB 日本語版 http://create.msdn.com/ja-JP
APP HUBサイトでは従来どおり、XNA Game Studioに関する情報やサンプルがあり、プレミアム会員の場合はインディーズゲームの発信ができるのに加えて新たにWindows Phone用のゲームが発信できるようになりました。
Windows Phoneでの開発に興味がある人はラーニング ロードマップのページが参考になると思います。
また、日本語版からのリンクからはまだ見ることができないXNA Game Studio 4.0の新機能に関するサンプルも英語版のEducation Catalogから見ることができます。例えばエコーサンプルなどはダイナミックサウンド機能を使い始める上で参考になるでしょう。
Game Building中はゲームを作ることが優先されますが、優先度の高いバグや他のチームからの質問などには対応しないといけません。そんな訳で、今日は出社した途端に優先度の高いバグの検証作業などが入り、Game Buildingの作業は一旦中止になってしまいました。
それではいよいよコーディング開始です。まずは、ゲームの状態の管理サンプルをダウンロードして、プロジェクト名と、GUIDを変更します。GUIDを変更するのはXbox 360に配置するときに、このGUIDが他のプロジェクトと見分けるIDとなるので、同じGUIDのプロジェクトを配置すると上書きしてしまうという問題を避けるためです。
ゲームステート管理サンプルはおそらくクリエーターズクラブオンラインサイトの中では最も使われているサンプルでしょう。今回のGame Buildingでも殆どのゲームがこのサンプルを雛形にしてメニュースクリーンを作っていました。
注: 4.0版のサンプルは既に出ているのですが、サイトのバグでフレームワークの表示部分が2.0のままになっていることに注意してください。サンプル名+_4_0.zipとなっているものは4.0版です。
今回はSci-Fiものということで、それっぽいフォントに差し替えました。
それ以外にもデバッグサンプルのコードや、自作しておいたLightWaveのインポーター、プロセッサをプロジェクトへ追加しました。
私がゲームを作るときに必ずあるのがDrawContextとGlobalというクラスです。DrawContenxtはその名のとおり、描画するのに必要な情報��まとめて持っておくクラスで、View、Projectionを設定するメソッドがあり、設定した場合に鏡面光を計算するのに視線ベクトルや、BoundingFrustumなどを生成するようになっています。描画メソッドにはこのクラスのインスタンスを渡して描画するようになっています。
また、Globalクラスはゲームの中で一度生成したら破棄しないものを入れておくためのクラスです。例えばゲーム全体に共通するグラフィクス関連のリソースなどを入れています。また、このクラスはstaticではなくSingletonパターンを使っていて、Global.Current.XXXXの様にメンバにアクセスします。staticクラスじゃない理由としては、インスタンスを作る時期を明示的にコントロールできる、拡張メソッドを追加できる(拡張メソッドはインスタンスメソッドのみに使える)、後でインスタンスクラスにしたい時に移行が楽になる、といった感じです。
また、この段階で将来的に作るであろうソースコードの種類を分類してフォルダーとして作っておきます(中身はカラ)。私は習慣的にこのフォルダの名前をGameXXXXといった名前にします。これはEnemyというフォルダ名を作ってしまうと、その中に更にEnemey.csという名前のクラスを作ることになってしまうので、名前衝突が起きてしまうのを避けるためです。
この段階では特に名前にこだわらずにゲームにありそうな名前を適当に付けていくだけです。そんな感じで作業開始から20分足らずの段階で下図のようなソリューションになります。
なぜ、この段階でカラのフォルダーだけ作るのかというと、作業の全体量を早めのうちに把握できるからです。あくまでゲームを完成させるのが目的なので、一部分だけ気合を入れすぎて作ってしまうと、他の部分とのバランスが取れなくなったりして、スケジュールが差し迫った時には他の部分を作りこむ余裕が無くなってしまった、なんていうことが良くあります。また、作業を進めていく途中でも「ここまでやった」という達成感があり、モチベーション維持にも役立ちます。
雛形ができたので実際にプログラムを組んでいきます。LightWaveのインポーターを作った時にテスト用に描画プログラムも書いたのですが、なにぶんテスト用だったので下図の左側のシーンツリーを素直に描画するだけのものでした。そこで、今回は簡単なマテリアルバッチ変換をして描画するように変更しました(マテリアルバッチの効果についてはGamefest Japan 2008デモプログラムを参考)。
「最適化は必要にならない限りしない」という言葉がありますし、私も同じ事を言ってるので、「おいおい、言ってることとやってることが違うじゃないか」と突っ込みが入りそうですが、実は今回マテリアルバッチを最初に組んだのには最適化以外の理由があります。
マテリアルバッチは描画高速化に有効な手立てのひとつですが、他にもシーンツリーがノード毎の座標空間を渡り歩いて「このノードのモデルを描画」という風に描画するのに対して、マテリアル毎に渡り歩いて「このマテリアルを使っているノードを描画」という風に描画の指定の仕方が違うという特徴があります。
実際のゲームではマテリアルをアニメーションさせたりすることが多いので、そういうときにもマテリアルバッチを使っていると処理がしやすくなります。
今回はまさにそれに該当するケースで、敵のエンジン(と思われる)部分の色をアニメーションさせたかったからです。例えば下図の場合では白い部分がアニメーションさせたい部分です。マテリアルバッチにしておけば、こまエンジン部分の色を一箇所で変えるだけで、このマテリアルを使っている全てのモデルに反映させることができます。
また、この部分を別のレンダーターゲットに描画し、ぼかした後に元のシーンと重ねることで下図のようにまぶしい光の表現もできるなぁ、と、この時は考えていました。
マテリアルバッチ処理のコードを書いた後はLightWaveから出力したシーンをアニメーションさせる部分をプログラム。今回のゲームは最初から最後までプレイすると6分程掛かります。これをひとつのシーンファイルにまとめてしまうと、敵の出現タイミングを合わせたりするのに時間が掛かるので、複数のシーンファイルに分けておいて連続で再生するようにしました。コード的には以下のように単純なものですが、このテーブルを変更することでテストしたいシーンからすぐに始められるので時間の節約になります。
GameScene[] scenes = { new StartScene("game-scene01"), // スタート new GameScene("game-scene02"), // ロウンチ new WarpScene("game-scene03"), // ワープ new AsteroidBeltScene("game-scene04"), // アステロイドベルト new BattleShipScene("game-scene05"), // 戦艦 new MotherShipScene("game-scene06"), // 空母 new PlanetScene("game-scene07"), // 惑星 };
これらの「GameScene」クラスを管理するGameScenePlayerクラスがあり、このクラスで現在再生中のゲームシーンの管理と、それぞれのシーンの連続再生をするようになっています。また、GameSceneは再生中にGameComponenetと同じようにUpdateとDrawが呼び出されるのでシーン毎に敵パターンなどを管理できるようになっています。
とりあえず、シーンの管理周りができたのでLightWaveでこの二日間でモデリングした3Dモデルを配置し、簡単なカメラの移動アニメーションを作り、実際にゲームに読み込んでテストしました。
さて、テストシーンでは殆どのモデルが正常に表示され、カメラのアニメーションも問題なく再生されました。ですが、ひとつDeath Ball(上図の左側にあるピンク色の四角形のモデル)のマテリアルが逆になって表示されているという問題がありました。
マテリアルが逆になっている問題ですが、丁度マテリアルバッチのプログラムを追加したので、その線が濃厚なのですがデバッグしてみると、マテリアル情報が元から逆になっていることが判明したのでインポーターのデバッグを開始しました。
コンテント・パイプラインのデバッグはここで紹介した方法のうち、デバッガをアタッチする方法を使っています。Visual Studio 2010を二つ起動させ、二つ目のVisual Studio 2010からゲームのプロジェクトを開いているVisual Studio 2010にアタッチします。
問題の起きるモデルと起きないモデルの比較をしながら、LWOファイルインポーターをデバッグしはじめて1時間半、LWOファイルのマテリアルの参照インデックスはマテリアルの宣言順ではなく、TAGSチャンクと呼ばれるデータの中で文字列が宣言されている順番だという仕様書読み間違いが原因でした。
インポーターのバグをとったついでに、LightWaveのシーンファイルであるLWSファイルを処理するプロセッサに新しい機能を追加することにしました。
LWSファイルのプロセッサはスキニングモデルサンプルと同様にコンテントビルド時にアニメーションデータをサンプリングするようになっていて、LightWaveで指定したフレームレートでサンプルするようになっています。
規定値では30FPSなので、この値をプロセッサパラメーターで設定できるようにし、60FPSでサンプリングするようにしました。
これで滑らかなアニメーションが再生されるようになりました。
LightWaveで作ったデータをゲーム内で表示、動作させる部分が完成したので、実際にゲームのシーンを作る準備が整いました。実際にシーンを作っていく前に、モデリングする時にサイズを気にせずにして作ったモデルのサイズ調整をします。
オリジナルのゲームの設定では戦艦のサイズが500m、母艦に至っては2Kmという大きさになっています。このままの数字でも問題ないのですが、これだけ大きなスケールには馴染みがないので実感がなく、シーンを作っている時に手探りになってしまうことがあります。
そこで、今回は設定の1/100スケールにします。つまり、500mの大きさの戦艦は5mになり、18mの設定の敵小型戦闘機は18cmの大きさになるわけです。このサイズになると、部屋の中に5mの大きさの戦艦があって、自分の手には18cmの大きさの模型を手に持ち、童心に返って「ブーン」なんて言いながら飛行経路を考えるなんてことが容易にできるようになります。
FPSなどの場合は現実にあるサイズをそのまま使ったりしますが、今回のようなSFものの場合はゲームのスケールを馴染みのある大きさに縮尺することでゲームプレイ部分をいつでも容易に考えることができます。
Game Building発表まで、あと3日……
月曜の朝は週末に溜まったメールに目を通すので、これに1時間程の時間を費やしてから作業開始です。
まずは曲面のモデリングですが、NURBSとか使った曲面モデリングはMayaでやったことがあるのですが、LightWaveではやったことがなかったので例によって例のごとくトレーニングビデオを観て勉強しました。 Introduction to the Bend Tool(ベンドツールの紹介) Adding thickness to single-sided geometry(板ポリゴンに厚みをつける方法)
今回はポリゴンで作った板をベンドツールを使って曲げることにしました。
外観が大体できたのですが、このシーンは巨大空母の内部に入っていくというシーンなので中に何もないと非常に寂しいので内部のモデリングすることにしました。
ここら辺の資料は殆どないので何度もビデオを観ながら、こんな感じかな?という感じに手探りでモデリングしたので時間が掛かりました。
プログラマーの葛藤、その1: ここへ来てマテリアル数が増えてきたので、ひとつひとつマテリアルを追加する度に「ああ、DrawIndexedPrimitiveの呼び出しがまた増える…」と悩むようになりました。テクスチャにして一つのマテリアルでごまかすという手もありますが、テクスチャを貼る、特にUV座標の編集は非常に時間が掛かるのでマテリアル数を追加することを選びました。「まぁ、実際のゲームではもっとマテリアル数があったりするから、これくらいでいいか」というようにプログラマー脳を眠らせながらモデリングしていました。
とりあえず、中身もそれっぽいものがモデリングできました。もちろん、時間を掛ければもっと細かい部分を追加できますが、今日中にモデリングは終わらせておきたかったので、ここで一旦終了して家に帰りました。
帰宅して、夕食を摂り、少し休んだ後にまたモデリング開始です。次のモデルは非常に形状が複雑な上に参考になる資料が少ないという状態だったのでモデリングするのが大変でした。
何度も何度もビデオを観て、複雑だと思ってた形状も八角形の形で、二種類のパーツを回転コピーさせるとできるということがわかってから黙々とそのパーツ郡をモデリングしていきました。
モデリング開始してから5時間以上経って、ようやくそれらしい形になりました。本当は内部のモデリングをしないといけないのですが、朝6時前で気力がないのと、これ以上モデリングに時間を費やしたら間に合わなくなりそうだったので、ここで切り上げることにしました。
これでGame Building二日目の作業を終えました。
明日からはこの二日間で作ったモデルを実際にゲームの中に組み込んでいくプログラミング作業を開始します。
さて、今回からは実際にGame Buildingでしたことをレポートしていきます。時間が妙に正確なのはTwitterでつぶやいた時刻がログに残っているからです。
注:今回の記事で参照しているトレーニングビデオのリンクはftpなので、クリックするだけでは見ることができないことがあります。右クリックメニューから対象を保存するを選んでダウンロードしてから観てください。
先週は仕事が入り、週末こそはGame Buildingの作業を始めようと思ってた矢先にいきなり歯が痛み出し、あまりの痛さに土曜日は一日中寝てました。それもあってこんな時間に目が覚めました。まだ歯は痛みますが、我慢できない程ではないのでモデリング作業開始です。
まずは作るモデルの参考にするためにこのビデオを観ました。LightWaveでまじめにモデリングするのはこれが初めてのことなので練習も兼ねて簡単なモデルから作っていきます。ちなみにこのBGMが大好きなんで、作業中はずっと流しっぱなしでした。
9月19日(日) 02:17AM Death Ball完成
まずは最初のモデルであるDeath Ball、簡単そうに見えますが操作になれるまで時間が掛かり、1時間以上掛かりました。この間にみたトレーニングビデオは以下の三つです。赤い部分は光らせたいので別のマテリアルで作りました。
Introduction to Action Center Control Introcution to the Bevel Tool(べベルツールの紹介) Introduction to Magic Bevel(マジックベベルの紹介)
9月19日(日) 03:26AM Faker完成
LightWaveの基本的な使い方が判らないのでNewTekのサイトからマニュアルをダウンロードしました。このモデルも1時間くらい掛かりました。
頂点、辺、面の選択、移動は判ったのですが、選択を全て外す簡単な方法が判らなかったので、ネットで検索して答えを発見。何も使っていないxキーをショートカットキーにして作業効率が大分上がりました。
9月19日(日) 05:08AM Faker完成
形状が複雑で、ビデオを見ても良く判らない場所があったりしたので試行錯誤しながら作業したので1時間半掛かりました。
9月19日(日) 05:58AM Talken完成
所要時間50分。モデリングに少し慣れてきました。
9月19日(日) 07:04AM Scutter完成
こういった形状をボックスプリミティブから作るというのを覚えました。所要時間はやはり1時間。6時間程連続で作業したので疲れたのと眠いのでお昼前まで寝ることにしました。
9月19日(日) 01:00PM トレーニングビデオ鑑賞
お昼を食べながら、トレーニングビデオを鑑賞。Booleans vs Speed Booleans(ブーリアンとクイックブーリアンの違い)を観てブーリアンを勉強しました。
9月19日(日) 02:18PM Hover 完成
早速、ブーリアンツールを使って足の部分と胴体を繋げることをしてみました。お陰で30分でできました。
9月19日(日) 03:37PM Blue Fly完成
約1時間で完成、ここでもブーリアン使いました。このあたりから平面問題が気になり始めました。ポリゴンで平面を作った後に頂点を移動させると、平面じゃなくなってしまい、描画が正しくできなくなるという問題です。三角形化すれば表示はされますが、デザイン的に平面にしたいことがあるので、良い方法が無いかを考え始めました。
9月19日(日) 04:45PM Large Tower Cannon完成
所要時間40分。このモデリングではここでも平面問題に悩まされましたが、良い解決策が思いつかないのでそのまま放置することにしました。
9月19日(日) 05:05PM Small Tower Cannon完成
これは簡単、と気を抜いたら間違ったモデルでファイルを上書きしてしまうという凡ミスをして、やり直しも含めると15分掛かりました。こういったモデリングをする時にはモデリング時のファイルと、ゲームで使うファイルは分けるのが普通です。これは実際の開発現場でもやっていることですが、モデリング時にあると便利なデータはゲーム内では要らないし、三角形化してある必要なゲーム用のデータではモデリングがしづらいという問題があるからです。
ただ、これだとデザイナーさんが扱うファイルが増えてしまうので、今回のようにファイル上書きミスとか、デザイン用ファイルは更新したけどゲーム用ファイルを更新し忘れたなんてことが発生したりします。
プログラマーの場合、バージョンコントロールなどを使ったりするのですが、デザイナー向けツールでもそういったバージョンコントロールが標準で備わっていて欲しいですね。
9月19日(日) 06:00PM Violet Bee完成
所要時間30分。これは見た瞬間にボックスの面を押し出し(Extrude)処理を続ければできそう、と思って実行してみたら、問題なくできました。
9月19日(日) 11:11PM Delta Nose完成
ここでもブーリアンを使って窪んでいるところを形作りました。所要時間は三時間半。時間は掛かりましたが、難易度的には高いとは感じませんでした。これくらいの大きさのモデリングになると、各パーツを個々にモデリングして組み立てるという感じになるようです。逆に小物の方が形状に気をつけないといけないので難しいと感じました。
この段階までくるとモデリングが楽しくなってきて、いくらでも細かい部分を追加できるのですが、時間の制約があるのでとりあえずという形で止める事にしました。プログラムの場合はプログラムが正常に動いた時点で作業完了という目処が立つのですが、モデリングの場合はいつまでも細かい部分をつけていけそうなのでデザイナーさんがいつまでも修正を加えていくという気分がなんとなく判ったような気がしました。
時間制限があるのでいらない作業をして時間を無駄にしないよう、作業の切り上げ時を判断することが大事だということを改めて認識しました。そんな作業短縮化の一つとして、このモデルの下の部分はゲーム中には見えないので、見えない部分のモデリングはしていません。
9月19日(月) 01:14AM Hammer Head完成
所要時間2時間。これは前のモデルと形状が似ていたので前より短い時間でモデリングすることができました。
そんな訳で、一日で12個のモデルを作ることができました。これが多いか少ないかは判断しかねますが、最初の方ではツールの使い方も良くわかっていない状態から考えれば、ここまで出来ればまぁまぁと言ったところでしょうか?
今日一日だけで何度も24時間トレーニングビデオ(英語)のお世話になっているのが判るかと思います。このトレーニングビデオの良い所は、機能ひとつひとつの紹介の中で基本的な使い方はもちろん、どんな時に使うのかということも紹介してあるので非常に役に立ちました。
前回の投稿で述べたように、ツールに関する情報の多さがそのまま開発効率向上に繋がっているというのが実感できた一日でした。
また、ゲームに必要のないところはモデリングしないで時間を節約するなど、単にモデリングをするだけよりもゲーム内容をしっかりと把握していれば、貴重な時間を費やすことも減ってくるというのも教訓のひとつですね。
Game Building発表まで、あと6日……
続く
今回のGame Buildingではゲームに出てくる3Dモデルをモデリングすることからはじめました。私が今回3Dモデリングツールに選んだのはLightWave 3Dでした。北米のゲーム開発現場で使われている3Dモデリングツールというと、Maya、3Ds Maxが主流となっていますが、個人で気軽に購入するというには値が張ります(MayaもAutodeskになってから実質値上げしてしまった)。それらのツールに比べると安価に入手できるLightWaveが個人や小規模のスタジオ(TVドラマの特殊効果スタジオも含む)ではLightWaveが使われていたりすることも多いようです。例えばBattlestar Galacticaシリーズの特殊効果はLightWaveで作られています。
世の中にはいろいろなモデリングツールがあるので、どれを選ぶかは人それぞれですし、選ぶ基準も値段、使いやすさ、ユーザーの多さといろいろありますが、私がツールを選ぶ基準を一言で表すと「情報量の多さ」です。
3Dモデリングツールは非常に複雑で、初めてツールを起動したときには誰もが困惑します。ここで、なんらかの足ががりがないと使いこなす前に挫折してしまうことでしょう。まずはツールのコンセプトを学ぶためのチュートリアル、ドキュメントでもいいのですがGUIツールという性質上、ビデオチュートリアルがあるのが好ましいです。また、使い方がよく解らなかったり、「こんなモデルを作るにはどうしたらいいのか?」という疑問があったときにネットで検索して即座に答えを得られるというのはとても大事なことです。
今回のGame Buildingで3Dモデリングをしているときにも、LightWaveに関する情報量の多さに助けられた場面が何度もありました。
また、プログラムと違ってチュートリアルビデオであれば、英語があまり理解できなくてもGUIの操作部分を見てればなんとなく解かるということも多いので、大量にある英語資料に目を通すことをお勧めします。例えば、それぞれのツール名+”3D”で検索すると以下のようになっています。
今回LightWaveを使うにあたって日本語資料がどれくらいあるか調べてみたのですが、チュートリアルやトレーニングビデオはあれど有償のものが殆どでした。
対して英語資料だと24時間トレーニングビデオ(英語)なんてものが無償で提供されていて、このビデオには何度も助けられました。
digital-tutorsというサイトではさまざまDCCツールのトレーニングビデオ(XNAもある)があるので、こちらもフリーのトレーニングビデオを一度見ることをお勧めします。
プログラマー視点からみると、どのDCCツールが自分のゲームに組み込みやすいかというのも基準になりますが、最近はプラグインなども豊富に提供されているので、扱いやすいファイルフォーマットに出力することでツール間の差を気にすることも少なくなってきたと思います。
結局、ゲーム全体で見ると、より良いコンテントをどれだけ早く作れるが重要になってくるので、自分の使いやすいツールを使いましょうということになりますね。
今回からGame Buildingで作ったゲームの製作過程を紹介していこうと思います。今まではどちらかというとプログラマー視点から記事を書くことが多かったのですが、今回のGame BuildingではXNA Game Studioをより良いものにする為に実際にインディーズ・ゲーム開発者側の視点に立ってゲーム製作をしてみようということを念頭に置いて製作しました。
また、Game Buildingでは限られた時間内で製作するという制限があります。Game Building期間中でも、他に作業が入ったりすることがあるので、いかにして短い間内で遊べるゲームを完成させることができるかがカギとなってきます。今回のGame Buildingは全体で二週間あったのですが、私が実際に作業できたのは9月19日(日)~9月24日(金)の午後四時まで、日付の上では6日間でしたが、途中で仕事が入ったので実質5日間の作業期間となりました。
この短期間内では新しいゲームプレイを企画して試したりする時間がないので、既存のゲームを作ることにしました。元となったゲームはギャラクシアン3と呼ばれる16年前のゲームです。当時は二つのLDプレイヤーを使ってあらかじめ用意されたビデオ画像の上に3Dポリゴンで表示された敵を撃つというゲームでした。今だったらリアルタイムでできそうだし、背景自体とのインタラクションは少ないし、移動する敵を撃つだけというシンプルなゲーム内容なのでプログラム技術的には問題なさそうということで、今回はこのゲームを再現することにしました。
私はこのゲームが大好きで、アーケードに通いまくって6人プレーのところを一人でクリアできるよう頑張ったり、ゲーム内容を収録したLDとか、サントラとか、設定資料集まで買ったりしていました。PS1版があるのですが、動画のフレームレートが低く(たぶん15FPS程度?)、あんまり快適とは言えないものでした。
個人的にはネットワーク対応にして大人数でプレイできれば面白そうなのに、とは思うのですがそういった話もとんと聞かないので、ないのなら自分で作ってしまおうということで、今回のGame Buildingで作ることにしました。
今回は作業を始める段階で自作しておいたコンテント・パイプラインのライブラリがあったのが大幅な作業短縮に繋がりました。このライブラリは3DモデリングツールのLightWaveのモデルファイルフォーマットであるLWOファイルと、シーンファイルフォーマットであるLWSファイルのインポーターとプロセッサがあります。ですから、プロジェクト上に直接LWOファイルとLWSファイルを追加するだけで簡単にコンテントを追加することができるようになっています。
また、テスト用に作っておいたシーンファイル再生ライブラリがあるのでそれを流用することにします。LightWave用のパイプライン・ライブラリにはLightWaveで作ったアニメーションをCurveクラスのデータに変換するようになっていますが、大量のCurveクラスを使うのは処理速度的に厳しそうだったので、スキニングモデルサンプルにあるAnimationPlayerを元にしてあらかじめキーフレームデータへと変換するようになっています。
コンテントとして流用したのは最初の出撃シーンで、これは友人がモデリングしてもらったものを使わせてもらいました。
次回からは、時系列毎にGame Buildingの5日間にあった出来事を書いていきます。
NickがGame Buildingで作ったゲームの紹介と、XNA Game Studio 4.0を使っての製作過程の紹介を複数回に渡って紹介しています。
My AppWeek 2010
The delights of DualTextureEffect 4.0で追加されたDualTextureEffectを使ってライトマップを実現しています。ライトマップ自体は3D World Studioを使って生成しています。
Batch your polygons 3D World Studioから出力されたモデルをそのまま使うと実行時のDraw呼び出しの回数が増え、4画面分割の場合には716回の呼び出しになってしまうという問題がありました。Nickはランタイム時にビューカリングするのではなく、複数のモデルをまとめるカスタム・プロセッサを作ることで描画関数呼び出しの回数を716回から20回にまで減らすことでパフォーマンスが劇的に向上しました。
ここでのポイントは実装に時間の掛かるポータルカリングなどの実行時の最適化をせずにコンテント自体を最適化することで少ない労力で効果的に最適化したということでしょう。
Don’t reinvent those wheels 限られた時間の中でゲームを作るというGame Guildingはいかにして効果的にゲームを作ることができるかという事が課題になります。
そこでNickは、EasyConfig、BoxCollider、パーティクルサンプルなどの既存のコードを組み合わせることで製作時間の短縮を実現しています。パーティクルサンプルはグレネードの表現に使ったそうです。
Nickはゲームを完成させたいのであれば、世の中に流用できるものが無いかを探すのにほんの少し時間を掛けることで開発速度のアップにつながるとしています。
Don’t build more than what you need Nickは、最初のうちは空き時間を使って作っていた3Dゲームエンジンを完成させ、自分のゲームに使おうと思いましたが作っているうちに開発速度が思ってたよりも遅いということに気づきました。
そこでNickは途中で自作の3Dゲームエンジンを捨てて、Game Buildingに必要な部分だけを作るようにしたことで殆ど時間を費やすこともなくエンジンを使っていたところまで組みなおし、その後も理想的な開発速度を保ちながら開発を続けることができました。
ここでの教訓として、3Dゲームエンジンを自作するのは技術的に楽しいものですが、作りたいゲームが定まらない状態だと、不必要な機能を盛り込んだりして終わりが見えず、時間が掛かりすぎて最終的にモチベーションが続かずに放置するなんてことを経験した人は少なからず居ることと思います。
逆に自分が作りたいゲームをしっかりと把握していると迷うことなく短い時間でゲームを完成させることができます。大事なのは「ゲームを作りたい」よりも「ゲームを完成させる」という目的意識を持つことです。
と、まじめな話になってしまったので、ここでちょっと一息。
昨日の投稿で紹介し忘れたゲームがひとつありました。作成したCooperは、グラフィクスよりもオーディオ部分に気合を入れて作っていたので残念ながらゲームシーンのスクリーンショットはありませんが、そのタイトルは
Beers of War (ビアーズ オブ ウォー)
です。私はこのタイトル画面を見た瞬間にあのテーマ曲が頭の中で再生されました(笑)
内容は、缶ビールと瓶ビールの壮絶な戦いを描いたゲームだそうです。プレイヤーが操るのは缶ビール側で、南部訛りの英語で喋るカウボーイタイプなキャラクター(でも缶)のBud(バド)、筋肉ムキムキタイプ(でもやっぱり缶)のColt(コルト)、45才。某ゲームに出てくるマーカスタイプ(だから缶だって)のFlask(フラスク)、そしてオーストラリア訛りのFosters(フォスタース)の4人のキャラクターを操ることができる予定だったようです。
ゲームは一般的なFPSなのですが、ビール瓶の敵を倒すたびに
「バド、なんでお前はワインクーラー臭ぇんだ?」
「今日はリサイクル業者が大忙しだな」
「なんで、この町はこん���に見てくれが悪いんだ?」「ライトマップが無いからであります、サー」
という、ユニークな台詞が大うけでした。
是非、このまま続けて作って欲しいですね。
XNA Game Studio 4.0がリリースされ(Xbox 360のランタイムの完成版はもう少し待ってね)、XNAチーム内では恒例のGame Building(AppWeek)がありました。3.1の時のAppWeekのゲーム紹介はここ。
いつもならGame Buildingの期間は一週間程度なのですが、今回は二週間という長い期間があり、皆いろんなゲームを作っていました。残念ながら、私は他にしなければいけない作業が入ったので実質5日間のGame Buildingとなりました。
いつもはプログラム部分に大半の時間を掛けるのですが、以前作っておいたコンテント・パイプラインのインポーターやプロセッサを流用したので、今回はコンテント製作とプログラムが半々といった感じになりました。
このゲームは16年程前にあったゲームで、当時はLD(レーザーディスク)で再生された背景の上に敵が3Dポリゴン表示されているというものでした。今だったら全部リアルタイムで描画できそうだし、ネットワーク対応にしたら面白いかも?という思いつきで作ってみました。分類的には今では少なくなったレイルシューターなので、まずは習作という意味でオリジナルシーンをどこまで再現できるか試してみました。残念ながら、ゲームの最後のシーンまでは時間ができなくて再現できませんでしたが、当時の雰囲気をある程度までは再現できていると思います。
上の動画はYouTube版ですが、ニコニコ動画版の方に60FPSでキャプチャーしたものをおいておきました。
こちらはShawnが作ったソフトウェアシンセサイザーです。4.0からサポートされたダイナミックオーディオ機能を使い、WinFormサンプルをベースにして各モジュールをつなげ合わせることで複雑な音を生成することができます。リズム機能もあり、この図はドラムセットをビートに合わせて再生しているものです。
続いてNickが作ったのはFPSゲームです。グラフィクスはDualTextureEffectを使ってライトマップを実現しています。DualTextureEffectはWindows Phoneでも動作するので同じものがWindows Phoneでも遊べるようになっています。
Rezaの作品はDeferredレンダリングを使ったもので、沢山の点光源が移動する様は幻想的でもありますが、ゲーム内容の方はアバターを操り、手にしたバットで光を叩きまくるという幻想的とは言えないものでした(汗)
こちらはXiaoyueの作ったゲームで、プレイヤーである玉を操作して囲った領域を消して敵を倒すというゲーム(名前が思い出せない)なのですが、このゲームではプレイヤーが弾を撃って敵を倒すこともできます。ちなみに画面に映っているいるのはボスのバナナ(3Dで描画されている)です。
続いてAaron、Brett、Mike、そしてMarcの4人で作ったCEOZ(Crunchy Employee Offering for Zombies)というゲームです。迫り来るゾンビを倒すというゲームの中に中間管理職として社員を殺さずに効率的にゾンビを撃退することができるかが試されるシミュレーションゲームということらしいです。
こちらはEricの作ったShape Shooter、コントローラーのボタンの色と敵の色との組み合わせによって時間内に得点を競うゲームで、最大4人まで同時プレイができます。見た目はシンプルですが、小魚の群れのように移動する敵の動きが特徴的でした。
Shannonが作ったのはコンテントを作るのがアレだから、コンテントを作ることを断念して作ったというゲームです。こちらもスクリーショットを見るとシンプルですが、有機的に移動する四角に敵の動きが面白かったです。
そして、今回のGame Buildingで最もウケたのがJaceの作ったゲームでした。Game Buildingではチーム内で受けを狙う為に作る人も居るのですが、内輪向けということでピア・レビュー絶対通らないとか、ブログで紹介すらできないよっていうものまであります。ちなみに、JaceはGame Building発表の前日に私のところへ「アバターの腕だけ表示させたいんだけど、どうしたら良いかな?」と、相談しに来ました。なんで腕だけを表示させたいのか首をかしげながらも、いくつかの質問に答えたのですが、その結果がこんなゲームになるとは思いませんでした。
ゲーム内容は至って単純で、4人プレーでAボタンをいかに早く連打するかを競うといものです。
一番最初にゲージを満タンにした人の勝利となります。
これで終わりかな?と思っているとおもむろにカウントダウンが始まり、負けたアバターが不思議そうにあたりをキョロキョロと見回します。
ここから先は説明する必要はないでしょう。スクリーンショットを見てください。
さて、これを見た人の中には「やってみたい」と思う人がいるかも知れませんが、念のために言っておきますが禁止されているアバターの取り扱いの中では
出血や流血、手足または頭部の切断、身体への損傷、身体に致命的な欠損を生じるような暴力行為
と明言されているので、同じようなゲームを作った場合は投稿直後にピアレビューが蹴られるので注意しましょう(汗)。
デバッグコマンドはゲーム開発する上では欠かせないツールの一つですがXbox 360上で使用するにはUSBキーボードが必要になります。私の場合は新し物好きで定期的にキーボードを買い換えるので家の中には使っていないキーボードが幾つかあり、いならくなったキーボードを使っていました。
ですが、最近になって11年物のTVが写らなくなってしまい、ようやっとHDTVというものを購入しました。新しいTVの画面上で自分の作ったゲームが動いているのを見るのは楽しいので、リビングルームでソファに座りながらプログラムするという機会が増えました。
そこで、新たに起きた問題が発生しました。その問題を図式化したのが以下の図です。
ソファーに座っていると、ねこさん達が私の膝の上に乗ってきます。これから寒くなってくる時期には暖かいねこが膝の上に乗ってくるというのはありがたいものです。ですが、デバッグコマンドを使おうとするときに問題が発生します。デバッグコマンドを使用するときにはXbox 360に接続されたキーボードがあるところまで移動しないといけません。その為には膝の上のねこをどける必要があるのですが、せっかく寄ってきたねこさんを無下にする訳にもいきません。
USB延長ケーブルで手元にキーボードを持ってくるという方法もありますが、コントローラーも無線、Xbox 360へのゲームの転送もWiFi使っているので無線という環境なので、延長ケーブルを使うというのはスマートではありません。
そこで新たに追加したデバッグコマンドがremoteコマンドです。remoteコマンドはWindowsとXbox 360上で同じゲームを実行している時にNetworkSession機能を使い、Windows上で動作しているゲームで入力したコマンドをXbox 360で実行するというものです。
下図はWindows上でremoteコマンドを実行した状態のものです。
リモートコマンドの実行が成功するとデバッグコマンドがリモートコマンドモードへと移行し、今まではCMD>と表示されていたものが[Client]と表示されます。この状態で入力されたコマンドはXbox 360側へと送られ実行され、実行された結果はWindows側へと送られます。リモートコマンド状態から抜け出すにはquitコマンドを使用します。
ゲームへの追加以下のようにコンポーネントを追加するだけです。Windwos Phoneには対応していないので、#ifdefで括っておくと良いでしょう。
#if WINDOWS || XBOX // リモートデバッグコマンド「remote」の追加 Components.Add(new RemoteDebugCommand(this)); #endif
#if WINDOWS || XBOX
// リモートデバッグコマンド「remote」の追加
Components.Add(new RemoteDebugCommand(this));
#endif
NetworkSessionを使っているのでGamerServicesを初期化する必要があるのですが、remoteコマンドはGamerServicesを使っていない場合は自動で初期化するので、GamerServicesを使っていないゲームでも特別なコードを書く必要がなく使えます。また、既にNetworkSessionを使っている場合にはゲーム側で作ったNetworkSessionをRemoteDebugCommand.NetworkSessionへ設定し、文字列データを受け取った場合にRemoteDebugCommand.ProcessRecievedPacketメソッドを呼び出すようにすることで共存できるようになっています。
ただし、最低でもローカルプロファイルがサインインしている必要があります。
ここで見逃しがちなのが、ローカルプロファイルの作るにはプロファイルの生成を選択した後の画面で下の方にスクロールさせた場所にあるリンクをクリックする必要があるということです。
実のことを言うと、remoteコマンドはデバッグサンプルの3.1版を公開したときに既にあった機能でしたが、いままで説明するのをすっかり忘れていました(汗)。そんな訳で、このリモートコマンド機能は前日に公開した4.0版のデバッグサンプルに既に含まれており、リモートコマンドも登録してあるので、そのまま使えるようになっています。
これで私は膝の上に乗っているねこさんを降ろすことなくデバッグコマンドが使えるようになりました。
と、いうのは半分冗談で、実はリモートコマンドにはもう一つの重要な役割があります。