Twitter @HigenekoTwitter #XNA
上の画面はテクスチャのプロパティ画面です。Content Processorの脇に+のついた四角いマークに気づいたでしょうか?
クリックすると複数のパラメーターが表示されます。これがXNA GS 2.0の新機能の一つであるプロセッサパラメーターです。XNA GSE 1.0では複数の複数のプロセッサを書く必要がありましたが、XNA GS 2.0ではひとつのパラメーターつきのプロセッサを書くだけで、どのようにコンテントがプロセスされるかを指定できるようになりました。
Textureプロセッサには以下のパラメーターが設定できます。
パラメーター名
用途
Modelプロセッサでは以下のパラメータが設定できます。
プロセッサパラメーターは自分で作ったプロセッサでも簡単に使えるようになっています。ちなみにコンテントパイプラインを拡張するのに便利な"Content Pipeline Extension Library (2.0)"テンプレートがXNA GS 2.0では追加されました。またカスタムプロセッサや、カスタムインポーターの雛形となるContent Processor、Content Importerテンプレートをソースコード追加時に指定できるようになりました。
プロセッサパラメーターをカスタムプロセッサへ追加するのは簡単でプロパティを宣言するだけです。
[ContentProcessor(DisplayName = "ねこプロセッサ")] public class NekoProcessor : ContentProcessor<TInput, TOutput> { // プロセッサパラメーター public bool NekoMode { get { return nekoMode; } set { return nekoMode = value; } } bool nekoMode = false;
このままでは味気ないので、以下のようにアトリビュートを指定することによってプロパティ画面でより読みやすい状態にすることができます。これらのアトリビュートはSystem.ComponentModel内で宣言されています。
// 規定値の指定 [DefaultValue(false)] // 表示される文字列の指定 [DisplayName("ねこモード")] // パラメーターの説明 [Description("Trueにすると、なんとなくねこっぽくなります")] public bool NekoMode {
このプロセッサをコンパイルすると、プロパティ画面では以下のようにパラメーターの説明つきで分かりやすい表示になります(説明自体が分かりやすいかどうかは別問題ですが…)。
今まではどんなに小さなパラメーターでも直接コードで変更するか、インポーターを介して読まないといけなかったのですが、プロセッサパラメータを使うことでそういった煩雑な作業をする必要が大幅に減ることになるでしょう。
原文URL
http://blogs.msdn.com/shawnhar/archive/2007/11/26/content-processor-parameters-in-xna-game-studio-2-0.aspx
フォーラムの質問を見て、今まで書いていなかったことに気づいたので遅ればせながらカスタムエフェクトの使い方を説明します。
例によって例の如く、コピー元はShawn Hargreaves氏の投稿からです。
独自に作ったエフェクトを使うには2つの方法があります。ひとつはコンテント・パイプラインが処理したエフェクトをゲーム実行時に切り替える方法。そしてふたつ目はカスタムプロセッサを書くことで、コンテントパイプライン内でコンテントビルド時に独自のエフェクトに切り替える方法です。
後者の方法の方が自由度が高く、ゲーム実行時に余計な処理をしなくて済むようになるので、ここではこの方法を紹介します。
まず最初にModelProcessorから派生したプロセッサーを作り、ConvertMaterialメソッドをオーバーライドします。
/// <summary> /// ModelProcessorから派生したプロセッサー /// </summary> [ContentProcessor(DisplayName = "MyModelProcessor")] public class MyModelProcessor : ModelProcessor { // ConvertMaterialをオーバーライドして、マテリアル変換時に自分のマテリアルに差し替える protected override MaterialContent ConvertMaterial(MaterialContent material, ContentProcessorContext context) { // エフェクトを含むことのできるEffectMaterialContentを使う EffectMaterialContent myMaterial = new EffectMaterialContent(); // 使いたいエフェクトファイルを外部参照として指定する string effectPath = Path.GetFullPath("MyEffect.fx"); myMaterial.Effect = new ExternalReference<EffectContent>(effectPath); // 引数で渡されたmaterialの代わりに、ここで作ったmyMaterialを渡す return base.ConvertMaterial(myMaterial, context); } }
ここで指定しているMyEffect.fxファイルは直接読み込んでいるので、Visual Studioのプロジェクトに追加する必要はありません。また、複数のモデルやメッシュから参照されている場合でもこのマテリアルの実体は一度しか作られません。
このサンプルコードでは直接ファイル名を指定していますが、渡されたマテリアル名(material.Name)や、material.OpaqueDataからファイル名を取得したり、ProcessメソッドをオーバーライドしてNodeContentの情報を保持しておいて、以下のコードのようにしてモデルファイルからの相対パスでファイル名を指定することもできます。
string directory = Path.GetDirectoryName(rootNode.Identity.SourceFilename); string effectPath = Path.Combine(directory, "MyEffect.fx");
これでエフェクトが使えますが、エフェクトにはパラメーターを設定するのが普通です。また、基本的なマテリアル情報は渡されたマテリアルから取得できるので、以下のようなコードを書くことができます。
if (material is BasicMaterialContent) { BasicMaterialContent basicMaterial = (BasicMaterialContent)material; // エフェクトで使うテクスチャを設定する myMaterial.Textures.Add("DiffuseTexture", basicMaterial.Texture); // ここで任意のエフェクトパラメーターの設定もできる myMaterial.OpaqueData.Add("Shininess", basicMaterial.SpecularPower * 10); myMaterial.OpaqueData.Add("BumpSize", 42); } else if (material is EffectMaterialContent) { EffectMaterialContent effectMaterial = (EffectMaterialContent)material; // TODO: 渡されたマテリアルがEffectMaterialContentだった // 時の処理をここでする(必要ならば) } else throw new Exception("なんじゃこりぁ?");
ここで設定したエフェクトやそのパラメーターは実行時に自動的に読み込まれ、設定されます。これで実行時の特別な処理いらずで通常のModelを描画するようにして独自のエフェクトが適用されたモデルを描画することができます。
XNA 2.0リリースと同時に配信されたネットワーク対応のスターターキットにNet Rumbleがありますが、もっとシンプルなサンプルが欲しいという人の為に4つのネットワークサンプルコードが配信されました。
Network Architectures: Client/Sever
XNA 2.0上でのシンプルなサーバー/クライアント型のネットワークゲームのサンプルです。このサンプルではクライアントは単に入力情報をサーバーに送るのと、レンダリングするだけの処理をしています。サーバー側はクライアントから受け取った情報を元にシミュレーションを実行し、その結果をクライアントに送るようになっています。
Network Architectures: Peer-to-Peer
上記のサーバー/クライアント形式に対して、このサンプルではピア・ツー・ピア形式のプログラムになっています。それぞれが自分の戦車のコントロールとシュミレーションを行い、その結果をセッションに参加している全てのプレイヤーに送るようになっています。そして、その結果を受け取った側は、その情報を元に処理を行います。
Network Game State Management
このサンプルではネットワークゲームを作る場合のセッション参加のための必要なシンプルなメニューを用いて行います。 シングルプレイヤー、LIVE、またはシステムリンクの選択に始まり、新規セッションの追加、動作中のセッションへの参加などの処理をしています。また、ネットワークに起因するエラーハンドリングの処理も行っているので参考になります。
Network Prediction Sample
上で紹介したクライアント/サーバーとピア・ツー・ピアのサンプルでは1/60秒毎にデータを送っています。これはLAN環境では問題なく動作しますが、インターネットを介して遊ぶ場合には遅延や帯域の問題があります。そこで、このサンプルではピア・ツー・ピアのサンプルを元にしてインターネットを介しても動作するプログラムに改善しています。戦車の動きはパケットロスや遅延があった場合でも滑らかに動くように予測処理がなされています。またLAN環境でもインターネット環境をシミュレートするためにNetworkSession.SimulateLatencyやNetworkSession.SimulatedPacketLossを使っています。
これらのサンプルの他にも英文ですが、Shawn Hargreaves氏のサイトではネットワークゲームに関する有用な投稿が複数あります。
Network Latency
Network Packet loss
Network bandwidth: packet headers
Network bandwidth: voice
ひにけにの方でも、これらの投稿を日本語訳(意訳?)していこうと思います。
それ以外にもXNAチームメンバのブログを日本語で紹介して欲しいという要望があればコメント欄でリクエストを受け付けます。
XNA 2.0のプロジェクジェクトをソリューションエクスプローラで見ると以下のようになっています。
参照設定の項目が二つあることに気づいたでしょうか?これはContentがWindowsGame1のサブプロジェクトになっているからです。XNA 2.0では、このサブプロジェクト内にコンテントを追加します。その他にも、以前まではメインプロジェクトに記述されていたコンテントに関する情報、例えばコンテントがどのようにインポートされプロセスされるかの情報、カスタマイズされたコンテントパイプラインアセンブリの参照などが含まれます。
以前はWindows、Xbox 360の両対応のゲームを開発している時に、XNA 1.0ではそれぞれのプロジェクトに同じコンテントを追加しないといけませんでした。それだけでもコンテントの管理が面倒だったのですが、XNA 2.0になってプロセッサプロパティ対応になったので、細かいパラメーター設定まで両方のプラットフォームのプロジェクトで設定しないというのは面倒であり、エラーの原因にもなります。
そこで、XNA 2.0ではWindows、Xbox 360の両プラットフォームでコンテント情報を共有するための仕組みとしてできたのがコンテントサブプロジェクトです。
XNA 2.0ではWindowsプロジェクトを作ったときにプロジェクトの右クリックメニューで「Create Copy of Project for Xbox 360...」を選択すると、Windosプロジェクトを元にしてXbox 360用のプロジェクトを作ることができます。この時、両方のプロジェクトにコンテントプロジェクトが存在しますが実際には同じサブプロジェクトを参照しているだけです。
コンテントプロジェクトを共有している訳ですから、Windowsのコンテントプロジェクトにコンテントを追加すると、同じコンテントがXbox 360側のコンテントプロジェクトにも追加されるようになっています。これでWindows、Xbox 360両対応のゲームを作る時の手間が大幅に減ることになります。
このコンテントプロジェクト、テンプレートを使ってゲームプロジェクトを作った場合、「プロジェクトフォルダ\Content」フォルダ内にContent.contentprojというファイル名で作られます。
このファイル中身は知らない人には単なるXMLファイルのように見えますが、Visual Studio 2005から採用された新しいビルトツールであるMSBuildのプロジェクトになっています。Visual Studio 2005やVisual C# Express上でビルドした場合、裏ではMSBuildがビルドする仕事を担っています。
実は普段目にしている.csprojファイルもMSBuild用のプロジェクトファイルになっているのでパスの通っている状態でコマンドラインから
msbuild.exe myproject.csproj
と、タイプするとC#のプロジェクトをビルドすることができます。もちろん、Content.contentprojファイルも単独でビルドすることができます。つまり、コンテントビルドだけを単独で行うことができるわけです。
「コマンドラインなんて普段使わないから、関係ないのでは」と思う人もいるかもしれませんが、この仕組みを利用して以前紹介したコンテントパイプラインのデバッグをする第3の方法に使える訳です。
この方法はVisual Studio 2005上でしか使えませんが、コンテントパイプライン拡張用のプロジェクトのプロパティ画面のデバッグ設定を以下のように変更することでコードに変更を加えることなくデバッグすることができます。
これで、カスタムプロセッサのデバッグなどを普通のプロジェクトをデバッグする時と同じようにデバッグすることができます。デバッグ設定は一度設定すれば後は変更する頻度は少ないので、コードを変更する必要のある他の手法に比べるとお手軽かもしれません。
デフォルトではプラットフォームはWindows、Debug状態の設定でビルトが行われます。プラットフォームを変更したい場合はコマンドライン引数でファイル名を指定する前にWindowsならば
/p:XnaPlatform=Windows
Xbox 360の場合は
/p:XnaPlatform="Xbox 360"
と、指定することで異なるプラットフォームでのコンテントビルドをすることができます。
デバッグ、リリースの変更は
/p:BuildConfiguration=Debug
または
/p:BuildConfiguration=Release
と、することで変更することができます。
XNA1.0で作ったソースコードをXNA2.0に移植していて最初に気づくのは以下の警告メッセージだと思います。
warning CS0672: Member 'MyGame.Game1.LoadGraphicsContent(bool)' overrides obsolete member 'Microsoft.Xna.Framework.Game.LoadGraphicsContent(bool)'.
結論から書くと、XNA2.0ではグラフィクスリソースの扱いが簡単になり、Windows上で発生するデバイスロスト等の問題を気にする必要が殆ど無なり、新しく追加されたGame.LoadContent内でグラフィクスリソースを簡単に生成できるようになりました。LoadGraphicsContentメソッドもXNA 1.0との互換性を保つために一度だけ呼ばれます。
Texture2D、VertexBuffer、RenderTargetなどの全てのグラフィクスリソースはXNA2.0上では一度生成したら、そのインスタンスは常に有効な状態になります。もちろん、デバイスロストやデバイスリセットが発生するケース、例えばウィンドウのサイズ変更、フルスクリーンへの切り替え、マルチモニタ環境でウィンドウをモニタ間で移動したときでも最初に作ったインスタンスは問題なく使えます。
ただしDirectX 9のドライバモデルの制限上、RenderTargetやDynamicVertexBufferといった動的に内容を書き換えるグラフィクスリソースの中身はデバイスロスト時に破棄されてしまいます。通常、動的に生成されるグラフィクスリソースの多くは毎フレーム毎に生成されるので、その内容が破棄されても次のフレームで生成されるので特別な処理をする必要がありません。フレーム間でその内容を保持しなければいけないグラフィクスリソース、例えばHDRレンダリングで使われるトーンマッピング用の明度テクスチャ、前のフレームの内容を重ねて描くことによるモーションブラーなどの手法を使うときにのみデバイスロスト時に正しい初期値にする必要があります。
まとめると:
と、いった感じになります。
XNA1.0ではGameクラスやDrawableComponentクラスにはLoadGraphicsContentとUnloadGraphicsContentメソッドがあり、デバイスリセット時にはUnloadGraphicsContent(flase)、LoadGraphicsContent(false)の順に呼ばれ、デバイスの再構築時にはUnloadGraphicsContent(true)、LoadGraphicsContent(true)の順に呼び出され、その関数の中でグラフィクスリソースの開放と生成をしなければいけませんでした。
ここでの問題はTexture2DやVertexBufferといったインスタンスを生成する必要があるので、ゲーム側のでこれらのオブジェクトを参照している場合、それらの参照を更新する必要がありました。これではゲームが複雑になるに比例してLoadGraphicsContentメソッド内のコードも複雑になるし、予期せぬエラーの原因になってしまいます。
XNA 2.0では、この問題を解決することでグラフィクスリソースの管理が格段に簡単になりました。
Texture2DやVertexBufferといったマネージクラスは内部でネイティブのリソースを管理しています。XNA 1.0ではデバイスロスト時にマネージクラス自体を破棄する必要がありましたが、XNA 2.0ではマネージクラスは内部でネイティブリソースに対して処理をするようになっています。マネージクラスはテクスチャのサイズやフォーマットといったネイティブリソースの生成情報を保持しているので、ネイティブリソースの再構築が必要なときでも自動的にネイティブリソースを生成しなおすことができます。
また、デバイスの再構築が必要なとき、例えばウィンドウを他のモニタへ移動させた場合、マネージクラスはD3DPOOL_MANAGEDでつくられたリソースの内容を一旦メインメモリに保持してから、ネイティブリソースの再構築、リソースの内容の復元を行うようになっています。
Xbox 360上ではデバイスロスト自体発生しないので、上記のようなGraphicsDeviceの仮想化処理は最初からする必要がありません。逆に言えば、XNA 2.0ではXbox 360のようにデバイスロストのない開発しやすい環境をWindos上に持ってきたとも言えます。
参考URL:
http://blogs.msdn.com/shawnhar/archive/2007/12/12/virtualizing-the-graphicsdevice-in-xna-game-studio-2-0.aspx
と、言うわけでXNA Game Studio 2.0がリーリスされました。
以下のリンクからダウンロードできます。
http://www.microsoft.com/downloads/details.aspx?FamilyId=DF80D533-BA87-40B4-ABE2-1EF12EA506B7&displaylang=en
インストール時の注意としてはXNA 2.0のベータ版をアンインストールしてからリリース版をインストールしてください。このとき、Games for Windows Live Redistもアンインストールするのを忘れないでください。
その他は
といった感じです。
ネットワークゲームの開発環境としてはクリエータークラブ会員である場合はXbox 360とWindowsマシンをLAN接続している環境、つまりXbox 360用ゲームを開発できる環境があればXbox 360、Windows間で遊べるネットワークゲームを作ることができます。
クリエータークラブ会員でなくとも、Windowsマシンを2つ用意してLAN接続することで実現できます。