Affichage des boîtes à l’aide de tampons d’index

Page mise à jour :
Date de création de la page :

résumé

J’utilise beaucoup de polygones pour créer une boîte. Ce faisant, un tampon d’index est utilisé pour réduire la quantité de données dans les données de sommet.

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

Environnement d’exploitation

Conditions préalables

Versions XNA prises en charge
  • 4.0
Plates-formes prises en charge
  • Windows (XP SP2 ou version ultérieure, Vista, 7)
  • Xbox 360
  • Windows Phone 7
Version du Vertex Shader requise par Windows 2.0
Version du Pixel Shader requise par Windows 2.0

Environnement d’exploitation

plateforme
  • Windows 7
  • Xbox 360
  • Émulateur Windows Phone 7

substance

À propos de la boîte

La boîte se compose de six faces, dont l’une est constituée de deux polygones triangulaires. Cela signifie que le nombre total de polygones triangulaires est « 2×6 = 12 ». De plus, puisque le polygone triangulaire a trois sommets, le total des sommets est « 12×3 = 36 ». Par conséquent, lors de la création uniquement avec « VertexBuffer », il est possible de l’afficher sous forme de boîte si vous décidez des informations de position de sorte que 36 éléments de données aient la forme d’une boîte et écrivez-les. (24 sont requis pour TriangleStrip)

Mais imaginez une boîte. Les coins de la boîte sont de 8 pièces. Huit devraient suffire pour les informations de localisation. À mesure que le nombre de données de vertex augmente, la mémoire est soumise à une pression. Pour réduire cela d’une manière ou d’une autre, nous utilisons « IndexBuffer ».

Vous n’avez besoin que de 8 informations de position, mais vous avez toujours besoin de 36 sommets pour un polygone. Par conséquent, le but de l’utilisation de « IndexBuffer » est de partager des données de 8 sommets.

四角形ポリゴン

champ

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

Le champ est déclaré « IndexBuffer », mais un « tableau de nombres de sommets » est pré-créé en dessous. Ce tableau réserve un tableau pour 36 sommets, mais la signification de chaque nombre est le nombre de données de sommet des huit données de sommet utilisées par chaque polygone triangulaire. Si vous regardez attentivement, vous pouvez voir que les données à l’intérieur sont écrites avec un indice compris entre « 0 ~ 7 ». C’est facile à voir dans les commentaires.

D’ailleurs, le type du tableau est « Int16[] », mais il peut aussi être « short[] » (2 octets). Dans certains cas, un tableau est créé avec « int » (4 octets), mais celui-ci est utilisé lorsque le nombre de sommets dépasse « 65535 ». Si le nombre de sommets ne dépasse jamais ce nombre, créez un tableau de données de 2 octets pour réduire la consommation de mémoire.

création

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

Création de tampons de sommets. À l’origine, il est nécessaire de créer 36 sommets, mais en utilisant un tampon d’index, vous n’avez besoin de créer que 8 sommets.

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

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

Création de tampons d’index. Le deuxième argument spécifie le nombre de bits de l’index de sommet à écrire. Étant donné qu’un index est de 2 octets, spécifiez « IndexElementSize.SixteenBits ».

Le troisième argument est le nombre d’index. Dans ce cas, nous allons dessiner 12 polygones, donc spécifiez 36, qui est le nombre de sommets × de polygones des polygones triangulaires. Bien sûr, il n’y a aucun problème si vous spécifiez le nombre d’éléments dans le tableau d’index tel quel, mais cette fois-ci, les numéros sont intentionnellement séparés pour plus de clarté.

Comme nous avons déjà créé un tableau d’indices de sommets avec des champs, nous allons les écrire avec la méthode « IndexBuffer.SetData ».

IndexBuffer constructeur

Crée une instance de la classe IndexBuffer qui gère l’index qui fait référence aux données de sommet.

graphiqueAppareil Appareil graphique Spécifie le GraphicsDevice à associer à la mémoire tampon d’index.
indexElementSize IndexElementSize Taille d’un seul index de sommet. Spécifiez « SixteenBits » pour 2 octets, « ThirtyTwoBits » pour 4 octets et spécifiez BufferUsage.None.
indexCount Int Spécifie le nombre d’index.
usage BufferUsage Utilisation de la mémoire tampon d’index. Spécifiez BufferUsage.None, sauf indication contraire.

IndexBuffer.SetData méthode

Copiez le tableau d’indices de sommet dans la mémoire tampon d’index.

T Type de valeur Type de tableau d’index de sommets
données T Tableau d’index de sommets à copier

dessin

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

Si vous souhaitez utiliser une mémoire tampon d’index, définissez-la sur l’appareil avant de dessiner le polygone.

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

Si vous utilisez des tampons d’index et de sommets, utilisez la méthode « GraphicsDevice.DrawIndexedPrimitives » pour dessiner des polygones.

Le quatrième argument est le nombre de sommets créés. Dans l’exemple, « 8 » est spécifié car les données de 8 sommets sont partagées.

Le sixième argument spécifie le nombre de primitives. Il est « 12 » car il dessine 12 polygones triangulaires.

Pour les autres paramètres numériques, 0 convient.

GraphicsDevice.DrawIndexedPrimitives méthode

Dessine une primitive basée sur l’index de sommet et la mémoire tampon de vertex spécifiés.

primitiveType PrimitiveType Spécifie la primitive à dessiner.
baseVertex Int Décalage à ajouter à chaque index de sommet dans la mémoire tampon d’index. Par exemple, lorsque le premier index de sommet pointe vers les données de sommet 2, si « 1 » est spécifié dans cet argument, le premier index de sommet pointe vers les données de sommet 3.
minVertexIndex Int L’indice de sommet minimum du sommet utilisé dans l’appel. Par exemple, un minVertexIndex de 1 augmente l’index des données de sommet de 1 (il n’augmente pas le nombre de tampons, de sorte que le dernier élément des données de sommet ne peut pas être spécifié). Si l’index de sommet pointe vers les données du deuxième sommet, il pointe vers les premières données du sommet.
numSommets Int Nombre de données de sommet utilisées.
startIndex Int Décalage de départ de l’index de sommet. Par exemple, si vous spécifiez TriangleList comme primitiveType, spécifiez « 3, 6, 9,... » pour ignorer les polygones qui commencent à dessiner. Si vous spécifiez une valeur autre que le nombre divisé par 3, le modèle sera réduit. (Parce que tous les index sont désactivés)
primitiveCount Int Le nombre de primitives à dessiner. La valeur maximale qui peut être spécifiée est « Nombre d’indices de sommets÷ Nombre de sommets de primitives - startIndex »

Tous les codes

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