Vyberte model z jeho polohy na obrazovke

Stránka aktualizovaná :
Dátum vytvorenia strany :

súhrn

Umožňuje vám vybrať model na pozícii kurzora myši. Keď umiestnite kurzor myši na model, text prístupu sa zmení na hodnotu True.

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

Prevádzkové prostredie

Predpoklady

Podporované verzie XNA
  • 4.0
Podporované platformy
  • Windows (XP SP2 alebo novší, Vista, 7)
  • Konzola Xbox 360
  • Windows Phone 7
Windows vyžaduje verziu tieňovača vrcholov 2.0
Windows vyžaduje verziu Pixel Shader 2.0

Prevádzkové prostredie

nástupište
  • Windows 7
  • Konzola Xbox 360
  • Emulátor Windows Phone 7

Ako pracovať so vzorkou

Funguje klávesnicaOvládač Xbox 360myš dotyková
Pohyb kurzora ↑↓←→ Ľavá páčka Pohyb myši -

látka

Prevod súradníc obrazovky na 3D priestorové súradnice

Možno budete chcieť vybrať model v 3D priestore pomocou myši. V tomto prípade je potrebné previesť dvojrozmerný súradnicový bod na obrazovke na trojrozmernú súradnicu, kde model existuje, a vykonať posúdenie zásahu.

Aby sa však prvok rozšíril z 2D na 3D, nie je možné nájsť bod s 3D súradnicami z 2D súradníc obrazovky iba X a Y. Ak si napríklad predstavíte, že skutočne kliknete na obrazovku, pochopíte, že nie je možné určiť, či je poloha v 3D priestore po kliknutí pred objektom, samotným objektom alebo za objektom.

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

Preto namiesto toho, aby sa kliknutá poloha znázorňovala ako bodka, považuje sa za čiaru natiahnutú od polohy kamery v smere kliknutia. Vykonaním detekcie kolízií medzi čiarou a objektom je možné vybrať model. Mimochodom, parametre čiary môžu byť v XNA spracované štruktúrou s názvom Ray.

Získanie polohy v 3D priestore z pozície obrazovky

XNA nemá spôsob, ako nájsť čiaru v smere kliknutia na obrazovku. Keďže je však možné nájsť bod v 3D priestore zadaním súradníc a hĺbky obrazovky, je možné nájsť čiaru spojením polohy kamery a súradnicového bodu 3D priestoru transformovaného v konkrétnej hĺbke.

Nájdenie súradníc priestoru objektu zo súradníc priestoru obrazovky sa dá ľahko vykonať pomocou metódy "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);

Prvým argumentom je Vector3 so súradnicami a hĺbkou obrazovky. Nastavte X, Y na súradnice obrazovky a Z na hodnotu hĺbky. Hĺbka závisí od parametrov "nearPlaneDistance" a "farPlaneDistance" projekčnej matice, kde môžete zadať 0,0f na zistenie vzdialenosti od polohy kamery k nearPlaneDistance a 1,0f na určenie vzdialenosti od pozície kamery k farPlaneDistance.

Druhým argumentom je matica projekcie a tretím argumentom je matica zobrazenia.

Ako vrátenú hodnotu môžete nájsť vektor objektového priestoru.

Viewport.Unproject metóda

Premietne vektor z priestoru obrazovky do priestoru objektu.

zdroj Vektor3 Vektor súradníc obrazovky na konverziu na súradnice objektového priestoru
výčnelok Matica Projektívna matica
pohľad Matica Zobraziť maticu
svet Matica Určuje konečnú transformáciu súradníc svetovej matice, ktorá sa má vykonať
Vrátené hodnoty Vektor3 Získanie vektora v priestore objektov

Vytvorenie lúča

Parametre čiary môžu byť Ray štruktúry. Prvým argumentom konštruktora je východiskový bod lúča a druhým argumentom je orientácia lúča.

Nastavte polohu kamery ako východiskový bod a vypočítajte orientáciu odpočítaním polohy kamery od súradníc 3D priestoru, ktoré už boli prevedené na orientáciu. Orientácia sa nastaví na jednotkový vektor pomocou metódy Vector3.Normalize.

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

Ray staviteľ

Vytvorte inštanciu štruktúry "Ray", ktorá obsahuje parametre čiary.

pozícia Vektor3 Východiskový bod lúča
smer Vektor3 Smer lúča

Hitbox lopty a lúča

Trieda ModelMesh načítaná z kanála obsahu obsahuje údaje gule, ktoré zahŕňajú povrchovú sieť, nazývanú vlastnosť BoundingSphere. Zadaním lúča, ktorý ste práve vytvorili v metóde Intersects tejto triedy, môžete skontrolovať, či sa guľa a lúč zrážajú.

