Visa rutor med hjälp av indexbuffertar

Sidan uppdaterad :
Datum för skapande av sida :

sammanfattning

Jag använder många polygoner för att skapa en ruta. På så sätt används en indexbuffert för att minska mängden data i hörndata.

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

Operativ miljö

Förutsättningar

XNA-versioner som stöds
  • 4.0
Plattformar som stöds
  • Windows (XP SP2 eller senare, Vista, 7)
  • Xbox 360
  • Windows Phone 7 (på engelska)
Windows Nödvändig version av Vertex Shader 2.0
Windows Pixel Shader-version som krävs 2.0

Operativ miljö

plattform
  • Windows 7
  • Xbox 360
  • Windows Phone 7 Emulator

substans

Om boxen

Lådan består av sex ytor, varav en består av två triangulära polygoner. Detta innebär att det totala antalet triangulära polygoner är "2×6 = 12". Dessutom, eftersom den triangulära polygonen har tre hörn, är summan av hörnen "12×3 = 36". Därför, när du bara skapar med "VertexBuffer", är det möjligt att visa den som en ruta om du bestämmer positionsinformationen så att 36 databitar är i form av en ruta och skriver den. (24 krävs för TriangleStrip)

Men föreställ dig en låda. Lådans hörn är 8 stycken. Åtta bör räcka för platsinformation. När antalet hörndata ökar sätter det press på minnet. För att minska detta på något sätt använder vi "IndexBuffer".

Du behöver bara 8 positionsinformation, men du behöver alltid 36 hörn för en polygon. Därför är syftet med att använda "IndexBuffer" att dela 8 hörndata.

四角形ポリゴン

fält

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

Fältet deklareras som en "IndexBuffer", men en "vertex-nummermatris" skapas i förväg under det. Den här matrisen reserverar en matris för 36 hörn, men innebörden av varje tal är hur många hörndata av de åtta hörndata som varje triangelpolygon använder. Om du tittar noga kan du se att data inuti är skrivna med ett index mellan "0 ~ 7". Det är lätt att se i kommentarerna.

Förresten, typen av matris är "Int16[]", men den kan också vara "kort[]" (2 byte). I vissa fall skapas en matris med "int" (4 byte), men detta används när antalet hörn överskrider "65535". Om antalet hörn aldrig överskrider det här antalet skapar du en matris med data på 2 byte för att minska minnesförbrukningen.

skapelse

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

Skapa hörnbuffertar. Ursprungligen är det nödvändigt att skapa 36 hörn, men genom att använda en indexbuffert behöver du bara skapa 8 hörn.

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

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

Skapa indexbuffertar. Det andra argumentet anger antalet bitar av hörnindexet som ska skrivas. Eftersom ett index är 2 byte anger du "IndexElementSize.SixteenBits".

Det tredje argumentet är antalet index. I det här fallet ritar vi 12 polygoner, så ange 36, vilket är antalet hörn × polygoner av de triangulära polygonerna. Naturligtvis är det inget problem om du anger antalet element i indexmatrisen som det är, men den här gången är siffrorna avsiktligt separerade för tydlighetens skull.

Eftersom vi redan har skapat en array av vertex-index med fält kommer vi att skriva dem med metoden "IndexBuffer.SetData".

IndexBuffer konstruktor

Skapar en instans av klassen IndexBuffer som hanterar indexet som refererar till hörndata.

graphicsDevice (grafikEnhet) Grafikenhet Anger den GraphicsDevice som ska associeras med indexbufferten.
indexElementSize IndexElementSize (på engelska) Storleken på ett enda hörnindex. Ange "SixteenBits" för 2 byte, "ThirtyTwoBits" för 4 byte och ange BufferUsage.None.
indexCount Int Anger antalet index.
användning Buffert Användning Användning av indexbuffert. Ange BufferUsage.None om inget annat anges.

IndexBuffer.SetData metod

Kopiera matrisen med hörnindex till indexbufferten.

T Värdetyp Typ av matris för hörnindex
data T Hörnindexmatris som ska kopieras

teckning

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

Om du vill använda en indexbuffert ställer du in indexbufferten på enheten innan du ritar polygonen.

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

Om du använder index- och vertex-buffertar, använd metoden "GraphicsDevice.DrawIndexedPrimitives" för att rita polygoner.

Det fjärde argumentet är antalet hörn som skapas. I exemplet anges "8" eftersom 8 hörndata delas.

Det sjätte argumentet anger antalet primitiver. Det är "12" eftersom det ritar 12 triangulära polygoner.

För andra numeriska parametrar är 0 bra.

GraphicsDevice.DrawIndexedPrimitives metod

Ritar en primitiv baserat på det angivna hörnindexet och hörnbufferten.

primitiveType Primitiv typ Anger vilken primitiv som ska ritas.
baseVertex Int Förskjutningen som ska läggas till i varje hörnindex i indexbufferten. Till exempel, när det första hörnindexet pekar på hörndata 2, om "1" anges i det här argumentet, kommer det första hörnindexet att peka på hörndata 3.
minVertexIndex Int Det minsta hörnindexet för det hörn som används i anropet. Till exempel ökar ett minVertexIndex på 1 indexet för hörndata med 1 (det ökar inte antalet buffertar, så det sista elementet i hörndata kan inte anges). Om hörnindexet pekar på de andra hörndata, kommer det att peka på de första hörndata.
numVertices Int Antalet hörndata som används.
startIndex (startIndex) Int Startförskjutningen för vertex-indexet. Om du till exempel anger TriangleList som primitiveType anger du "3, 6, 9,..." för att hoppa över de polygoner som börjar rita. Om du anger ett annat värde än talet som divideras med 3 kommer modellen att kollapsa. (Eftersom alla index är avstängda)
primitiveCount Int Antalet primitiver som ska ritas. Det maximala värdet som kan anges är "Antal hörnindex÷ Antal hörn av primitiver – startIndex"

Alla koder

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