Afișarea casetelor folosind buffere de index

Pagina actualizată :
Data creării paginii :

rezumat

Folosesc o mulțime de poligoane pentru a crea o cutie. În acest sens, se utilizează un tampon de index pentru a reduce cantitatea de date din datele nodurilor.

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

Mediul de operare

Cerințe preliminare

Versiuni XNA acceptate
  • 4.0
Platforme acceptate
  • Windows (XP SP2 sau o versiune ulterioară, Vista, 7)
  • Xbox 360
  • Windows Phone 7
Versiunea Vertex Shader necesară pentru Windows 2.0
Versiunea Pixel Shader necesară pentru Windows 2.0

Mediul de operare

peron
  • Windows 7
  • Xbox 360
  • Windows Phone 7 Emulator

substanță

Despre cutie

Cutia este formată din șase fețe, dintre care una este formată din două poligoane triunghiulare. Aceasta înseamnă că numărul total de poligoane triunghiulare este "2×6 = 12". Mai mult, deoarece poligonul triunghiular are trei noduri, totalul nodurilor este "12×3 = 36". Prin urmare, atunci când creați numai cu "VertexBuffer", este posibil să îl afișați ca o casetă dacă decideți informațiile de poziție, astfel încât 36 de date să aibă forma unei casete și să le scrieți. (24 sunt necesare pentru TriangleStrip)

Dar imaginați-vă o cutie. Colțurile cutiei sunt de 8 bucăți. Opt ar trebui să fie suficiente pentru informații despre locație. Pe măsură ce numărul de date de nod crește, pune presiune pe memorie. Pentru a reduce cumva acest lucru, folosim "IndexBuffer".

Aveți nevoie doar de 8 informații despre poziție, dar aveți întotdeauna nevoie de 36 de noduri pentru un poligon. Prin urmare, scopul utilizării "IndexBuffer" este de a partaja 8 date de nod.

四角形ポリゴン

câmp

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

Câmpul este declarat ca "IndexBuffer", dar o "matrice de numere de nod" este pre-creată sub el. Această matrice rezervă o matrice pentru 36 de noduri, dar semnificația fiecărui număr este câte date de nod din cele opt date de nod utilizează fiecare poligon triunghiular. Dacă te uiți cu atenție, poți vedea că datele din interior sunt scrise cu un index între "0 ~ 7". Este ușor de văzut în comentarii.

Apropo, tipul matricei este "Int16[]", dar poate fi și "short[]" (2 octeți). În unele cazuri, o matrice este creată cu "int" (4 octeți), dar aceasta este utilizată atunci când numărul de noduri depășește "65535". Dacă numărul de noduri nu depășește niciodată acest număr, creați o matrice de date de 2 octeți pentru a reduce consumul de memorie.

creație

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

Crearea de buffere de nod. Inițial, este necesar să creați 36 de noduri, dar folosind un tampon de index, trebuie să creați doar 8 noduri.

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

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

Crearea de memorii tampon de index. Al doilea argument specifică numărul de biți ai indexului nodului care urmează să fie scris. Deoarece un index are 2 octeți, specificați "IndexElementSize.SixteenBits".

Al treilea argument este numărul de indici. În acest caz, vom desena 12 poligoane, așa că specificați 36, care este numărul de noduri × poligoane ale poligoanelor triunghiulare. Desigur, nu există nicio problemă dacă specificați numărul de elemente din matricea de index așa cum este, dar de data aceasta numerele sunt separate în mod intenționat pentru claritate.

Deoarece am creat deja o matrice de indici de noduri cu câmpuri, le vom scrie cu metoda "IndexBuffer.SetData".

IndexBuffer constructor

Creează o instanță a clasei IndexBuffer care gestionează indexul care face referire la datele nodului.

graficăDispozitiv Dispozitiv grafic Specifică GraphicsDevice de asociat cu bufferul de index.
indexElementSize IndexElementSize Dimensiunea unui singur indice de nod. Specificați "SixteenBits" pentru 2 octeți, "ThirtyTwoBits" pentru 4 octeți și specificați BufferUsage.None.
indexCount Int Specifică numărul de indici.
obicei BufferUsage Utilizarea tamponului de index. Specificați BufferUsage.None dacă nu este altfel.

IndexBuffer.SetData metodă

Copiați matricea de indici de noduri în bufferul de index.

T ValueType Tip matrice index de noduri
date T Matrice de index de nod de copiat

desen

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

Dacă doriți să utilizați un buffer de index, setați bufferul de index pe dispozitiv înainte de a desena poligonul.

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

Dacă utilizați zone tampon de index și noduri, utilizați metoda "GraphicsDevice.DrawIndexedPrimitives" pentru a desena poligoane.

Al patrulea argument este numărul de noduri create. În eșantion, "8" este specificat deoarece sunt partajate date cu 8 noduri.

Al șaselea argument specifică numărul de primitive. Este "12" pentru că desenează 12 poligoane triunghiulare.

Pentru alți parametri numerici, 0 este în regulă.

GraphicsDevice.DrawIndexedPrimitives metodă

Desenează o primitivă pe baza indexului de nod și a tamponului de noduri specificate.

primitiveType PrimitiveType Specifică primitivul de desenat.
bazăVertex Int Decalajul de adăugat la fiecare index de nod din bufferul de index. De exemplu, atunci când primul index de nod indică date de nod 2, dacă "1" este specificat în acest argument, primul index de nod va indica datele de nod 3.
minVertexIndex Int Indicele minim de nod al nodului utilizat în apel. De exemplu, un minVertexIndex de 1 crește indicele datelor nodului cu 1 (nu crește numărul de tamponuri, deci ultimul element al datelor nodului nu poate fi specificat). Dacă indexul nodului indică la a doua dată de nod, va indica la primele date de nod.
numVertices Int Numărul de date de nod utilizate.
startIndex Int Decalajul de pornire al indexului nodului. De exemplu, dacă specificați TriangleList ca primitiveType, specificați "3, 6, 9,..." pentru a omite poligoanele care încep să deseneze. Dacă specificați o altă valoare decât numărul care este împărțit la 3, modelul se va restrânge. (Pentru că toți indicii sunt dezactivați)
primitiveCount Int Numărul de primitive de desenat. Valoarea maximă care poate fi specificată este "Numărul de indici de noduri÷ Numărul de noduri ale primitivelor - startIndex"

Toate codurile

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