ばぐだし

XNAとかで面白いもの作る。

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

XNAの3Dモデルが透けてしまうことについて

前回の記事で書きましたが、3Dモデルを描画すると後ろの物体が透けてしまいました。
よくよく見ると、どうやら物体の描画順序が遅いものが上書きされてしまっているようです。

で、いろいろ調べたのですが、Integration Of Memeplexesさんの記事で

protected override void Draw(GameTime gameTime)
{
graphics.GraphicsDevice.Clear(
ClearOptions.Target | ClearOptions.DepthBuffer, //色と深度バッファをクリア
Color.CornflowerBlue, //色の初期値
0, //深度バッファの初期値(いちばん近い所からはじめる)
0 //ステンシルバッファの初期値
);

graphics.GraphicsDevice.RenderState.DepthBufferFunction = CompareFunction.GreaterEqual;
blueTriangle.Draw(graphics.GraphicsDevice, basicEffect);
redTriangle.Draw(graphics.GraphicsDevice, basicEffect);
}
}

なるコードを発見。
GraphicsDevice.Clear関数は1つだけと思っていましたが、
複数の引数をとることができるようです。

そこで描画の基本部分をSpaceWarからコピペすることにしました。
といっても基本的には、
drawDepthBuffer = new DepthStencilBuffer(引数略);

graphics.GraphicsDevice.DepthStencilBuffer = drawDepthBuffer;

を追加して、
graphics.GraphicsDevice.Clear(ClearOptions.DepthBuffer, Color.CornflowerBlue, 1.0f, 0);

のようにClear()関数で引数を指定してやればよいでしょう。

以上で問題が解決して、無事に3Dモデルを表示できました。
これでやっと前に作ったもやしもんのオリゼー君をXNAで表示できます。

orize3D

ただやすー

スポンサーサイト

3Dモデル表示の実装

今回は3Dモデル表示のための実装です。

前々回のXNA記事でお話したことをおさらいすると、3Dモデルの表示には以下の行列が必要になります。
  • ワールド行列
  • ビュー行列
  • 射影変換行列
これらを定義できれば、とりあえず3Dモデルを出力することはできます。

ところで、3Dモデルを1つのクラスとしてみた場合、上記すべての行列を自分で生成・保持する必要はあるのでしょうか?
ワールド行列はモデルの位置姿勢を定義するものです。なのでモデルに依存します。
ビュー行列はカメラの位置姿勢ですね。なのでカメラに移るモデルに共有されなければなりません。
射影変換行列もビュー行列と同様です。

そんなわけでまずはビュー行列と射影変換行列を管理するCameraクラスを作ります。
これは各クラスから簡単に参照できるようにしたいので、staticオブジェクトとしてGameクラスが保持します。てかSpaceWarでそうしてたのでそうします。

次は3DモデルのクラスMover3Dを作ります。
こいつにはワールド行列と3Dモデルデータを保持させます。

そんなこんなで表示できました。
SpaceWar

後側が透けて見えてしまっています。これはいかんですな。
ですがとりあえず表示とコントローラでの回転や移動はできました。

描画部分のソースはこちら。

//モデルの描画
foreach (ModelMesh mesh in _model.Meshes)
{
//エフェクトの指定
foreach (BasicEffect effect in mesh.Effects)
{
//ライティング
effect.EnableDefaultLighting();

//ワールド変換行列
effect.World = _world;

//ビュー変換行列
effect.View = ShtGame.Camera.View;

//射影変換行列
effect.Projection = ShtGame.Camera.Projection;
}
mesh.Draw();
}


透けているのはeffectに与えるパラメータが不足しているからでしょうか。
それともGameDeviceのパラメータ関連?
次回はこれの解決方法を調べます。

あとModel、Mesh、Effectの関係がなんとなくしか分かっていないのと、
GraphicsDevice.RenderStateプロパティいじったらいろいろ出来そうなので、
これらについてもそのうち調べる予定です。
ま、我慢しきれなくなって製作に移っちゃうかもしれませんが。

XBOX Live コミュニティーゲームズ アナウンス

近いうちに、XNAで作ったゲームをXBOX Liveで配布できるようになるようです。

