Memaparkan Kotak Menggunakan Penimbal Indeks

Laman dikemaskini :
Tarikh penciptaan halaman :

Ringkasan

Saya menggunakan banyak poligon untuk mencipta kotak. Dengan berbuat demikian, penimbal indeks digunakan untuk mengurangkan jumlah data dalam data bucu.

インデックスバッファを使用したボックスの表示

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

Mengenai kotak

Kotak itu terdiri daripada enam muka, salah satunya terdiri daripada dua poligon segi tiga. Ini bermakna jumlah poligon segi tiga ialah "2×6 = 12". Tambahan pula, kerana poligon segi tiga mempunyai tiga bucu, jumlah bucu ialah "12×3 = 36". Oleh itu, apabila membuat hanya dengan "VertexBuffer", adalah mungkin untuk memaparkannya sebagai kotak jika anda memutuskan maklumat kedudukan supaya 36 keping data dalam bentuk kotak dan menulisnya. (24 diperlukan untuk TriangleStrip)

Tetapi bayangkan sebuah kotak. Sudut kotak adalah 8 keping. Lapan sepatutnya cukup untuk maklumat lokasi. Apabila bilangan data bucu meningkat, ia memberi tekanan pada ingatan. Untuk mengurangkan ini entah bagaimana, kami menggunakan "IndexBuffer".

Anda hanya memerlukan 8 maklumat kedudukan, tetapi anda sentiasa memerlukan 36 bucu untuk poligon. Oleh itu, tujuan menggunakan "IndexBuffer" adalah untuk berkongsi 8 data bucu.

四角形ポリゴン

Bidang

/// <summary>
/// インデックスバッファ
/// </summary>
private IndexBuffer indexBuffer = null;

/// <summary>
/// インデックスバッファの各頂点番号配列
/// </summary>
private static readonly Int16[] vertexIndices = new Int16[] {
    2, 0, 1, // 1枚目のポリゴン
    1, 3, 2, // 2枚目のポリゴン
    4, 0, 2, // 3枚目のポリゴン
    2, 6, 4, // 4枚目のポリゴン
    5, 1, 0, // 5枚目のポリゴン
    0, 4, 5, // 6枚目のポリゴン
    7, 3, 1, // 7枚目のポリゴン
    1, 5, 7, // 8枚目のポリゴン
    6, 2, 3, // 9枚目のポリゴン
    3, 7, 6, // 10枚目のポリゴン
    4, 6, 7, // 11枚目のポリゴン
    7, 5, 4  // 12枚目のポリゴン
};

Medan ini diisytiharkan sebagai "IndexBuffer", tetapi "tatasusunan nombor bucu" telah dicipta terlebih dahulu di bawahnya. Tatasusunan ini menempah tatasusunan untuk 36 bucu, tetapi makna setiap nombor ialah bilangan data bucu daripada lapan data bucu yang digunakan oleh setiap poligon segitiga. Jika anda melihat dengan teliti, anda dapat melihat bahawa data di dalamnya ditulis dengan indeks antara "0 ~ 7". Mudah dilihat dalam komen.

Dengan cara ini, jenis tatasusunan ialah "Int16[]", tetapi ia juga boleh menjadi "pendek[]" (2 bait). Dalam sesetengah kes, tatasusunan dibuat dengan "int" (4 bait), tetapi ini digunakan apabila bilangan bucu melebihi "65535". Jika bilangan bucu tidak pernah melebihi nombor ini, buat tatasusunan data 2-bait untuk mengurangkan penggunaan memori.

Penciptaan

// 頂点の数
int vertexCount = 8;

// 頂点バッファ作成
this.vertexBuffer = new VertexBuffer(this.GraphicsDevice,
    typeof(VertexPositionColor), vertexCount, BufferUsage.None);

// 頂点データを作成する
VertexPositionColor[] vertives = new VertexPositionColor[vertexCount];

vertives[0] = new VertexPositionColor(new Vector3(-2.0f, 2.0f, -2.0f), Color.Yellow);
vertives[1] = new VertexPositionColor(new Vector3(2.0f, 2.0f, -2.0f), Color.Gray);
vertives[2] = new VertexPositionColor(new Vector3(-2.0f, 2.0f, 2.0f), Color.Purple);
vertives[3] = new VertexPositionColor(new Vector3(2.0f, 2.0f, 2.0f), Color.Red);
vertives[4] = new VertexPositionColor(new Vector3(-2.0f, -2.0f, -2.0f), Color.SkyBlue);
vertives[5] = new VertexPositionColor(new Vector3(2.0f, -2.0f, -2.0f), Color.Orange);
vertives[6] = new VertexPositionColor(new Vector3(-2.0f, -2.0f, 2.0f), Color.Green);
vertives[7] = new VertexPositionColor(new Vector3(2.0f, -2.0f, 2.0f), Color.Blue);

