Dizin Arabelleklerini Kullanarak Kutuları Görüntüleme

Sayfa güncel :
Sayfa oluşturma tarihi :

özet

Bir kutu oluşturmak için çok fazla çokgen kullanırım. Bunu yaparken, köşe verilerindeki veri miktarını azaltmak için bir dizin arabelleği kullanılır.

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

Çalışma ortamı

Önkoşullar

Desteklenen XNA Sürümleri
  • 4.0
Desteklenen Platformlar
  • Windows (XP SP2 veya üstü, Vista, 7)
  • Xbox 360 için Oyunlar
  • Windows Phone 7
Windows Gerekli Köşe Gölgelendiricisi Sürümü 2.0
Windows Gerekli Pixel Shader Sürümü 2.0

Çalışma ortamı

peron
  • Windows 7
  • Xbox 360 için Oyunlar
  • Windows Phone 7 Emülatörü

madde

Kutu hakkında

Kutu, biri iki üçgen çokgenden oluşan altı yüzden oluşur. Bu, toplam üçgen çokgen sayısının "2×6 = 12" olduğu anlamına gelir. Ayrıca, üçgen çokgenin üç köşesi olduğundan, köşelerin toplamı "12×3 = 36" dır. Bu yüzden sadece "VertexBuffer" ile oluşturma yaparken konum bilgisini 36 adet verinin kutu şeklinde olacak şekilde kararlaştırıp yazarsanız bunu kutu olarak göstermeniz mümkündür. (TriangleStrip için 24 adet gereklidir)

Ama bir kutu hayal edin. Kutunun köşeleri 8 adettir. Konum bilgisi için sekiz yeterli olmalıdır. Köşe verilerinin sayısı arttıkça, bellek üzerinde baskı oluşturur. Bunu bir şekilde azaltmak için "IndexBuffer" kullanıyoruz.

Yalnızca 8 konum bilgisine ihtiyacınız vardır, ancak bir çokgen için her zaman 36 köşeye ihtiyacınız vardır. Bu nedenle "IndexBuffer" kullanmanın amacı 8 köşe verisini paylaşmaktır.

四角形ポリゴン

alan

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

Alan bir "IndexBuffer" olarak bildirilir, ancak altında bir "köşe sayısı dizisi" önceden oluşturulur. Bu dizi, 36 köşe için bir dizi ayırır, ancak her sayının anlamı, her üçgen çokgenin sekiz köşe verisinin kaç köşe verisini kullandığıdır. Yakından bakarsanız, içindeki verilerin "0 ~ 7" arasında bir indeks ile yazıldığını görebilirsiniz. Yorumlarda görmek kolaydır.

Bu arada, dizinin türü "Int16[]", ancak "short[]" (2 bayt) da olabilir. Bazı durumlarda, "int" (4 bayt) ile bir dizi oluşturulur, ancak bu, köşe sayısı "65535" i aştığında kullanılır. Köşe sayısı hiçbir zaman bu sayıyı aşmazsa, bellek tüketimini azaltmak için 2 baytlık bir veri dizisi oluşturun.

yaratım

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

Köşe arabellekleri oluşturma. Başlangıçta 36 köşe oluşturmak gerekir, ancak bir indeks arabelleği kullanarak yalnızca 8 köşe oluşturmanız gerekir.

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

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

Dizin arabellekleri oluşturma. İkinci bağımsız değişken, yazılacak köşe indeksinin bit sayısını belirtir. Bir dizin 2 bayt olduğundan, "IndexElementSize.SixteenBits" belirtin.

Üçüncü argüman indeks sayısıdır. Bu durumda 12 çokgen çizeceğiz, bu nedenle üçgen çokgenlerin köşelerinin × çokgenlerinin sayısı olan 36'yı belirtin. Tabii ki, indeks dizisindeki elemanların sayısını olduğu gibi belirtirseniz sorun olmaz, ancak bu sefer sayılar netlik için kasıtlı olarak ayrılmıştır.

Zaten alanlı bir köşe indeksleri dizisi oluşturduğumuz için bunları "IndexBuffer.SetData" metodu ile yazacağız.

IndexBuffer Oluşturucu

Köşe verilerine başvuran dizini yöneten IndexBuffer sınıfının bir örneğini oluşturur.

graphicsDevice (grafikAygıt) Ekran KartıAygıt Dizin arabelleğiyle ilişkilendirilecek GraphicsDevice'ı belirtir.
indexElementSize IndexElementSize (Dizin Öğesi Boyutu) Tek bir köşe indeksinin boyutu. 2 bayt için "SixteenBits", 4 bayt için "ThirtyTwoBits" belirtin ve BufferUsage.None değerini belirtin.
indexCount (indeks sayısı) Int Dizin sayısını belirtir.
Kullanım Tampon Kullanımı Dizin arabelleği kullanımı. Aksi olmadıkça BufferUsage.None belirtin.

IndexBuffer.SetData yöntem

Köşe indeksleri dizisini indeks arabelleğine kopyalayın.

T Değer Türü Köşe indeksi dizi türü
veri T Kopyalanacak köşe indeksi dizisi

çizim

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

Bir indeks arabelleği kullanmak istiyorsanız, çokgeni çizmeden önce cihazda dizin arabelleğini ayarlayın.

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

Dizin ve köşe arabellekleri kullanıyorsanız, çokgenler çizmek için "GraphicsDevice.DrawIndexedPrimitives" yöntemini kullanın.

Dördüncü argüman, oluşturulan köşelerin sayısıdır. Örnekte, 8 köşe verisi paylaşıldığı için "8" belirtilmiştir.

Altıncı bağımsız değişken, temel öğelerin sayısını belirtir. 12 üçgen çokgen çizdiği için "12"dir.

Diğer sayısal parametreler için 0 iyidir.

GraphicsDevice.DrawIndexedPrimitives yöntem

Belirtilen köşe indeksine ve köşe arabelleğine dayalı olarak bir temel öğe çizer.

ilkel tip İlkel Tip Çizilecek ilkeli belirtir.
baseVertex (Üs Köşesi) Int Dizin arabelleğindeki her köşe dizinine eklenecek uzaklık. Örneğin, ilk köşe indeksi köşe verisi 2'yi gösterdiğinde, bu bağımsız değişkende "1" belirtilirse, ilk köşe indeksi köşe verisi 3'ü gösterecektir.
minVertexIndex Int Çağrıda kullanılan köşenin minimum köşe indeksi. Örneğin, 1 minVertexIndex köşe verilerinin indeksini 1 artırır (arabellek sayısını artırmaz, bu nedenle köşe verilerinin son öğesi belirtilemez). Köşe indeksi ikinci köşe verisine işaret ediyorsa, ilk köşe verisine işaret edecektir.
numVertices Int Kullanılan köşe verilerinin sayısı.
startIndex (Başlangıç Dizini) Int Köşe indeksinin başlangıç ofseti. Örneğin, primitiveType olarak TriangleList'i belirtirseniz, çizime başlayan çokgenleri atlamak için "3, 6, 9,..." değerini belirtin. 3'e bölünen sayı dışında bir değer belirtirseniz, model daraltılır. (Çünkü tüm indeksler kapalı)
ilkel Sayı Int Çizilecek temel öğelerin sayısı. Belirtilebilecek en yüksek değer "Köşe indekslerinin sayısı÷ İlkellerin köşe sayısı - startIndex" şeklindedir.

Tüm Kodlar

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