XNAのリリース前から言われていた、「作ったゲームをXBOX Liveで配布」という構想が近いうちに現実になります。「XBOX Live コミュニティーゲームズ」と名づけられたこのサービスは、XNAクリエイターズクラブ会員が同サービスに作品をアップロードして他の会員にプレイ・評価してもらい、一定の評価に達した作品はXBOX Liveマーケットプレースで配布出来るそうです。今回発表のあったXBOX Live コミュニティーゲームズの特徴は、...
XNA情報:GDC2008 XBOX Live コミュニティーゲームズ アナウンス


今までXbox360版のゲームはCreators Club会員しか遊べなかったので、
閉鎖的もいいとこだったんですよね。
これでやっとXNA構想の完成が見えてきました。

 Xbox Live Community Gamesは,さらに門戸を広げたWeb 2.0的なサービスへの拡張が見られる。Create,Submit,Peer Review,Playの4段階で構成され,第1段階はクリエイター志望者がXNAでゲームを作ることから始まる。それを同サービスを利用して自主販売し,Xbox Liveのゲーマーズタグのように,開発者としての専用IDを取得することになるのが第2段階だ。第3段階では,「自分のゲーム」として出展したものに Peer,つまりほかの登録者達が,作品の採点やレビューを書き加える。第4段階のPlayというのは,その評価に応じて,より多くの人々にプレイしてもらえる環境ができあがるという仕組みである。多くの人に認められる作品を生み出し続ければ,それが登録者の履歴として残り,その才能を見出されてプロの道を歩むチャンスにめぐり合えるかもしれない,というのがMicrosoftの説明する“ゲーム業界の民主化”なのである。
