オノデラの研究日記 in わんくま

思いついたネタを気ままに書いていくブログ

ホーム 連絡をする 同期する ( RSS 2.0 ) Login
投稿数  209  : 記事  5  : コメント  5982  : トラックバック  40

ニュース

プロフィール

  • ●おのでら
    宮城県在住
    主に業務向けソフトを製作

Twitter

ニュース

主なリンク

XNA 関連リンク

アイテム

ゲーマーカード

その他

記事カテゴリ

書庫

日記カテゴリ

2008年8月8日 #

 今回のサンプルではマウスカーソルの位置にあるモデルを選択できるようにしています。カーソルをモデルに合わせると、Hit テキストが True に変化します。

スクリーン上の位置からモデルを選択

スクリーン座標から3次元空間座標へ変換

 マウスなどで3次元空間上のモデルなどを選択したい場合があると思います。この場合は、スクリーン上の2次元座標点からモデルの存在する3次元座標に変換してあたり判定などを行う必要があります。

 しかし、2次元から3次元に要素を拡張するため、X,Y のみの2次元のスクリーン座標から、3次元座標の点を求めることはできません。たとえば、実際に画面をクリックするイメージを考えてもらうとわかるかと思いますが、クリックしたときの3次元空間の位置が、オブジェクトよりも手前の位置なのかオブジェクト自体なのか、はたまたオブジェクトの奥なのかを判定することはできません。

オブジェクトの選択対象の判断

 そのため、クリックした位置は点で表すのではなく、カメラの位置からクリックした方向に伸ばしたとして扱います。その線とオブジェクトとの衝突判定を行うことによってモデルの選択などができるようになります。ちなみに線のパラメータは XNA では Ray という構造体で扱うことができます。

スクリーンの位置から3次元空間の位置を取得

 XNA にはスクリーンでクリックした方向へ向かうような線を求めるようなメソッドなどはありません。しかし、スクリーン座標と奥行きを指定することで3次元空間の点を求めることができるので、カメラの位置と特定の深度で変換した3次元空間座標点を結ぶことによって線を求めることができます。

 スクリーン空間座標からオブジェクト空間座標を求めるには「Viewport.Unproject」メソッドを使用することで簡単に求めることができます。

// ビューポートを取得
Viewport viewport = this.GraphicsDevice.Viewport;

// スクリーンの位置を Vector3 で作成 (Z は 1.0 以下を設定)
Vector3 screenPosition = new Vector3(this.markPosition, 1.0f);

// スクリーン座標を3次元座標に変換
Vector3 worldPoint = viewport.Unproject(screenPosition,
                                        this.projection,
                                        this.view,
                                        Matrix.Identity);

 第1引数にはスクリーン座標に深度を含めた Vector3 を渡します。X, Y にはスクリーンの座標を設定し、Z に深度の値を設定します。深度はプロジェクションマトリックスの「nearPlaneDistance」と「farPlaneDistance」のパラメータに依存し、0.0f を指定するとカメラの位置から nearPlaneDistance の距離、1.0f を指定するとカメラの位置から farPlaneDistance の距離を求めることができます。

 第2引数にはプロジェクションマトリックス、第3引数にはビューマトリックスを指定します。

 戻り値としてオブジェクト空間ベクトルを求めることができます。

レイの作成

 線のパラメータには Ray 構造体が使用できます。コンストラクタの第1引数にレイの開始点を指定し、第2引数にレイの向きを指定します。

 開始点にカメラの位置を設定し、向きに変換済みの3次元空間座標からカメラの位置を引いて向きを算出します。向きは Vector3.Normalize メソッドで単位ベクトルにしています。

// マークが指す方向へのレイを作成
Ray ray = new Ray(this.cameraPosition,
                    Vector3.Normalize(worldPoint - this.cameraPosition));

球とレイの当たり判定

 コンテンツパイプラインから読み込んだ ModelMesh クラスには BoundingSphere プロパティというメッシュを包括した球データが含まれています。このクラスの Intersects メソッドに先ほど作成した Ray を指定することによって球とレイが衝突しているかを調べることができます。

 衝突する場合はレイの開始点と衝突ポイントの距離が返ります。衝突しない場合は null が返るので、サンプルでは null 判定で衝突しているか調べています。

 ただし、このメソッドを使用する場合はモデルが原点に配置されていることが前提です。もし、モデルを移動させている場合は、レイをモデルの移動に合わせて座標変換する必要があります。

 ちなみに今回のサンプルモデルは球なので、正確なあたり判定ができると思います。

// 球とレイとの当たり判定を行う
this.isHit = false;
foreach (ModelMesh mesh in this.model.Meshes)
{
    if (mesh.BoundingSphere.Intersects(ray) != null)
    {
        // 球とレイは交差している
        this.isHit = true;
        break;
    }
}

サンプルプロジェクト

静的サイト

  • 後でまとめますw
posted @ 1:12 | Feedback (9)