スクリーンスペースからワールドスペース


10

私のゲームの世界では、x軸が左から右、y軸が上から下、z軸が画面の外に出ている2Dゲームを作成しています。

ここに画像の説明を入力してください

私のゲームの世界はトップダウンですが、ゲームは少し傾いてレンダリングされます。

ここに画像の説明を入力してください

私は、ワールドスペースからスクリーンスペースへ、またはその逆への投影に取り組んでいます。前者は次のように動作しています:

var viewport = new Viewport(0, 0, this.ScreenWidth, this.ScreenHeight);
var screenPoint = viewport.Project(worldPoint.NegateY(), this.ProjectionMatrix, this.ViewMatrix, this.WorldMatrix);

NegateY()XNAのため、拡張メソッドは、それがのように聞こえるまさに行い、Y軸は、トップの代わりに、上から下へ下へと走ります。上のスクリーンショットは、これがすべて機能していることを示しています。基本的に、私は3D空間に多数のポイントを持ち、それを画面空間にレンダリングします。カメラのプロパティをリアルタイムで変更して、新しい位置にアニメーション表示することができます。明らかに、私の実際のゲームはポイントではなくスプライトを使用し、カメラの位置は固定されますが、それに到達する前に、すべての計算を適切に実行しようとしています。

今、私は逆に変換しようとしています。つまり、上の画面空間のxyの点を指定して、ワールド空間の対応する点を決定します。たとえば、緑色の台形の左下にカーソルを合わせると、ワールドスペースの読み取り値は(0、480)になります。Z座標は無関係です。または、むしろ、ワールド空間にマッピングし直すとき、z座標は常にゼロになります。基本的に、私はこのメソッドシグネチャを実装したいと思います。

public Vector2 ScreenPointToWorld(Vector2 point)

私はこれを機能させるためにいくつかのことを試みましたが、運が悪いだけです。私の最新の考えでは、Viewport.Unproject異なるz値とfar z値を使用して2回呼び出し、結果を計算Rayし、それを正規化してから、基本的に私の世界の地上レベルを表すRayとの交差を計算する必要がありPlaneます。しかし、私は最後のステップで立ち往生し、私が物事を過度に複雑にしているのかどうか確信が持てませんでした。

これを達成する方法について誰かが正しい方向に私を向けることができますか?

回答:


4

あなたのアイディアはかなり的確だと思います!まず、ニアプレーンとファープレーンの両方を2D座標のZ値として使用して、カーソルの光線を計算します(Z座標には0と1を使用します)。これを処理するヘルパーメソッドを次に示します。

public Ray GetScreenRay(Vector2 screenPosition, Viewport viewport, Matrix projectionMatrix, Matrix viewMatrix, Matrix worldMatrix)
{
    Vector3 nearPoint = viewport.Unproject(new Vector3(screenPosition, 0f), projectionMatrix, viewMatrix, worldMatrix);
    Vector3 farPoint = viewport.Unproject(new Vector3(screenPosition, 1f), projectionMatrix, viewMatrix, worldMatrix);
    return new Ray(nearPoint, Vector3.Normalize(farPoint - nearPoint));
}

次にPlane、地面に一致するインスタンスが必要です。これを計算する最も簡単な方法は、平面上の3つの点を取り、地上オブジェクトから3つの頂点を渡すコンストラクターを使用することです。地面を計算する方法の例:

Plane groundPlane = new Plane(ground.Vertices[0], ground.Vertices[1], ground.Vertices[2]);

そして最後に、この方法を使用して光線と平面の間の交点を見つけます。以下の例のように交差座標を計算するために出力結果パラメーターを使用できます。

float? result;
mouseRay.Intersects(ref groundPlane, out result);
if(result != null)
    Vector3 worldPoint = mouseRay.Position + mouseRay.Direction * result.Value;

あなたNegateYもメソッドについて何かをしなければならないかもしれませんが、私はどこにあるかわかりません。


これは非常に役に立ちます。ありがとうございました。それは私が行方不明だった最後の行でした。フロートをどうしたらいいのかわからなかった!私は私のゲームクレジットにあなたの名前を入れなければならないだろうと思います:)
12

@ user13414実際、ドキュメントはそのメソッドについては少々不足しており、交差点を取得するために距離を使用する方法の例を示していません。
David Gouveia
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.