// 頂点データを頂点バッファに書き込む
this.vertexBuffer.SetData(vertives);

Mencipta penimbal bucu. Pada asalnya, adalah perlu untuk membuat 36 bucu, tetapi dengan menggunakan penimbal indeks, anda hanya perlu membuat 8 bucu.

// インデックスバッファを作成
this.indexBuffer = new IndexBuffer(this.GraphicsDevice,
    IndexElementSize.SixteenBits, 3 * 12, BufferUsage.None);

// 頂点インデックスを書き込む
this.indexBuffer.SetData(vertexIndices);

Mencipta penimbal indeks. Hujah kedua menentukan bilangan bit indeks bucu yang akan ditulis. Oleh kerana satu indeks ialah 2 bait, tentukan "IndexElementSize.SixteenBits".

Hujah ketiga ialah bilangan indeks. Dalam kes ini, kita akan melukis 12 poligon, jadi tentukan 36, iaitu bilangan bucu × poligon poligon segi tiga. Sudah tentu, tidak ada masalah jika anda menentukan bilangan elemen dalam tatasusunan indeks seperti sedia ada, tetapi kali ini nombor sengaja dipisahkan untuk kejelasan.

Memandangkan kami telah mencipta tatasusunan indeks bucu dengan medan, kami akan menulisnya dengan kaedah "IndexBuffer.SetData".

IndexBuffer Constructor

Mencipta contoh kelas IndexBuffer yang menguruskan indeks yang merujuk data bucu.

graphicsPeranti GrafikPeranti Menentukan GraphicsDevice untuk dikaitkan dengan penimbal indeks.
indexElementSize Saiz Elemen Indeks Saiz indeks bucu tunggal. Tentukan "SixteenBits" untuk 2 bait, "ThirtyTwoBits" untuk 4 bait, dan tentukan BufferUsage.None.
IndexCount Int Menentukan bilangan indeks.
Penggunaan Penggunaan Penimbal Penggunaan penimbal indeks. Tentukan BufferUsage.None melainkan sebaliknya.

IndexBuffer.SetData Kaedah

Salin tatasusunan indeks bucu ke penimbal indeks.

T Jenis Nilai Jenis tatasusunan indeks bucu
Data T Tatasusunan indeks bucu untuk disalin

Lukisan

// インデックスバッファをセット
this.GraphicsDevice.Indices = this.indexBuffer;

Jika anda ingin menggunakan penimbal indeks, tetapkan penimbal indeks pada peranti sebelum melukis poligon.

// インデックスを使用してポリゴンを描画する
this.GraphicsDevice.DrawIndexedPrimitives(
    PrimitiveType.TriangleList,
    0,
    0,
    8,
    0,
    12
);

Jika anda menggunakan penimbal indeks dan bucu, gunakan kaedah "GraphicsDevice.DrawIndexedPrimitives" untuk melukis poligon.

Hujah keempat ialah bilangan bucu yang dibuat. Dalam sampel, "8" ditentukan kerana 8 data bucu dikongsi.

Hujah keenam menentukan bilangan primitif. Ia adalah "12" kerana ia melukis 12 poligon segi tiga.

Untuk parameter berangka lain, 0 tidak mengapa.

GraphicsDevice.DrawIndexedPrimitives Kaedah

Melukis primitif berdasarkan indeks bucu yang ditentukan dan penimbal bucu.

