Visualización de cuadros mediante búferes de índice

Actualización de la página :
Fecha de creación de la página :

resumen

Utilizo muchos polígonos para crear una caja. Al hacerlo, se utiliza un búfer de índice para reducir la cantidad de datos en los datos de vértice.

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

Entorno operativo

Prerrequisitos

Versiones de XNA compatibles
  • 4.0
Plataformas compatibles
  • Windows (XP SP2 o posterior, Vista, 7)
  • Xbox 360
  • Windows Phone 7
Versión del sombreador de vértices requerida para Windows 2.0
Versión de Pixel Shader requerida para Windows 2.0

Entorno operativo

plataforma
  • Windows 7
  • Xbox 360
  • Emulador de Windows Phone 7

sustancia

Sobre la caja

La caja consta de seis caras, una de las cuales consta de dos polígonos triangulares. Esto significa que el número total de polígonos triangulares es "2×6 = 12". Además, dado que el polígono triangular tiene tres vértices, el total de vértices es "12×3 = 36". Por lo tanto, al crear solo con "VertexBuffer", es posible mostrarlo como un cuadro si decide la información de posición para que 36 datos tengan la forma de un cuadro y lo escriba. (Se requieren 24 para TriangleStrip)

Pero imagínate una caja. Las esquinas de la caja son de 8 piezas. Ocho debería ser suficiente para la información de ubicación. A medida que aumenta el número de datos de vértice, ejerce presión sobre la memoria. Para reducir esto de alguna manera, usamos "IndexBuffer".

Solo necesita 8 información de posición, pero siempre necesita 36 vértices para un polígono. Por lo tanto, el propósito de usar "IndexBuffer" es compartir datos de 8 vértices.

四角形ポリゴン

campo

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

El campo se declara como "IndexBuffer", pero se crea previamente una "matriz de números de vértices" debajo de él. Esta matriz reserva una matriz para 36 vértices, pero el significado de cada número es la cantidad de datos de vértice de los ocho datos de vértice que usa cada polígono de triángulo. Si observa de cerca, puede ver que los datos en el interior están escritos con un índice entre "0 ~ 7". Es fácil de ver en los comentarios.

Por cierto, el tipo de matriz es "Int16[]", pero también puede ser "short[]" (2 bytes). En algunos casos, se crea una matriz con "int" (4 bytes), pero se utiliza cuando el número de vértices supera "65535". Si el número de vértices nunca supera este número, cree una matriz de datos de 2 bytes para reducir el consumo de memoria.

creación

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

Creación de búferes de vértices. Originalmente, es necesario crear 36 vértices, pero mediante el uso de un búfer de índice, solo necesita crear 8 vértices.

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

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

Creación de búferes de índice. El segundo argumento especifica el número de bits del índice de vértices que se van a escribir. Dado que un índice es de 2 bytes, especifique "IndexElementSize.SixteenBits".

El tercer argumento es el número de índices. En este caso, dibujaremos 12 polígonos, así que especifica 36, que es el número de vértices × polígonos de los polígonos triangulares. Por supuesto, no hay problema si especifica el número de elementos en la matriz de índice tal como está, pero esta vez los números se separan intencionalmente para mayor claridad.

Como ya hemos creado una matriz de índices de vértices con campos, los escribiremos con el método "IndexBuffer.SetData".

IndexBuffer constructor

Crea una instancia de la clase IndexBuffer que administra el índice que hace referencia a los datos de vértice.

gráficosDispositivo Dispositivo gráfico Especifica el GraphicsDevice que se va a asociar con el búfer de índice.
indexElementSize IndexElementSize El tamaño de un índice de vértice único. Especifique "SixteenBits" para 2 bytes, "ThirtyTwoBits" para 4 bytes y especifique BufferUsage.None.
indexCount Int Especifica el número de índices.
uso Uso de búfer Uso del búfer de índices. Especifique BufferUsage.None a menos que se indique lo contrario.

IndexBuffer.SetData método

Copie la matriz de índices de vértices en el búfer de índices.

T ValueType (Tipo de valor) Tipo de matriz de índice de vértices
datos T Matriz de índice de vértices para copiar

dibujo

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

Si desea utilizar un búfer de índice, establezca el búfer de índice en el dispositivo antes de dibujar el polígono.

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

Si utiliza búferes de índice y vértices, utilice el método "GraphicsDevice.DrawIndexedPrimitives" para dibujar polígonos.

El cuarto argumento es el número de vértices creados. En el ejemplo, se especifica "8" porque se comparten datos de 8 vértices.

El sexto argumento especifica el número de primitivas. Es "12" porque dibuja 12 polígonos triangulares.

Para otros parámetros numéricos, 0 está bien.

GraphicsDevice.DrawIndexedPrimitives método

Dibuja un primitivo basado en el índice de vértices y el búfer de vértices especificados.

primitiveType PrimitiveType (Tipo primitivo) Especifica el primitivo que se va a dibujar.
baseVértice Int El desplazamiento que se va a agregar a cada índice de vértice en el búfer de índice. Por ejemplo, cuando el primer índice de vértice apunta a los datos de vértice 2, si se especifica "1" en este argumento, el primer índice de vértice apuntará a los datos de vértice 3.
minVertexIndex Int El índice de vértice mínimo del vértice utilizado en la llamada. Por ejemplo, un minVertexIndex de 1 aumenta el índice de los datos de vértice en 1 (no aumenta el número de búferes, por lo que no se puede especificar el último elemento de los datos de vértice). Si el índice de vértices apunta a los datos del segundo vértice, apuntará a los datos del primer vértice.
numVértices Int El número de datos de vértice utilizados.
startIndex Int Desplazamiento inicial del índice de vértices. Por ejemplo, si especifica TriangleList como primitiveType, especifique "3, 6, 9,..." para omitir los polígonos que comienzan a dibujarse. Si especifica un valor distinto del número dividido por 3, el modelo se contraerá. (Porque todos los índices están desactivados)
primitiveCount Int El número de primitivas que se van a dibujar. El valor máximo que se puede especificar es "Número de índices de vértices÷ Número de vértices de primitivas - startIndex"

Todos los códigos

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