Ruutujen näyttäminen indeksipuskureiden avulla

Sivu päivitetty :
Sivun luontipäivämäärä :

yhteenveto

Käytän paljon monikulmioita laatikon luomiseen. Tällöin indeksipuskuria käytetään vähentämään kärkipistetietojen tietomäärää.

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

Toimintaympäristö

Edellytykset

Tuetut XNA-versiot
  • 4.0
Tuetut alustat
  • Windows (XP SP2 tai uudempi, Vista, 7)
  • Xbox 360
  • Windows Phone 7
Windowsin vaatima Vertex Shader -versio 2.0
Windowsin vaatima Pixel Shader -versio 2.0

Toimintaympäristö

lava
  • Windows 7
  • Xbox 360
  • Windows Phone 7 -emulaattori

aine

Tietoja laatikosta

Laatikko koostuu kuudesta pinnasta, joista yksi koostuu kahdesta kolmion muotoisesta monikulmiosta. Tämä tarkoittaa, että kolmiomaisten monikulmioiden kokonaismäärä on "2×6 = 12". Lisäksi, koska kolmiomaisella monikulmiolla on kolme pistettä, pisteiden kokonaismäärä on "12×3 = 36". Siksi, kun luot vain "VertexBufferilla", on mahdollista näyttää se laatikkona, jos päätät sijaintitiedot niin, että 36 tietoa on laatikon muotoinen ja kirjoita se. (24 vaaditaan TriangleStripille)

Mutta kuvittele laatikko. Laatikon kulmat ovat 8 kpl. Kahdeksan pitäisi riittää sijaintitietoihin. Kun kärkipisteiden määrä kasvaa, se aiheuttaa paineita muistille. Tämän vähentämiseksi jotenkin käytämme "IndexBufferia".

Tarvitset vain 8 sijaintitietoa, mutta tarvitset aina 36 pistettä monikulmiolle. Siksi "IndexBufferin" käytön tarkoituksena on jakaa 8 kärkipistettä.

四角形ポリゴン

pelto

/// <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枚目のポリゴン
};

Kenttä julistetaan "IndexBufferiksi", mutta sen alle on luotu valmiiksi "kärkinumerotaulukko". Tämä taulukko varaa taulukon 36 kärjelle, mutta kunkin luvun merkitys on se, kuinka monta kärkipistettä tietoja kahdeksasta kärkipistetiedosta kukin kolmion monikulmio käyttää. Jos tarkastelet tarkasti, näet, että sisällä olevat tiedot on kirjoitettu indeksillä välillä "0 ~ 7". Se on helppo nähdä kommenteissa.

Muuten, taulukon tyyppi on "Int16[]", mutta se voi olla myös "lyhyt[]" (2 tavua). Joissakin tapauksissa luodaan taulukko, jossa on "int" (4 tavua), mutta tätä käytetään, kun pisteiden lukumäärä ylittää "65535". Jos kärkipisteiden määrä ei koskaan ylitä tätä lukua, luo joukko 2-tavuisia tietoja muistin kulutuksen vähentämiseksi.

luomus

// 頂点の数
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);

Kärkipistepuskureiden luominen. Alun perin on tarpeen luoda 36 pistettä, mutta käyttämällä indeksipuskuria sinun tarvitsee luoda vain 8 pistettä.

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

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

Indeksipuskureiden luominen. Toinen argumentti määrittää kirjoitettavien kärkiindeksin bittien määrän. Koska yksi indeksi on 2 tavua, määritä "IndexElementSize.SixteenBits".

Kolmas argumentti on indeksien lukumäärä. Tässä tapauksessa piirrämme 12 monikulmiota, joten määritä 36, joka on kolmiomaisten monikulmioiden pisteiden × monikulmioiden lukumäärä. Tietenkään ei ole mitään ongelmaa, jos määrität indeksiryhmän elementtien lukumäärän sellaisenaan, mutta tällä kertaa numerot erotetaan tarkoituksella selkeyden vuoksi.

Koska olemme jo luoneet joukon kärkipisteindeksejä kentillä, kirjoitamme ne "IndexBuffer.SetData" -menetelmällä.

IndexBuffer rakentaja

Luo IndexBuffer-luokan esiintymän, joka hallitsee kärkipistetietoihin viittaavaa indeksiä.

grafiikkalaite Grafiikkalaite Määrittää indeksipuskuriin liitettävän GraphicsDevice-laitteen.
indexElementSize IndexElementSize Yhden kärkipisteen indeksin koko. Määritä "SixteenBits" 2 tavulle, "ThirtyTwoBits" 4 tavulle ja määritä BufferUsage.None.
indexCount Int Määrittää indeksien määrän.
käyttö BufferUsage Indeksipuskurin käyttö. Määritä BufferUsage.None, ellei toisin ole.

IndexBuffer.SetData menetelmä

Kopioi kärkipisteindeksien matriisi indeksipuskuriin.

T ValueType Kärkipisteindeksimatriisin tyyppi
data T Kopioitava kärkipisteindeksimatriisi

piirros

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

Jos haluat käyttää indeksipuskuria, aseta indeksipuskuri laitteeseen ennen monikulmion piirtämistä.

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

Jos käytät indeksi- ja kärkipistepuskureita, piirrä monikulmioita "GraphicsDevice.DrawIndexedPrimitives" -menetelmällä.

Neljäs argumentti on luotujen pisteiden lukumäärä. Näytteessä "8" on määritetty, koska 8 kärkipistettä on jaettu.

Kuudes argumentti määrittelee primitiivien lukumäärän. Se on "12", koska se piirtää 12 kolmion muotoista monikulmiota.

Muiden numeeristen parametrien osalta 0 on hyvä.

GraphicsDevice.DrawIndexedPrimitives menetelmä

Piirtää primitiivin määritetyn kärkipisteindeksin ja kärkipuskurin perusteella.

primitiivinenTyyppi PrimitiveTyyppi Määrittää piirtävän primitiivin.
baseVertex Int Siirtymä, joka lisätään indeksipuskurin kuhunkin kärkiindeksiin. Esimerkiksi kun ensimmäinen kärkipisteindeksi osoittaa kärkipistetietoihin 2, jos tässä argumentissa on määritetty "1", ensimmäinen kärkipisteindeksi osoittaa kärkipistetietoihin 3.
minVertexIndex Int Puhelussa käytetyn kärkipisteen vähimmäispisteindeksi. Esimerkiksi minVertexIndex 1 lisää kärkipistedatan indeksiä 1:llä (se ei lisää puskureiden määrää, joten kärkipistedatan viimeistä elementtiä ei voida määrittää). Jos kärkipisteindeksi osoittaa toiseen kärkipistedataan, se osoittaa ensimmäiseen kärkipistedataan.
numVertices Int Käytettyjen kärkipistetietojen määrä.
startIndeksi Int Kärkipisteindeksin alkusiirtymä. Jos esimerkiksi määrität primitiiviseksi tyypiksi TriangleList, ohita piirtämisen aloittavat monikulmiot määrittämällä "3, 6, 9,...". Jos määrität jonkin muun arvon kuin luvun, joka jaetaan 3:lla, malli kutistuu. (Koska kaikki indeksit ovat pois päältä)
primitiivinenCount Int Piirrettävien primitiivien lukumäärä. Suurin määritettävissä oleva arvo on "Kärkipisteindeksien lukumäärä÷ Primitiivien pisteiden lukumäärä - startIndex"

Kaikki koodit

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