Memaparkan poligon segi tiga

Laman dikemaskini :
Tarikh penciptaan halaman :

Ringkasan

Ia memaparkan poligon segi tiga dalam ruang 3D.

3角形ポリゴンの表示

Persekitaran operasi

Prasyarat

Versi XNA yang Disokong
  • 4.0
Platform yang Disokong
  • Windows (XP SP2 atau lebih baru, Vista, 7)
  • Xbox 360
  • Telefon Windows 7
Versi Vertex Shader yang Diperlukan Windows 2.0
Windows Versi Pixel Shader Diperlukan 2.0

Persekitaran operasi

Platform
  • Tingkap 7
  • Xbox 360
  • Windows Phone 7 Emulator

Bahan

Apa itu poligon?

Poligon ialah muka yang dijana oleh berbilang takrifan bucu. Secara umum, poligon ialah muka segi tiga yang terdiri daripada tiga bucu. Dan trigon adalah unit terkecil poligon. Sesetengah perisian pemodelan mungkin memaparkan poligon sebagai segi empat atau poligon, tetapi ini akhirnya akan terurai kepada poligon segi tiga.

Model yang dipaparkan dalam permainan dibentuk dengan menggabungkan berbilang poligon segi tiga ini.

最小単位のポリゴン

Poligon dibentuk oleh bucu. Bucu boleh mempunyai data seperti kedudukan dan warna. Sampel ini juga dibuat daripada data "kedudukan" dan "warna".

ポリゴンと頂点

Warna muka dalam contoh ini diinterpolasi dengan kemas oleh warna dan jarak yang ditetapkan untuk setiap bucu, tetapi anda boleh mengubahnya dengan bebas dengan program shader anda sendiri (lebih lanjut mengenai program shader lain kali).

Definisi Data Vertex

Untuk memaparkan poligon, "data bucu" diperlukan, dan pengaturcara mesti memutuskan elemen apa yang hendak dimasukkan dalam bucu itu. Apabila melukis poligon, anda perlu memberitahu peranti, iaitu enjin lukisan, data bucu apa yang hendak melukis poligon. Untuk melakukan ini, buat kelas "VertexDeclaration" dan tetapkan "Definisi Data Vertex".

Walau bagaimanapun, bermula dengan XNA Game Studio 4.0, persediaan ini telah dipermudahkan dan anda tidak perlu menyediakan kelas VertexDeclaration untuk petua ini. (Ini kerana maklumat definisi sudah tertanam dalam data bucu yang disediakan oleh rangka kerja.)

Data bucu

Saya menulis bahawa data bucu diperlukan untuk melukis poligon, tetapi pertama-tama kita perlu memutuskan jenis data yang kita mahu miliki. Dalam kes ini, kami akan menggunakan data "kedudukan" dan "warna". Sebaik sahaja anda telah memutuskan data yang anda mahu miliki, anda perlu membuat struktur untuk menyimpan data tersebut. Anda mempunyai sedikit kebebasan untuk menentukan data bucu, tetapi data bucu yang biasa digunakan telah ditakrifkan dalam Rangka Kerja XNA, jadi sampel menggunakannya.

Data bucu dengan "kedudukan" dan "warna" ditakrifkan sebagai struktur "VertexPositionColor". Oleh kerana berbilang bucu diperlukan untuk membentuk poligon, kami mengisytiharkannya sebagai tatasusunan.

/// <summary>
/// 頂点データリスト
/// </summary>
private VertexPositionColor[] vertices = null;

Kesan

Dalam XNA, apabila anda melukis poligon, anda perlu menulis program shader yang berasingan untuk memutuskan cara melukisnya. Untuk melakukan ini, buat fail kesan yang berasingan, tulis program, muatkannya sebagai kelas kesan dan jalankan program shader.

Walau bagaimanapun, jika anda tidak perlu melukis poligon segi tiga ringkas seperti ini, atau kesan lukisan yang kompleks, ia boleh menjadi tugas yang sangat rumit.

Atas sebab ini, XNA mentakrifkan kesan lanjutan yang membolehkan anda menetapkan item yang diperlukan sebagai sifat supaya anda tidak perlu menulis program shader untuk lukisan asas. Itulah kelas "BasicEffect". Oleh kerana tujuan artikel ini adalah untuk melukis poligon, kami akan menggunakan "BasicEffect" yang tidak memerlukan banyak usaha untuk melukis.

/// <summary>
/// 基本エフェクト
/// </summary>
private BasicEffect basicEffect = null;

Saya akan bercakap lebih lanjut tentang kesan dan BasicEffects pada masa lain.

Dengan cara ini, Windows Phone 7 tidak membenarkan anda menggunakan kesan anda sendiri, hanya yang terbina dalam rangka kerja seperti BasicEffect.

Cipta takrifan data bucu

Sehingga Rangka Kerja XNA 3.1, anda perlu menciptanya secara secara pengaturcaraan secara eksplisit, tetapi bermula dengan 4.0, maklumat bucu terbina dalam rangka kerja sudah disertakan dalam maklumat bucu sebagai "IVertexType.VertexDeclaration", jadi kami akan menggunakannya.

