ゲームエディター-画面がクリックされたときに、クリックされたオブジェクトをどのように特定しますか?


7

ゲームエディターを作成しようとしています。現在は、さまざまなタイプのシェイプなどを配置しています。XNAで3Dを描画しながら、Windowsフォームでこれを行っています。したがって、画面にいくつかの図形があり、画面をクリックした場合、クリックしたこれらのオブジェクトの「どれ」を識別できるようにしたいと考えています。

これに最適な方法は何ですか?後ろに2つのオブジェクトがあるため、後ろのオブジェクトではなく前の1つのオブジェクトを認識できるはずです。また、カメラを回転させて後ろの1つをクリックすると、最初のオブジェクトではなく、それを識別できるはずです。

これについて賢明な方法はありますか?


6
クリックされたオブジェクトを特定するプロセスは、通常「ピッキング」と呼ばれます。「xna picking」のようなものを検索するいくつかのグーグルはあなたにいくつかの有用な結果を与えるはずです。
Gyan別名Gary Buyn 2012年

回答:


2

このビデオでは、コードでそれを行う方法を示します...投影/ビューは等角投影ですが、すべての計算は3Dで行われます...

http://www.youtube.com/watch?v=axHp1f3RlHM

マウスレイを計算するときに、平面に対する衝突をチェックします...しかし、手順は、オブジェクトに関連付けられた境界球のリストに対してチェックするためのアナログです。

アルゴリズムは次のようになります。

1. Calculate mouse ray
2. for every object
3.     check if ray intersecs with it
4.         if does then save the object and the distance in a sorted list by distance
5. choose from sorted list the nearest object.

あなたの例は私が探しているもので、おそらく等尺性ではありませんでした。グリッドとキューブのアウトラインをどのようにレンダリングしますか?マウスが3Dスペースのどこにあるかをテストするには、そのようなものが必要です。
Deukalion 2012年

私は独自のクラスを使用して線を描画しています...この文を使用して簡単に実装できますGraphicsDevice.DrawUserPrimitives <VertexPositionColor>(PrimitiveType.LineList、data.Vertices、0、data.Index / 2);
ブラウ

はい、似たようなことを試しましたが、機能しません。私はこれに数学的な方法を使用しますが、方法の私の理解は私がそう思っているものではありません。これについての私の質問:gamedev.stackexchange.com/questions/31424/...
Deukalion

ここにそれを描画するコードがありますpastebin.com/YpCKAHcF は簡単です...垂直線と水平線のみを描画します
Blau

DrawLine3Dを呼び出しますが、そのコードはありません。それは単にDrawUserPrimitives(LineList、Data.Vertices、0、data.Index / 2)ですか?data.Index / 2は何ですか?
Deukalion 2012年

9

よく理解する必要がある最初のことは、3Dポイントを2Dスクリーン座標に変換し、再び戻すことです。ここでは、そのテーマについて私が出したいくつかの回答を示します。3Dから画面へ3Dから2D への理解

ここで、マウス座標から2Dから3Dに移動するには、3Dから2Dへの逆変換を行う必要があります。これはかなり簡単です。

オブジェクト/ローカル座標は、ワールドマトリックス(世界座標を取得)、ビューマトリックス(カメラを基準に世界座標を作成)、投影行列(スクリーン座標を取得)で乗算することにより、画面空間に変換されます。 。

これを逆に行うのは簡単です。すべての行列を反転します。次に、逆投影法を掛け、次に逆ビュー行列を掛けます。これで、マウスの3D座標がなくなります。その理由は、データのディメンションが欠落していたためです。だからあなたが持っているのは代わりに光線です。しかし、それは良いことです。光線には定義座標があり、カメラがベクトルを見ている方向と同じ方向を指します。また、オブジェクトのワールドマトリックスを反転する必要がないことに気付くかもしれません。これは、オブジェクト/ローカルスペースに光線を本当に必要としないからです。意味がありません。おそらく、コリジョンボリュームをワールドスペースでも定義します。

これで、光線がオブジェクトと交差するかどうかを確認するために、円/ボックス/ポリ光線の交差テストを行うだけです。

交差するすべてのオブジェクトを見つけ、リストを保持します。次に、各オブジェクトのカメラからの距離を計算します。カメラに最も近いものは、ユーザーが選択したいものです。

