Laukų rodymas naudojant indekso buferius

Puslapis atnaujintas :
Puslapio sukūrimo data :

suvestinė

Aš naudoju daug daugiakampių, kad sukurčiau dėžutę. Tai darant, indekso buferis naudojamas sumažinti duomenų kiekį viršūnės duomenyse.

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

Darbo aplinka

Būtinosios sąlygos

Palaikomos XNA versijos
  • 4.0
Palaikomos platformos
  • "Windows" (XP SP2 arba naujesnė versija, Vista, 7)
  • "Xbox 360"
  • "Windows Phone 7"
"Windows" reikalinga "Vertex Shader" versija 2.0
"Windows" reikalinga "Pixel Shader" versija 2.0

Darbo aplinka

platforma
  • Langai 7
  • "Xbox 360"
  • "Windows Phone 7" emuliatorius

medžiaga

Apie dėžutę

Dėžutė susideda iš šešių veidų, iš kurių vienas susideda iš dviejų trikampių daugiakampių. Tai reiškia, kad bendras trikampių daugiakampių skaičius yra "2×6 = 12". Be to, kadangi trikampis daugiakampis turi tris viršūnes, viršūnių suma yra "12×3 = 36". Todėl, kuriant tik su "VertexBuffer", galima jį rodyti kaip langelį, jei nuspręsite pozicijos informaciją taip, kad 36 duomenų vienetai būtų dėžutės formos ir parašyti. ("TriangleStrip" reikalingi 24)

Bet įsivaizduokite dėžutę. Dėžutės kampai yra 8 vnt. Vietos informacijai turėtų pakakti aštuonių. Didėjant viršūnių duomenų skaičiui, tai daro spaudimą atminčiai. Norėdami tai kažkaip sumažinti, mes naudojame "IndexBuffer".

Jums reikia tik 8 pozicijų informacijos, bet daugiakampiui visada reikia 36 viršūnių. Todėl "IndexBuffer" naudojimo tikslas yra dalytis 8 viršūnių duomenimis.

四角形ポリゴン

laukas

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

Laukas deklaruojamas kaip "IndexBuffer", tačiau po juo iš anksto sukurtas "viršūnių skaičių masyvas". Šis masyvas rezervuoja masyvą 36 viršūnėms, tačiau kiekvieno skaičiaus reikšmė yra tai, kiek viršūnių duomenų iš aštuonių viršūnių duomenų naudoja kiekvienas trikampis daugiakampis. Jei atidžiai pažvelgsite, pamatysite, kad viduje esantys duomenys yra parašyti indeksu tarp "0 ~ 7". Tai lengva pamatyti komentaruose.

Beje, masyvo tipas yra "Int16[]", tačiau jis taip pat gali būti "trumpas[]" (2 baitai). Kai kuriais atvejais masyvas sukuriamas su "int" (4 baitai), tačiau tai naudojama, kai viršūnių skaičius viršija "65535". Jei viršūnių skaičius niekada neviršija šio skaičiaus, sukurkite 2 baitų duomenų masyvą, kad sumažintumėte atminties suvartojimą.

kūrinys

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

Viršūnių buferių kūrimas. Iš pradžių būtina sukurti 36 viršūnes, tačiau naudojant indekso buferį reikia sukurti tik 8 viršūnes.

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

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

Indekso buferių kūrimas. Antrasis argumentas nurodo, kiek viršūnių indekso bitų reikia parašyti. Kadangi vienas indeksas yra 2 baitai, nurodykite "IndexElementSize.SixteenBits".

Trečiasis argumentas yra indeksų skaičius. Tokiu atveju mes nupiešime 12 daugiakampių, todėl nurodykite 36, tai yra trikampių daugiakampių viršūnių × daugiakampių daugiakampių skaičius. Žinoma, nėra jokių problemų, jei nurodote indekso masyvo elementų skaičių, koks jis yra, tačiau šį kartą skaičiai yra sąmoningai atskirti, kad būtų aiškiau.

Kadangi jau sukūrėme viršūnių indeksų masyvą su laukais, juos parašysime "IndexBuffer.SetData" metodu.

IndexBuffer Konstruktorius

Sukuria "IndexBuffer" klasės egzempliorių, kuris valdo indeksą, nurodantį viršūnės duomenis.

grafikaĮrenginys GrafikaDevice Nurodo GraphicsDevice, kurį reikia susieti su indekso buferiu.
indexElementSize IndexElementSize Vieno viršūnės indekso dydis. Nurodykite "SixteenBits" 2 baitams, "ThirtyTwoBits" 4 baitams ir nurodykite BufferUsage.None.
indexCount Int Nurodo indeksų skaičių.
Naudojimo BuferisUsage Indekso buferio naudojimas. Nurodykite BufferUsage.Nėra, nebent kitaip.

IndexBuffer.SetData metodas

Nukopijuokite viršūnių indeksų masyvą į indekso buferį.

T "ValueType" Vertex indekso masyvo tipas
duomenys T Vertex indekso masyvas, kurį reikia kopijuoti

piešinys

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

Jei norite naudoti indekso buferį, prieš piešdami daugiakampį, nustatykite įrenginio indekso buferį.

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

Jei naudojate indekso ir viršūnių buferius, naudokite metodą "GraphicsDevice.DrawIndexedPrimitives", kad pieštumėte daugiakampius.

Ketvirtasis argumentas yra sukurtų viršūnių skaičius. Pavyzdyje nurodomas "8", nes bendrinami 8 viršūnių duomenys.

Šeštasis argumentas nurodo primityvų skaičių. Jis yra "12", nes piešia 12 trikampių daugiakampių.

Kitiems skaitiniams parametrams 0 yra gerai.

GraphicsDevice.DrawIndexedPrimitives metodas

Nubrėžia primityvą pagal nurodytą viršūnės indeksą ir viršūnės buferį.

primityvusTipas Primityvustipas Nurodo primityvą piešti.
baseVertex Int Poslinkis, kurį reikia pridėti prie kiekvieno indekso buferio viršūnės indekso. Pavyzdžiui, kai pirmasis viršūnės indeksas nurodo į viršūnės duomenis 2, jei šiame argumente nurodytas "1", pirmasis viršūnės indeksas nurodys viršūnės duomenis 3.
minVertexIndex Int Minimalus skambučio metu naudojamos viršūnės viršūnės indeksas. Pavyzdžiui, 1 minVertexIndex padidina viršūnių duomenų indeksą 1 (jis nepadidina buferių skaičiaus, todėl negalima nurodyti paskutinio viršūnės duomenų elemento). Jei viršūnės indeksas nurodo į antruosius viršūnės duomenis, jis nurodys pirmuosius viršūnės duomenis.
numVertices Int Naudotų viršūnių duomenų skaičius.
pradėtiIndeksas Int Pradinis viršūnės indekso poslinkis. Pavyzdžiui, jei nurodote TriangleList kaip primityvųTipą, nurodykite "3, 6, 9,...", kad praleistumėte daugiakampius, kurie pradeda piešti. Jei nurodysite kitą reikšmę nei skaičius, padalytas iš 3, modelis bus sutrauktas. (Nes visi indeksai išjungti)
primityvusCount Int Primityvių, kuriuos reikia nupiešti, skaičius. Didžiausia vertė, kurią galima nurodyti, yra "Viršūnių indeksų skaičius÷ Primityvių viršūnių skaičius - startIndex"

Visi kodai

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