[GDC2008#12]Microsoftの基調講演 ~ XNAで行う「ゲーム開発と流通の民主化」


面白いのは、登録から承認までMicrosoftが介入していないことですね。
Microsoftは場と道具を提供するだけで、作品自体の評価は行わない(著作権違反チェック等はすると思いますが)というのは、まさにWeb2.0的と言えます。
任天堂ではWiiWare、SCEにはゲームやろうぜ!がありますが、
アマチュア視点からすればXNAのこのシステムは最も的を得ている気がします。

アマチュアが作ったひどく個性的なゲームがひしめき合うカオスの中から、何か画期的なゲームが出たりして…なんて夢見ちゃいますね。

XNA Creators Club メンバーシップ、学生に無償提供!

キタ━━━(゚∀゚)━( ゚∀)━(  ゚)━(  )━(゚  )━(∀゚ )━(゚∀゚)━━━!!!!

学生にXNA Creators Club メンバーシップの無償提供が開始されますよ!

一応前から発表がありましたが、なんの音沙汰もなく不安だったんですよ。
無事実現されてよかった!

他にも、
  • Visual Studio 2005 Professional Edition
  • Visual Studio 2008 Professional Edition
  • Expression Studio
  • SQL Server 2005 Developer Edition
  • Windows Server Standard Edition
これらすべてを無償提供するってんだから太っ腹にもほどがあるぜMicrosoft!

といっても海外の話で、日本では6ヵ月以内に提供するとのこと。
楽しみに待ってます♪ありがとうMS!ありがとうゲイツ!

Matrix構造体

前回に引き続き3Dモデルの描画について。

XNAではMatrixという構造体があり、その静的関数でMatrixを生成することが出来ます。
1個ずつ見ていきましょう。

名前内容
CreateTranslation移動
CreateRotationXX軸を中心に回転
CreateRotationYY軸を中心に回転
CreateRotationZZ軸を中心に回転
CreateFromAxisAngle任意軸を中心に回転
CreateFromYawPitchRollX,Y,Z軸周りの回転を指定
CreateFromQuaternion4元数を使って回転(よくわからん)
CreateScale拡大縮小
CreateWorld位置、姿勢を指定
CreateBillboardビルボード(カメラに対し正面に向いたモデル)用に回転
CreateConstrainedBillboard1自由度を固定したビルボードを作成(マリオ64の木みたいな)
CreateLookAtビュー行列を作成
CreateOrthographic遠くのものも近くのものも同じ大きさの正射影行列を作成
CreateOrthographicOffCenter中心をずらした正射影行列を作成
CreatePerspective射影行列を作成
CreatePerspectiveFieldOfView画角を指定して射影行列を作成
CreatePerspectiveOffCenter中心をずらした射影行列を作成
CreateReflection反射用の回転行列を作る(自信なし)
CreateShadowキャストシャドウ用の行列を作る(自信なし)

・・・とまぁこんな感じです。
自信なしなのもありますが、前回書いたことが理解に役立ちました。

次回はいよいよプログラムを実装して実際に3Dモデルを表示してみます。

3DCGの基礎

今回からいよいよ3Dモデルの描画に挑戦します。

早速ファイルを読み込んで表示…といきたいところですが、
今回は自分の復習のために3Dモデルがどのようにして描画されるかを書きたいと思います。
というのも、3次元の描画は行列を多用するので、仕組みが分かってないとわけわからなくなる恐れがあるからです。

3Dモデルの描画とは?
3Dモデルというのは、要は点の集まりです。点どうしが線を描いたり面(ポリゴン)を作ったりして3次元物体を表現するのです。

では、3Dモデルを画面に出力するってのはどういうことか?
それは3次元の点P(X,Y,Z)を画面(2次元)の点Q(x,y)に変換することです。

ではどうやって変換すればよいのか?
その答えは簡単。私たちの目やカメラの、物理的な仕組みをシミュレートすればよいのです。

3つの変換
3次元の点Pを2次元の点Qに変換するには以下の3つの変換を行います。

P -> (モデルビュー変換) -> (射影変換) -> (ビューポート変換) -> Q

モデルビュー変換は、3D空間中のモデルの位置・姿勢を表します。カメラの位置・姿勢も兼ねています。
射影変換は、いわば視界の定義です。ズームイン、ズームアウトや、アスペクト比などを設定します。
ビューポート変換は射影変換で出来た画像を画面に印刷する作業です。画面全体に表示することが多いです。

モデルビュー変換
モデルビュー変換は点P(X,Y,Z)に4次元目の値1を加えたベクトル[X,Y,Z,1]と4×4の行列の積により行います。
基本的なものとして以下のような座標変換行列があります。
  • なにもしない行列
  • 移動
  • 拡大縮小
  • X軸回転・Y軸回転・Z軸回転
  • 任意軸周りの回転
具体的な行列の値は下記参考サイト様を見てください。
後で説明しますが、これら行列の中身は知っておくべきですが、常に書けるようになる必要はありません。

上記の変換の他に、例えば座標(1,0,0)にZ軸周り90度で回転したいときは、
回転行列と移動行列の積を行えばOKです。

ところで、行列の合成は拡大縮小→回転→移動の順に行わないと、正しい位置に移動できないので注意が必要です。回転はモデル中心ではなく原点中心で行われるからです。

ところで、ここまでモデルの座標変換だけでカメラについては出てきませんでしたが、
カメラはモデルと相対関係(モデルが動くのとカメラが逆に動くのが同じ)にあるので、モデルビュー行列はそれらを一括で表現できるわけです。

といってもそれでは分かりづらいのでDirectXやXNAでは
  • ワールド行列(モデルの配置)
  • ビュー行列(カメラの配置)
の2つに分けて設定できるようになっています。

ついでに言っときますが、この行列は原点の移動も兼ねています。オブジェクトaから見たオブジェクトbの位置姿勢が行列Bで表されるとき、原点から見たオブジェクトbの位置姿勢(ワールド行列B’)はオブジェクトaのワールド行列Aを用いて、
B’=BA
で表すことができます。
これを使えば関節の動きなども表現できますね。
※DirectXはOpenGLとはかける順序が逆になるはずです。ご注意を。

射影変換
射影変換で設定する項目は以下のとおりです。
  • 画角
  • アスペクト比
  • Nearプレーン、Farプレーン
画角はズームイン、ズームアウトを行うものです。画角が狭いとズームイン、画角が広いとズームアウトです。アスペクト比は、画面の縦横比です。描画する領域にあわせるとよいでしょう。NearプレーンとFarプレーンは手前と奥がどこまで見えるかを決めるものです。

ビューポート変換
ビューポート変換は印刷作業です。これまでの変換で出来た映像を画面に印刷します。
左右半分ずつの対戦画面は、ビューポート変換時に印刷対象として画面の半分を指定して出力しています。
このとき印刷する画面のアスペクト比が射影変換と同じでないと縦や横に伸びた映像になってしまうので注意が必要です。
ビューポート変換は他の2つの変換と違い、行列ではなくViewport構造体でパラメータを指定します。

XNAでの行列生成
モデルビュー変換、射影変換は行列を用いて行うものですが、いちいち自分で行列の値を1つずつ指定する必要はありません。
XNAには少ないパラメータで目的の行列を生成してくれるありがたい関数があるのです。
次回はXNAの行列生成関数について調べます。


※本記事を書くにあたりこちらこちらを参考にさせていただきました。

スプライトを貼ってみる

今回はスプライト貼ってみます。あとそれをコントローラで動かせるようにします。

ここで役に立ったのがひにけにXNAさんの

SpriteBatchクラス その2
SpriteBatch.Beginメソッドにはブレンドモード、ソートモード、そしてステートモードの3つ引数を渡すメソッド以外に、引数を省略できる2つのオーバーライドがあります。引数を省略した場合、ブレンドモードはSpriteBlendMode.AlphaBlend、ソートモードはSpriteSortMode.Deferred、そしてステートモードはSaveStateMode.Noneとなります。

ここで重要なのはステートモードがSaveStateMode.Noneということで、SpriteBatch.Begin()、またはSpriteBatch.Begin(SpriteBlendMode blendMode)を呼んだ場合は、レンダーステートが変更されてしまうということです。変更されるレンダーステートは指定するSpriteBlendModeによって変わりますが、共通して以下のレンダーステートを変更します。


スプライトのみの描画を行う場合はいいですが、3Dオブジェクトも描画する場合はレンダーステートに気をつけなければなりません。

んまぁこれぐらいで、案外すんなりできました。
今までのDirectXを使ったプログラミングではここまでくるのにも結構苦労しましたが、
さすがXNA、すぐにできますね。
C#も使いやすく、アマチュアのゲーム作りには打ってつけじゃないでしょうか。
(製作物を使う側の制約はおいといて


できたのはこんなかんじ。
miku

出演はOtomaniaさんより、はちゅねミクでした。

デバッグ用GameComponent

階層化GameComponentを作り始めるとソースが肥大化して分かりにくくなると思うので、しばらく放置しておきます。

その間はGame.Componentsプロパティを使用します。…あれ?こうやって使うのか?
とりあえず単純なゲームなら階層化は必要ないでしょう。


さて、今回はデバッグ用コンポーネントを作ります。
何を作るにしても、FPS等のデバッグ情報は表示しておきたいですからね。

まず画面に文字を表示するために一苦労あります。
SpriteFontというXMLファイルを作り、それをフォントとして読み込む必要があるのです。
フォントが読み込めたら、SpriteBatch.DrawString()関数で任意の場所に文字が書けます。

SpriteFontの仕様や文字の書き方については、XNA Game Studioメモさんの記事を参考にさせてもらいました。

次はFPSの計測です。
えーこれについては箱○で始めた(備忘録)さんのソースコードを丸パクリさせてもらいました。
パクってばかりですねすいませんorz
箱○で始めたさんありがとうございます。

てなわけで完成したソースコード公開です。自己責任でご自由にお使いください。

public class DebugMessage : DrawableGameComponent
{
private double _fps;
private double _updateInterval = 1.0;
private double _timeSinceLastUpdate = 0.0;
private double _framecount = 0.0;
private double _elapsed;
private SpriteFont _font;
private SpriteBatch _spriteBatch;
private Vector2 _position = Vector2.Zero;

public DebugMessage(Game game, SpriteBatch spriteBatch)
: base(game)
{
// TODO: Construct any child components here
_spriteBatch = spriteBatch;
}

public override void Initialize()
{
// TODO: Add your initialization code here

base.Initialize();
}

protected override void LoadContent()
{
base.LoadContent();

_font = this.Game.Content.Load("DebugFont");
}

public override void Draw(GameTime gameTime)
{
_elapsed = gameTime.ElapsedRealTime.TotalSeconds;
_framecount++;
_timeSinceLastUpdate += _elapsed;
if (_timeSinceLastUpdate > _updateInterval)
{
_fps = _framecount / _timeSinceLastUpdate;
_timeSinceLastUpdate -= _updateInterval;
_framecount = 0;

// FPSをコンソールに出力
System.Diagnostics.Debug.WriteLine("FPS: " + _fps.ToString("00.000") + " RT: " + gameTime.ElapsedRealTime.TotalSeconds);
}

base.Draw(gameTime);

// FPSを画面に出力

_spriteBatch.DrawString(_font, "FPS: " + _fps.ToString("00.000"), _position, Color.Black);
}
}


ちなみに実行するとこんな感じ。(クリックで拡大)
debug

Game.Componentsプロパティ SpaceWarの場合

とりあえずサンプルのSpaceWarのソースを見てみると、Game.Componentsプロパティは一切使ってないご様子。

SpaceWarでは、自前で階層化したオブジェクト管理クラスSceneItemを用いて更新と描画を行っていました。そのクラスが継承していたのがGameComponentsCollectionでもGameComponentでもなく、Listだったのが不思議。
更新と描画をするなら何でもGameComponentにすればいいわけではないのか。

そういえばXNAGSEのGameComponentってもともとWindowsのコントロールみたいにドラッグ&ドロップで手軽にゲームが作成できるようにっていう概念がありましたよね。あれって今なくなってるのかな?
Game.Componentsプロパティってその名残で、とりあえず初めて作る人はここに追加すれば動きますよ的なものなのかも。

とりあえずSpaceWarにならって自分で階層化可能なオブジェクト管理クラスを作ることにします。
Game.ComponentsプロパティはFPSの表示などデバッグ的な部分のみに留めましょう。

Game.Componentsプロパティの使いどころ

うーむ。どうしたものか。

GameクラスにはComponentsっていうプロパティがあります。
これはGameComponentCollectionというクラスです。

これにGameComponentを追加すると、自動的にUpdate、Drawメソッドを呼び出してくれる便利なものなのですが、問題点がひとつ。

例えば2Dでスプライトを描いた後に、3Dオブジェクトを描画したい場合、またはその逆をしたい場合、Componentsプロパティ君に任せてたら順番の制御ができないんですよね。
なのでいくつかのGameComponentCollectionを使いたいな、と。

また、画面の遷移などを行うときも複数のGameComponentCollectionが扱えるとうれしい。

問題なのはGameクラスに1つだけGameComponentCollectionが備えられてることで、
派生クラスでGameComponentCollectionを持つにしてもこの備え付けのやつを
どう生かしたらいいのか…使わないなら使わないでスッキリしないんですよね。

ひにけにXNAさんの記事によると、XNA2.0の新機能について
ゲームを作るときに、タイトル画面、メニュー画面、ゲーム画面といった数種類の画面を行き来する必要があるのですが、この時にそれぞれの画面を GameComponentとして使い、その中で更に複数のGameComponentを扱うようにすると各画面の管理が簡単になります。現バージョンではGameComponentCollectionが、このシナリオを想定していない作りになっているので実現するのが難しかったという問題を解決します。
とあるのですが、GameComponentにそんな機能見当たらず。うーむ。

MSの人はどういう思想でこのような設計にしたのか聞いてみたいところです。
なんかいい答えがあるような気がするんですけどね~。

現在のところ、

  • Componentsプロパティは一切使わない

  • Componentsプロパティは常に動くシステムのみに使用する

  • Componentsプロパティに追加する順番を制御することで順序を制御する←これは面倒くさいw

ぐらいしか思いつきません。

まぁサンプルでも見ながら考えてみます。

XNA準備編

XNAで何か面白いものを作ろうと思い立ち、自分の備忘録や他の人に役に立つことを期待してブログに開発状況を書いていくことにしました。
XNAの仕様やゲームの作り方について解説するのではなく、あくまで試行錯誤の過程を記録するだけです。未熟者ですから間違った情報も書いてしまうと思うのでご注意を。あと更新は遅いです。

XNAの他にも、VRやMRにも興味があるのでその当たりも書いていけたらいいなと思っています。

さて、初っ端は準備編です。
準備といってもVisual StudioとかXNAGSとかの導入編は公式ページひにけにXNAさんのページを見ていただくとして、今回は3Dモデラの導入について触れておきます。

XNAはもちろん3Dモデルの描画をサポートしています。しかしそれを作るにはどうしたらよいでしょうか。

3Dモデラは市販でもいろいろ種類がありますが、趣味で作るのにお金はかけたくない…。
ってことでボクはSoftimage XSI ModToolを選びました。
こちらは無料の3Dモデラで、なんとXNAのサポートまでしてくれているのです。

出力するファイル形式ですが、Xファイル、FBXファイル等をModToolは出力してくれます。
さらにXSI形式というのも出力できるのですが、これをXNAで読み込むためのインポータもついていました。
最初はFBXファイルで3Dモデルを扱うことにします。


とりあえず作ってみたもの。
orize
かもすぞー

Home

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。