これは、XNAでこれを行うために必要なコードです。このソリューションは、他の種類のプロジェクトでも機能するはずです(最初に変換する限り)。2Dスプライトのみをレンダリングする場合は、おそらく射影行列を使用していないので、関数をMatrix.Identityに渡します。

using System;
using Microsoft.Xna.Framework;

namespace FluxPrototype
{
    /// <summary>
    /// Contains functions useful in working with XNA Vectors.
    /// </summary>
    static class VectorHelper
    {
        /// <summary>
        /// Converts a Vector2 position into a 3D ray.
        /// </summary>
        /// <param name="Position">The 2D position.</param>
        /// <param name="View">The view matrix for the camera.</param>
        /// <param name="Projection">The projection matrix for the camera.</param>
        /// <param name="Point">The returned point defining part of the 3D ray.</param>
        /// <param name="Direction">The direction of the 3D ray.</param>
        public static void Unproject(Vector2 Position, Matrix View, Matrix Projection, out Vector3 Point, out Vector3 Direction)
        {
            if (Position == null)
                Position = Vector2.Zero;

            // Create two 3D points from the position. The first one we will return.
            Point = new Vector3(Position, 0);
            Vector3 Point2 = new Vector3(Position, 1);

            // Transform the points.
            Matrix InvertedProjection = Matrix.Invert(Projection);
            Point = Vector3.Transform(Point, InvertedProjection);
            Point2 = Vector3.Transform(Point2, InvertedProjection);

            Matrix InvertedView = Matrix.Invert(View);
            Point = Vector3.Transform(Point, InvertedView);
            Point2 = Vector3.Transform(Point2, InvertedView);

            // Use the difference between the points to define the ray direction.
            // This will only be the camera direction if the view frustum is orthographic.
            Direction = (Point2 - Point);
            Direction.Normalize();
        }
    }
}

OK。調べてみます。行列を反転する方法を説明するのに気を付けていますか?どうすればいいのか分かりません。
Deukalion 2012年

1
Matrix InvertedView = Matrix.Invert(View);
OriginalDaemon

この方法は、エディターにコンテンツを配置するときに機能しますか?それらを選択するよりも「重要」であるためです。画面に立方体を追加したい場合は、クリックしたい場所をクリックします。この方法もそれをサポートしていますか?
Deukalion 2012年

これは私が行った限りであり、それが正しいかどうかはわかりません。Matrix m = screenPosition * matrix.Invert(Camera.MatrixWorld)* Matrix.Invert(Camera.MatrixView)* Matrix.Invert(Camera.MatrixWorld);
Deukalion

...そして私はこのようにして(私のCameraクラスに)Matricesを作成します:matrix_world = Matrix.CreateRotationZ(MathHelper.ToRadians(world_rotation.Z))* Matrix.CreateRotationY(MathHelper.ToRadians(world_rotation.Y))* Matrix.CreateRotationX (MathHelper.ToRadians(world_rotation.X))* Matrix.CreateTranslation(world_location)* Matrix.CreateScale(world_zoom); matrix_view = Matrix.CreateLookAt(view_position、view_lookat、Vector3.Up); matrix_projection = Matrix.CreatePerspectiveFieldOfView(projection_fieldofview、Projection_aspectratio、Projection_clipstart、Projection_clipend);
Deukalion 2012年

2

通常は、マウスからバウンディングボリュームを作成します。原点は私がクリックした場所です。次に、すべてのオブジェクトをループして交差テストを完了します。次に、取得したリストを必要な基準に基づいてソートし、要素0を選択します。


わかった。しかし、Z値をどのように使用すればよいですか?または、深度。画面をクリックするだけでX、Y座標が得られ、後でそれが3Dワールド内のクリックしたポイントに対応するため、深度の値は得られません。それはどれくらいカメラに「近い」のですか、それともどのくらい離れていますか?
Deukalion 2012年

1

私が検討したがまだ試していないアイデア:

実際の画像と同じであるがテクスチャなどはないオフスクリーン画像を描画します。単に、オブジェクトを描画します。各オブジェクトは異なる「色」で描画します。「色」は実際には単なるオブジェクト番号です。マウスの下に何があるかを理解するには、代替画像のピクセルの色を確認するだけです。

もちろん、これは多くの無駄な作業を行っていますが、CPUではなくGPUが行っているため、まったく同じルールで問題を解決できます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.