הצגת תיבות באמצעות מאגרי אינדקס

עודכן דף :
תאריך יצירת דף :

תקציר

אני משתמש בהרבה מצולעים כדי ליצור קופסה. בכך, מאגר אינדקס משמש להפחתת כמות הנתונים בנתוני הקודקוד.

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

סביבת הפעלה

דרישות מוקדמות

גרסאות XNA נתמכות
  • 4.0
פלטפורמות נתמכות
  • Windows (XP SP2 ואילך, Vista, 7)
  • Xbox 360
  • Windows Phone 7
Windows נדרש Vertex Shader גירסה 2.0
גירסת Pixel Shader נדרשת של Windows 2.0

סביבת הפעלה

פלטפורמה
  • חלונות 7
  • Xbox 360
  • אמולטור Windows Phone 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 מציין את GraphicsDevice לשיוך למאגר האינדקס.
indexElementSize אינדקסElementSize גודלו של אינדקס קודקוד יחיד. ציין "SixteenBits" עבור 2 בתים, "ThirtyTwoBits" עבור 4 בתים וציין BufferUsage.None.
indexCount int מציין את מספר האינדקסים.
שימוש BufferUsage שימוש במאגר אינדקס. ציין BufferUsage.none אלא אם כן אחרת.

IndexBuffer.SetData שיטת

העתק את מערך מדדי הקודקודים למאגר המדדים.

T ValueType סוג מערך אינדקס קודקודים
נתונים T מערך אינדקס קודקודים להעתקה

ציור

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

אם ברצונך להשתמש במאגר אינדקס, הגדר את מאגר האינדקס בהתקן לפני ציור המצולע.

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

אם אתה משתמש במאגרי אינדקס וקודקודים, השתמש בשיטה "GraphicsDevice.DrawIndexedPrimitives" כדי לצייר מצולעים.

הארגומנט הרביעי הוא מספר הקודקודים שנוצרו. במדגם, "8" מצוין מכיוון ש- 8 נתוני קודקודים משותפים.

הארגומנט השישי מציין את מספר הפרימיטיבים. הוא "12" מכיוון שהוא מצייר 12 מצולעים משולשים.

עבור פרמטרים מספריים אחרים, 0 זה בסדר.

GraphicsDevice.DrawIndexedPrimitives שיטת

מצייר פרימיטיבי בהתבסס על אינדקס הקודקודים ומאגר הקודקודים שצוינו.

סוג פרימיטיבי PrimitiveType מציין את הפרימיטיבי שיש לצייר.
baseVertex int ההסטה שיש להוסיף לכל אינדקס קודקודים במאגר המדדים. לדוגמה, כאשר אינדקס הקודקודים הראשון מצביע על נתוני קודקוד 2, אם צוין "1" בארגומנט זה, אינדקס הקודקודים הראשון יצביע על נתוני קודקוד 3.
minVertexIndex int אינדקס הקודקודים המינימלי של הקודקוד המשמש בשיחה. לדוגמה, minVertexIndex של 1 מגדיל את האינדקס של נתוני הקודקודים ב- 1 (הוא אינו מגדיל את מספר המאגרים, כך שלא ניתן לציין את הרכיב האחרון של נתוני הקודקוד). אם אינדקס הקודקודים מצביע על נתוני הקודקוד השני, הוא יצביע על נתוני הקודקוד הראשון.
numVertices int מספר נתוני הקודקודים שנעשה בהם שימוש.
startIndex int ההסטה ההתחלתית של אינדקס הקודקודים. לדוגמה, אם תציין TriangleList כסוג הפרימיטיבי, ציין "3, 6, 9,..." כדי לדלג על המצולעים שמתחילים לצייר. אם תציין ערך שונה מהמספר המחולק ב- 3, המודל יכווץ. (מכיוון שכל המדדים כבויים)
ספירה פרימיטיבית int מספר הפרימיטיביים לצייר. הערך המקסימלי שניתן לציין הוא "מספר מדדי קודקודים÷ מספר קודקודים של פרימיטיבים - 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);
        }
    }
}