Mencipta Kesan

Buat kelas BasicEffect. Tetapkan sifat BasicEffect.VertexColorEnabled kepada benar untuk mengekalkan warna bucu.

// エフェクトを作成
this.basicEffect = new BasicEffect(this.GraphicsDevice);

// エフェクトで頂点カラーを有効にする
this.basicEffect.VertexColorEnabled = true;

BasicEffect Constructor

Cipta contoh kelas kesan "BasicEffect" yang melakukan warna bucu, tekstur dan pencahayaan menggunakan Shader Model 2.0.

Peranti GrafikPeranti Menentukan GraphicsDevice untuk mencipta kesan

Lihat Matriks dan Matriks Unjuran

Tetapkan BasicEffect kepada matriks pandangan dan matriks unjuran. Untuk penjelasan konseptual setiap satu, lihat pautan di bawah.

// ビューマトリックスをあらかじめ設定 ((0, 0, 15) から原点を見る)
this.basicEffect.View = Matrix.CreateLookAt(
        new Vector3(0.0f, 0.0f, 15.0f),
        Vector3.Zero,
        Vector3.Up
    );

// プロジェクションマトリックスをあらかじめ設定
this.basicEffect.Projection = Matrix.CreatePerspectiveFieldOfView(
        MathHelper.ToRadians(45.0f),
        (float)this.GraphicsDevice.Viewport.Width /
            (float)this.GraphicsDevice.Viewport.Height,
        1.0f,
        100.0f
    );

Untuk menjana matriks paparan, gunakan kaedah "Matrix.CreateLookAt".

Hujah pertama menentukan kedudukan kamera, hujah kedua menentukan titik minat kamera, dan hujah ketiga menentukan arah ke atas kamera.

Dalam kes ini, ia ditetapkan untuk melihat asal dari kedudukan (0, 0, 15).

Matrix.CreateLookAt Kaedah

Cipta matriks paparan.

Kedudukan kamera Vektor3 Kedudukan Kamera
kameraSasaran Vektor3 Tempat Menarik Kamera
kameraUpVector Vektor3 Arah ke atas kamera

Untuk menjana matriks unjuran, gunakan kaedah "Matrix.CreatePerspectiveFieldOfView".

Hujah pertama ialah sudut tontonan dalam radian. Dalam sampel, unit darjah ditukar kepada radian menggunakan kaedah "MathHelper.ToRadians". Untuk maklumat lanjut tentang Radian dan Ijazah, lihat Radian dan Ijazah.

Hujah kedua menentukan nisbah aspek (nisbah aspek). Biasanya, anda menentukan nilai untuk Lebar Pandangan ÷ Tinggi. Dalam sampel, ia dikira daripada lebar dan ketinggian yang ditetapkan untuk port pandangan peranti.

Argumen ketiga menentukan kedudukan keratan ke hadapan, dan argumen keempat menentukan kedudukan keratan ke belakang.

Matrix.CreatePerspectiveFieldOfView Kaedah

Mencipta matriks unjuran perspektif berdasarkan tetapan medan paparan.

fieldOfView terapung Sudut pandangan. Dinyatakan dalam unit radian.
nisbah aspek terapung Nisbah aspek (nisbah aspek). Biasanya, anda menentukan nilai untuk "Lebar ÷ Tinggi Tondangan"
jarak dekat pesawat terapung Kedudukan klip hadapan. Objek di hadapan kedudukan ini tidak dilukis.
Jarak Pesawat Jauh terapung Kedudukan klip belakang. Objek di luar kedudukan ini tidak dilukis.

Mencipta Data Vertex

Buat tiga data bucu. Mula-mula, kita akan mencipta tatasusunan dan mencipta setiap bucu.

// 頂点データを作成する
this.vertices = new VertexPositionColor[3];

this.vertices[0] = new VertexPositionColor(new Vector3(0.0f, 3.0f, 0.0f),
                                           Color.Red);
this.vertices[1] = new VertexPositionColor(new Vector3(3.0f, -2.0f, 0.0f),
                                           Color.Blue);
this.vertices[2] = new VertexPositionColor(new Vector3(-3.0f, -2.0f, 0.0f),
                                           Color.Green);

Untuk mencipta data bucu, tentukan "kedudukan bucu" dan "warna bucu" dalam pembina "VertexPositionColor".

VertexPositionColor Constructor

Cipta contoh struktur "VertexPositionColor" dengan data bucu kedudukan dan warna.

Kedudukan Vektor3 Kedudukan Puncak
Warna Warna Warna bucu

Tetapkan kedudukan bucu kepada julat yang boleh dilihat dari kamera. Juga, tetapkan susunan bucu kepada "mengikut arah jam (mengikut arah jam)". Jika anda menetapkannya kepada "lawan jam", poligon tidak akan kelihatan. Untuk penjelasan tentang perkara ini, lihat Menentukan Muka Poligon untuk Dilukis.

Melukis poligon