primitifJenis Jenis Primitif Menentukan primitif untuk melukis.
BaseVertex Int Pengimbangan untuk ditambah pada setiap indeks bucu dalam penimbal indeks. Sebagai contoh, apabila indeks bucu pertama menunjuk kepada data bucu 2, jika "1" ditentukan dalam hujah ini, indeks bucu pertama akan menunjuk kepada data bucu 3.
MinVertexIndex Int Indeks bucu minimum bagi bucu yang digunakan dalam panggilan. Sebagai contoh, minVertexIndex 1 meningkatkan indeks data bucu sebanyak 1 (ia tidak meningkatkan bilangan penimbal, jadi elemen terakhir data bucu tidak boleh ditentukan). Jika indeks bucu menunjuk kepada data bucu kedua, ia akan menunjuk kepada data bucu pertama.
numVertices Int Bilangan data bucu yang digunakan.
Indeks permulaan Int Mengimbangi permulaan indeks bucu. Contohnya, jika anda menentukan TriangleList sebagai primitiveType, tentukan "3, 6, 9,..." untuk melangkau poligon yang mula melukis. Jika anda menentukan nilai selain daripada nombor yang dibahagikan dengan 3, model akan runtuh. (Kerana semua indeks dimatikan)
primitifCount Int Bilangan primitif untuk dilukis. Nilai maksimum yang boleh ditentukan ialah "Bilangan indeks bucu÷ Bilangan bucu primitif - startIndex"

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

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

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

        /// <summary>
        /// 頂点バッファ
        /// </summary>
        private VertexBuffer vertexBuffer = null;

        /// <summary>
        /// インデックスバッファ
        /// </summary>
        private IndexBuffer indexBuffer = null;

        /// <summary>
        /// インデックスバッファの各頂点番号配列
        /// </summary>
        private static readonly Int16[] vertexIndices = new Int16[] {
            2, 0, 1, // 1枚目のポリゴン
            1, 3, 2, // 2枚目のポリゴン
            4, 0, 2, // 3枚目のポリゴン
            2, 6, 4, // 4枚目のポリゴン
            5, 1, 0, // 5枚目のポリゴン
            0, 4, 5, // 6枚目のポリゴン
            7, 3, 1, // 7枚目のポリゴン
            1, 5, 7, // 8枚目のポリゴン
            6, 2, 3, // 9枚目のポリゴン
            3, 7, 6, // 10枚目のポリゴン
            4, 6, 7, // 11枚目のポリゴン
            7, 5, 4  // 12枚目のポリゴン
        };


        /// <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;

            // ビューマトリックスをあらかじめ設定 ((10, 10, 10) から原点を見る)
            this.basicEffect.View = Matrix.CreateLookAt(
                    new Vector3(10.0f, 10.0f, 10.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
                );

            // 頂点の数
            int vertexCount = 8;

            // 頂点バッファ作成
            this.vertexBuffer = new VertexBuffer(this.GraphicsDevice,
                typeof(VertexPositionColor), vertexCount, BufferUsage.None);

            // 頂点データを作成する
            VertexPositionColor[] vertives = new VertexPositionColor[vertexCount];

            vertives[0] = new VertexPositionColor(new Vector3(-2.0f, 2.0f, -2.0f), Color.Yellow);
            vertives[1] = new VertexPositionColor(new Vector3(2.0f, 2.0f, -2.0f), Color.Gray);
            vertives[2] = new VertexPositionColor(new Vector3(-2.0f, 2.0f, 2.0f), Color.Purple);
            vertives[3] = new VertexPositionColor(new Vector3(2.0f, 2.0f, 2.0f), Color.Red);
            vertives[4] = new VertexPositionColor(new Vector3(-2.0f, -2.0f, -2.0f), Color.SkyBlue);
            vertives[5] = new VertexPositionColor(new Vector3(2.0f, -2.0f, -2.0f), Color.Orange);
            vertives[6] = new VertexPositionColor(new Vector3(-2.0f, -2.0f, 2.0f), Color.Green);
            vertives[7] = new VertexPositionColor(new Vector3(2.0f, -2.0f, 2.0f), Color.Blue);

            // 頂点データを頂点バッファに書き込む
            this.vertexBuffer.SetData(vertives);

            // インデックスバッファを作成
            this.indexBuffer = new IndexBuffer(this.GraphicsDevice,
                IndexElementSize.SixteenBits, 3 * 12, BufferUsage.None);

            // 頂点インデックスを書き込む
            this.indexBuffer.SetData(vertexIndices);
        }

        /// <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);

            // 描画に使用する頂点バッファをセット
            this.GraphicsDevice.SetVertexBuffer(this.vertexBuffer);

            // インデックスバッファをセット
            this.GraphicsDevice.Indices = this.indexBuffer;

            // パスの数だけ繰り替えし描画 (といっても BasicEffect は通常1回)
            foreach (EffectPass pass in this.basicEffect.CurrentTechnique.Passes)
            {
                // パスの開始
                pass.Apply();
                
                // インデックスを使用してポリゴンを描画する
                this.GraphicsDevice.DrawIndexedPrimitives(
                    PrimitiveType.TriangleList,
                    0,
                    0,
                    8,
                    0,
                    12
                );
            }

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