نمایش باکس ها با استفاده از بافرهای ایندکس

صفحه به روز شده :
تاریخ ایجاد صفحه :

خلاصه

من از چند ضلعی های زیادی برای ایجاد یک جعبه استفاده می کنم. برای انجام این کار، از یک بافر شاخص برای کاهش میزان داده ها در داده های راس استفاده می شود.

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

محیط عملیاتی

پیش نیازها

نسخه های XNA پشتیبانی شده
  • 4.0
پلتفرم های پشتیبانی شده
  • ویندوز (XP SP2 یا بالاتر، ویستا، 7)
  • ایکس باکس 360
  • ویندوز فون 7
نسخه Vertex Shader مورد نیاز ویندوز 2.0
ویندوز نسخه Pixel Shader مورد نیاز است 2.0

محیط عملیاتی

بستر
  • ویندوز 7
  • ایکس باکس 360
  • شبیه ساز ویندوز فون 7

ماده

درباره جعبه

این جعبه از شش وجه تشکیل شده است که یکی از آنها از دو چند ضلعی مثلثی تشکیل شده است. این بدان معنی است که تعداد کل چند ضلعی های مثلثی "2×6 = 12" است. علاوه بر این، از آنجایی که چند ضلعی مثلثی دارای سه رأس است، مجموع رئوس "12×3 = 36" است. بنابراین ، هنگام ایجاد فقط با "VertexBuffer" ، اگر اطلاعات موقعیت را تعیین کنید ، می توانید آن را به صورت یک جعبه نمایش دهید تا 36 قطعه داده به شکل یک جعبه باشد و آن را بنویسید. (24 مورد برای TriangleStrip مورد نیاز است)

اما یک جعبه را تصور کنید. گوشه های جعبه 8 تکه است. هشت باید برای اطلاعات مکان کافی باشد. با افزایش تعداد داده های راس، به حافظه فشار وارد می کند. برای کاهش این به نحوی، از "IndexBuffer" استفاده می کنیم.

شما فقط به 8 اطلاعات موقعیت نیاز دارید، اما همیشه به 36 راس برای یک چند ضلعی نیاز دارید. بنابراین، هدف از استفاده از "IndexBuffer" به اشتراک گذاری 8 داده راس است.

四角形ポリゴン

زمینه

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

این فیلد به عنوان "IndexBuffer" اعلام می شود، اما یک "آرایه اعداد راس" از قبل در زیر آن ایجاد شده است. این آرایه یک آرایه برای 36 راس ذخیره می کند، اما معنای هر عدد این است که هر چند ضلعی مثلثی از چه تعداد داده راس از هشت داده راس استفاده می کند. اگر به دقت نگاه کنید، می بینید که داده های داخل با شاخصی بین "0 ~ 7" نوشته شده است. دیدن آن در نظرات آسان است.

به هر حال، نوع آرایه "Int16[]" است، اما می تواند "کوتاه[]" (2 بایت) نیز باشد. در برخی موارد، یک آرایه با "int" (4 بایت) ایجاد می شود، اما زمانی استفاده می شود که تعداد رئوس از "65535" بیشتر شود. اگر تعداد رئوس هرگز از این عدد فراتر نرفت، آرایه ای از داده های 2 بایتی ایجاد کنید تا مصرف حافظه کاهش یابد.

ایجاد

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

ایجاد بافرهای راس در ابتدا ایجاد 36 راس ضروری است، اما با استفاده از بافر ایندکس فقط باید 8 راس ایجاد کنید.

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

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

ایجاد بافرهای ایندکس آرگومان دوم تعداد بیت های شاخص راس را مشخص می کند که باید نوشته شود. از آنجایی که یک ایندکس 2 بایت است، "IndexElementSize.SixteenBits" را مشخص کنید.