// パスの数だけ繰り替えし描画 (といっても直接作成した BasicEffect は通常1回)
foreach (EffectPass pass in this.basicEffect.CurrentTechnique.Passes)
{
    // パスの開始
    pass.Apply();

    // ポリゴンを描画する
    this.GraphicsDevice.DrawUserPrimitives(
        PrimitiveType.TriangleList,
        this.vertices,
        0,
        1
    );
}

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

Terdapat dua jenis kesan, dipanggil "teknik" dan "laluan", di mana anda menjalankan program lukisan sebenar. Oleh kerana terdapat berbilang laluan dalam satu kesan, saya cuba memanggilnya berulang kali dalam foreach. Walau bagaimanapun, dalam BasicEffect, terdapat satu teknik dan satu laluan, jadi anda boleh menentukan indeks laluan secara langsung, tetapi penerangan di atas akan menjadi lebih bersih kerana anda boleh menggantikannya dengan kesan lain.

Sebelum memulakan lukisan sebenar, panggil kaedah "EffectPass.Apply" untuk memulakan pas. Dengan memanggil kaedah ini, parameter kesan yang akan digunakan kali ini digunakan pada peranti grafik.

Sebaik sahaja anda telah memulakan laluan, lukis poligon dengan kaedah "GraphicsDevice.DrawUserPrimitives".

Hujah pertama menentukan jenis primitif yang akan dilukis. Dalam kes ini, kita akan melukis poligon segi tiga, jadi tentukan "PrimitiveType.TriangleList".

Hujah kedua menentukan data bucu yang dibuat.

Hujah ketiga menentukan bucu untuk diambil. Biasanya, ini ialah 0.

Hujah keempat menentukan bilangan primitif untuk dilukis. Dalam kes ini, hanya terdapat satu poligon segi tiga, jadi tentukan 1. Perhatikan bahawa ia bukan bilangan bucu.

GraphicsDevice.DrawUserPrimitives Kaedah

Melukis primitif berdasarkan data bucu yang dibekalkan pengguna.

T Tiada had Struktur Data Vertex
primitifJenis Jenis Primitif Jenis primitif untuk dilukis
data vertex(Bahasa Inggris) T[] Tatasusunan data bucu untuk dilukis
Offset Puncak Int Tentukan bilangan data bucu yang akan digunakan untuk melukis
primitifCount Int Bilangan primitif untuk dilukis.

Itu sahaja untuk program lukisan. Jika anda benar-benar menjalankannya dan segitiga dipaparkan, anda sudah selesai.

Semua Kod

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

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

        /// <summary>
        /// 頂点データリスト
        /// </summary>
        private VertexPositionColor[] vertices = null;

        /// <summary>
        /// 基本エフェクト
        /// </summary>
        private BasicEffect basicEffect = null;


        /// <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()
        {
            // TODO: ここに初期化ロジックを書いてください

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

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

            // エフェクトを作成
            this.basicEffect = new BasicEffect(this.GraphicsDevice);

            // エフェクトで頂点カラーを有効にする
            this.basicEffect.VertexColorEnabled = true;

            // ビューマトリックスをあらかじめ設定 ((0, 0, 15) から原点を見る)
            this.basicEffect.View = Matrix.CreateLookAt(
                    new Vector3(0.0f, 0.0f, 15.0f),
                    Vector3.Zero,
                    Vector3.Up
                );

            // プロジェクションマトリックスをあらかじめ設定
            this.basicEffect.Projection = Matrix.CreatePerspectiveFieldOfView(
                    MathHelper.ToRadians(45.0f),
                    (float)this.GraphicsDevice.Viewport.Width /
                        (float)this.GraphicsDevice.Viewport.Height,
                    1.0f,
                    100.0f
                );

            // 頂点データを作成する
            this.vertices = new VertexPositionColor[3];

            this.vertices[0] = new VertexPositionColor(new Vector3(0.0f, 3.0f, 0.0f),
                                                       Color.Red);
            this.vertices[1] = new VertexPositionColor(new Vector3(3.0f, -2.0f, 0.0f),
                                                       Color.Blue);
            this.vertices[2] = new VertexPositionColor(new Vector3(-3.0f, -2.0f, 0.0f),
                                                       Color.Green);
        }

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

        /// <summary>
        /// 描画以外のデータ更新等の処理を行うメソッド
        /// 主に入力処理、衝突判定などの物理計算、オーディオの再生など
        /// </summary>
        /// <param name="gameTime">このメソッドが呼ばれたときのゲーム時間</param>
        protected override void Update(GameTime gameTime)
        {
            // Xbox 360 コントローラ、Windows Phone の BACK ボタンを押したときに
            // ゲームを終了させます
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
            {
                this.Exit();
            }

            // TODO: ここに更新処理を記述してください

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

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

            // パスの数だけ繰り替えし描画 (といっても直接作成した BasicEffect は通常1回)
            foreach (EffectPass pass in this.basicEffect.CurrentTechnique.Passes)
            {
                // パスの開始
                pass.Apply();

                // ポリゴンを描画する
                this.GraphicsDevice.DrawUserPrimitives(
                    PrimitiveType.TriangleList,
                    this.vertices,
                    0,
                    1
                );
            }

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