V prípade kolízie sa vráti vzdialenosť medzi začiatkom lúča a bodom zrážky. Ak nedôjde ku kolízii, vráti sa hodnota null, takže vzorka skontroluje, či nedošlo ku kolízii nulovým úsudkom.

Táto metóda však predpokladá, že model sa nachádza v počiatku. Ak model presúvate, budete musieť transformovať lúče pri pohybe modelu.

Mimochodom, tento vzorový model je guľa, takže si myslím, že sa dá presne určiť.

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

BoundingSphere.Intersects metóda

Vykonáva sa detekcia kolízie medzi inkluzívnou guľou a lúčom.

lúč Lúč Ray posúdil kolíziu s loptou
Vrátené hodnoty Nullable<float> V prípade zrážky vráti vzdialenosť medzi počiatočným bodom lúča a bodom dopadu na guľu. Ak nedôjde ku kolízii, vráti sa hodnota null.

Všetky kódy

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
#if WINDOWS_PHONE
using Microsoft.Xna.Framework.Input.Touch;
#endif

namespace ModelSelectByScreenPosition
{
    /// <summary>
    /// ゲームメインクラス
    /// </summary>
    public class GameMain : Microsoft.Xna.Framework.Game
    {
        /// <summary>
        /// グラフィックデバイス管理クラス
        /// </summary>
        private GraphicsDeviceManager graphics = null;

        /// <summary>
        /// スプライトのバッチ化クラス
        /// </summary>
        private SpriteBatch spriteBatch = null;

        /// <summary>
        /// スプライトでテキストを描画するためのフォント
        /// </summary>
        private SpriteFont font = null;

        /// <summary>
        /// モデル
        /// </summary>
        private Model model = null;

        /// <summary>
        /// マーク
        /// </summary>
        private Texture2D mark = null;

        /// <summary>
        /// マーク画像の中心位置
        /// </summary>
        private Vector2 markCenterPosition = Vector2.Zero;

        /// <summary>
        /// マークの位置
        /// </summary>
        private Vector2 markPosition = new Vector2(100.0f, 100.0f);

        /// <summary>
        /// モデルへの当たり判定フラグ
        /// </summary>
        private bool isHit = false;

        /// <summary>
        /// カメラの位置
        /// </summary>
        private Vector3 cameraPosition = new Vector3(0.0f, 0.0f, 10.0f);

        /// <summary>
        /// ビューマトリックス
        /// </summary>
        private Matrix view;

        /// <summary>
        /// プロジェクションマトリックス
        /// </summary>
        private Matrix projection;


        /// <summary>
        /// GameMain コンストラクタ
        /// </summary>
        public GameMain()
        {
            // グラフィックデバイス管理クラスの作成
            this.graphics = new GraphicsDeviceManager(this);

            // ゲームコンテンツのルートディレクトリを設定
            this.Content.RootDirectory = "Content";

#if WINDOWS_PHONE
            // Windows Phone のデフォルトのフレームレートは 30 FPS
            this.TargetElapsedTime = TimeSpan.FromTicks(333333);

            // バックバッファサイズの設定
            this.graphics.PreferredBackBufferWidth = 480;
            this.graphics.PreferredBackBufferHeight = 800;

            // フルスクリーン表示
            this.graphics.IsFullScreen = true;
#endif
        }

        /// <summary>
        /// ゲームが始まる前の初期化処理を行うメソッド
        /// グラフィック以外のデータの読み込み、コンポーネントの初期化を行う
        /// </summary>
        protected override void Initialize()
        {
            // ビューマトリックス
            this.view = Matrix.CreateLookAt(
                        this.cameraPosition,
                        Vector3.Zero,
                        Vector3.Up
                    );

            // プロジェクションマトリックス
            this.projection = Matrix.CreatePerspectiveFieldOfView(
                        MathHelper.ToRadians(45.0f),
                        (float)this.GraphicsDevice.Viewport.Width /
                            (float)this.GraphicsDevice.Viewport.Height,
                        1.0f,
                        100.0f
                    );

            // コンポーネントの初期化などを行います
            base.Initialize();
        }

        /// <summary>
        /// ゲームが始まるときに一回だけ呼ばれ
        /// すべてのゲームコンテンツを読み込みます
        /// </summary>
        protected override void LoadContent()
        {
            // テクスチャーを描画するためのスプライトバッチクラスを作成します
            this.spriteBatch = new SpriteBatch(this.GraphicsDevice);

            // フォントをコンテンツパイプラインから読み込む
            this.font = this.Content.Load<SpriteFont>("Font");

            // モデルを作成
            this.model = this.Content.Load<Model>("Model");

            // ライトとビュー、プロジェクションはあらかじめ設定しておく
            foreach (ModelMesh mesh in this.model.Meshes)
            {
                foreach (BasicEffect effect in mesh.Effects)
                {
                    // デフォルトのライト適用
                    effect.EnableDefaultLighting();

                    // ビューマトリックスをあらかじめ設定
                    effect.View = this.view;

                    // プロジェクションマトリックスをあらかじめ設定
                    effect.Projection = this.projection;
                }
            }

            // マーク作成
            this.mark = this.Content.Load<Texture2D>("Mark");

            // マークの中心位置
            this.markCenterPosition = new Vector2(this.mark.Width / 2, this.mark.Height / 2);
        }