استدلال سوم تعداد شاخص ها است. در این حالت ، ما 12 چند ضلعی را ترسیم می کنیم ، بنابراین 36 را مشخص می کنیم ، که تعداد رئوس × چند ضلعی های چند ضلعی مثلثی است. البته اگر تعداد عناصر موجود در آرایه فهرست را همانطور که هست مشخص کنید، مشکلی وجود ندارد، اما این بار اعداد عمدا برای وضوح از هم جدا می شوند.

از آنجایی که قبلا آرایه ای از شاخص های راس را با فیلدها ایجاد کرده ایم، آنها را با روش "IndexBuffer.SetData" می نویسیم.

IndexBuffer سازنده

نمونه ای از کلاس IndexBuffer ایجاد می کند که شاخصی را مدیریت می کند که به داده های راس ارجاع می دهد.

گرافیکدستگاه دستگاه گرافیکی GraphicsDevice را مشخص می کند تا با بافر فهرست مرتبط شود.
indexElementSize IndexElementSize اندازه یک شاخص راس واحد. "SixteenBits" را برای 2 بایت، "ThirtyTwoBits" را برای 4 بایت مشخص کنید و BufferUsage.None را مشخص کنید.
شمارش شاخص هوشمند تعداد نمایه ها را مشخص می کند.
استفاده استفاده از بافر استفاده از بافر شاخص. BufferUsage.None را مشخص کنید مگر اینکه خلاف آن باشد.

IndexBuffer.SetData روش

آرایه ای از شاخص های راس را در بافر شاخص کپی کنید.

T نوع ارزش نوع آرایه شاخص Vertex
داده T آرایه شاخص Vertex برای کپی کردن

نقاشی

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

اگر می خواهید از بافر ایندکس استفاده کنید، قبل از کشیدن چند ضلعی، بافر ایندکس را روی دستگاه تنظیم کنید.

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

اگر از بافرهای شاخص و راس استفاده می کنید، از روش "GraphicsDevice.DrawIndexedPrimitives" برای ترسیم چند ضلعی ها استفاده کنید.

آرگومان چهارم تعداد رئوس ایجاد شده است. در نمونه، "8" مشخص شده است زیرا 8 داده راس به اشتراک گذاشته شده است.

آرگومان ششم تعداد ابتدایی ها را مشخص می کند. "12" است زیرا 12 چند ضلعی مثلثی را ترسیم می کند.

برای سایر پارامترهای عددی، 0 خوب است.

GraphicsDevice.DrawIndexedPrimitives روش

یک ابتدایی را بر اساس شاخص راس مشخص شده و بافر راس ترسیم می کند.

نوع ابتدایی نوع اولیه ابتدایی ترسیم را مشخص می کند.
baseVertex هوشمند افست برای افزودن به هر شاخص راس در بافر شاخص. به عنوان مثال، هنگامی که اولین شاخص راس به داده راس 2 اشاره می کند، اگر "1" در این آرگومان مشخص شده باشد، اولین شاخص راس به داده های راس 3 اشاره می کند.
minVertexIndex هوشمند حداقل شاخص راس راس مورد استفاده در فراخوان. به عنوان مثال ، یک minVertexIndex 1 شاخص داده های راس را 1 افزایش می دهد (تعداد بافرها را افزایش نمی دهد ، بنابراین آخرین عنصر داده های راس را نمی توان مشخص کرد). اگر شاخص راس به داده های راس دوم اشاره کند، به داده های راس اول اشاره می کند.
numVertices هوشمند تعداد داده های راس استفاده شده.
startIndex هوشمند افست شروع شاخص راس. به عنوان مثال، اگر TriangleList را به عنوان primitiveType مشخص کنید، "3, 6, 9,..." را مشخص کنید تا از چند ضلعی هایی که شروع به ترسیم می کنند رد شوید. اگر مقداری غیر از عددی را که بر 3 تقسیم می شود مشخص کنید، مدل جمع می شود. (چون همه ایندکس ها خاموش هستند)
شمارش ابتدایی هوشمند تعداد ابتدایی ها برای ترسیم. حداکثر مقداری که می توان مشخص کرد "تعداد شاخص های راس÷ تعداد رئوس اولیه - startIndex" است.

همه کدها

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