        /// <summary>
        /// ゲームが終了するときに一回だけ呼ばれ
        /// すべてのゲームコンテンツをアンロードします
        /// </summary>
        protected override void UnloadContent()
        {
            // TODO: ContentManager で管理されていないコンテンツを
            //       ここでアンロードしてください
        }

        /// <summary>
        /// 描画以外のデータ更新等の処理を行うメソッド
        /// 主に入力処理、衝突判定などの物理計算、オーディオの再生など
        /// </summary>
        /// <param name="gameTime">このメソッドが呼ばれたときのゲーム時間</param>
        protected override void Update(GameTime gameTime)
        {
            // キーボードの情報取得
            KeyboardState keyboardState = Keyboard.GetState();

            // ゲームパッドの情報取得
            GamePadState gamePadState = GamePad.GetState(PlayerIndex.One);

            // Xbox 360 コントローラ、Windows Phone の BACK ボタンを押したときに
            // ゲームを終了させます
            if (gamePadState.Buttons.Back == ButtonState.Pressed)
            {
                this.Exit();
            }

            // 移動スピード
            float speed = 200.0f;

            // キーボードによるマークの移動
            if (keyboardState.IsKeyDown(Keys.Left))
            {
                this.markPosition.X -= speed * (float)gameTime.ElapsedGameTime.TotalSeconds;
            }
            if (keyboardState.IsKeyDown(Keys.Right))
            {
                this.markPosition.X += speed * (float)gameTime.ElapsedGameTime.TotalSeconds;
            }
            if (keyboardState.IsKeyDown(Keys.Up))
            {
                this.markPosition.Y -= speed * (float)gameTime.ElapsedGameTime.TotalSeconds;
            }
            if (keyboardState.IsKeyDown(Keys.Down))
            {
                this.markPosition.Y += speed * (float)gameTime.ElapsedGameTime.TotalSeconds;
            }

            // ゲームパッドによるマークの移動
            if (gamePadState.IsConnected)
            {
                this.markPosition.X += gamePadState.ThumbSticks.Left.X * speed *
                                       (float)gameTime.ElapsedGameTime.TotalSeconds;
                this.markPosition.Y -= gamePadState.ThumbSticks.Left.Y * speed *
                                       (float)gameTime.ElapsedGameTime.TotalSeconds;
            }

            // マウス処理
            MouseState mouseState = Mouse.GetState();

            if (mouseState.X >= 0 && mouseState.X < this.Window.ClientBounds.Width &&
                mouseState.Y >= 0 && mouseState.Y < this.Window.ClientBounds.Height &&
                mouseState.LeftButton == ButtonState.Pressed)
            {
                // マウスがウインドウ内にあればマウスの位置を優先する
                this.markPosition = new Vector2(mouseState.X, mouseState.Y);
            }

            // ビューポートを取得
            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);

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

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

            // 登録された GameComponent を更新する
            base.Update(gameTime);
        }

        /// <summary>
        /// 描画処理を行うメソッド
        /// </summary>
        /// <param name="gameTime">このメソッドが呼ばれたときのゲーム時間</param>
        protected override void Draw(GameTime gameTime)
        {
            // 画面を指定した色でクリアします
            this.GraphicsDevice.Clear(Color.CornflowerBlue);

            // Zバッファを有効にする
            this.GraphicsDevice.DepthStencilState = DepthStencilState.Default;

            // モデルを描画
            foreach (ModelMesh mesh in this.model.Meshes)
            {
                mesh.Draw();
            }

            // スプライトの描画準備
            this.spriteBatch.Begin();

            // マーク描画
            this.spriteBatch.Draw(this.mark, this.markPosition,
                null, Color.White, 0.0f,
                this.markCenterPosition, 1.0f, SpriteEffects.None, 0.0f);

            // テキスト描画
            this.spriteBatch.DrawString(this.font,
                "Cursor Key Press or" + Environment.NewLine +
                "   MouseLeftButton Drag" + Environment.NewLine +
                "Hit : " + this.isHit,
                new Vector2(50.0f, 50.0f), Color.White);

            // スプライトの一括描画
            this.spriteBatch.End();

            // 登録された DrawableGameComponent を描画する
            base.Draw(gameTime);
        }
    }
}