Visualizzazione delle caselle utilizzando i buffer di indice
sommario
Uso molti poligoni per creare una scatola. In questo modo, viene utilizzato un buffer di indice per ridurre la quantità di dati nei dati dei vertici.
Ambiente operativo
Prerequisiti
Versioni XNA supportate |
|
Piattaforme supportate |
|
Versione Vertex Shader richiesta da Windows | 2.0 |
Versione Pixel Shader richiesta da Windows | 2.0 |
Ambiente operativo
piattaforma |
|
sostanza
Informazioni sulla scatola
La scatola è composta da sei facce, una delle quali è costituita da due poligoni triangolari. Ciò significa che il numero totale di poligoni triangolari è "2×6 = 12". Inoltre, poiché il poligono triangolare ha tre vertici, il totale dei vertici è "12×3 = 36". Pertanto, quando si crea solo con "VertexBuffer", è possibile visualizzarlo come una casella se si decide la posizione delle informazioni in modo che 36 pezzi di dati siano a forma di casella e li si scrive. (24 sono necessari per TriangleStrip)
Ma immaginate una scatola. Gli angoli della scatola sono da 8 pezzi. Otto dovrebbero essere sufficienti per le informazioni sulla posizione. Con l'aumentare del numero di dati dei vertici, la memoria viene messa sotto pressione. Per ridurre questo in qualche modo, usiamo "IndexBuffer".
Hai solo bisogno di 8 informazioni sulla posizione, ma hai sempre bisogno di 36 vertici per un poligono. Pertanto, lo scopo dell'uso di "IndexBuffer" è quello di condividere 8 dati di vertice.
campo
<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枚目のポリゴン
};
Il campo viene dichiarato come "IndexBuffer", ma sotto di esso viene pre-creata una "matrice di numeri di vertice". Questo array riserva un array per 36 vertici, ma il significato di ogni numero è il numero di dati dei vertici degli otto dati dei vertici utilizzati da ciascun poligono triangolare. Se guardi da vicino, puoi vedere che i dati all'interno sono scritti con un indice compreso tra "0 ~ 7". È facile da vedere nei commenti.
A proposito, il tipo dell'array è "Int16[]", ma può anche essere "short[]" (2 byte). In alcuni casi, viene creata una matrice con "int" (4 byte), ma viene utilizzata quando il numero di vertici supera "65535". Se il numero di vertici non supera mai questo numero, creare una matrice di dati a 2 byte per ridurre il consumo di memoria.
creazione
// 頂点の数
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);
Creazione di buffer dei vertici. In origine, è necessario creare 36 vertici, ma utilizzando un buffer di indice, è necessario creare solo 8 vertici.
// インデックスバッファを作成
this.indexBuffer = new IndexBuffer(this.GraphicsDevice,
IndexElementSize.SixteenBits, 3 * 12, BufferUsage.None);
// 頂点インデックスを書き込む
this.indexBuffer.SetData(vertexIndices);
Creazione di buffer di indice. Il secondo argomento specifica il numero di bit dell'indice dei vertici da scrivere. Poiché un indice è di 2 byte, specificare "IndexElementSize.SixteenBits".
Il terzo argomento è il numero di indici. In questo caso, disegneremo 12 poligoni, quindi specifichiamo 36, che è il numero di vertici × poligoni dei poligoni triangolari. Naturalmente, non ci sono problemi se si specifica il numero di elementi nell'array dell'indice così com'è, ma questa volta i numeri sono separati intenzionalmente per chiarezza.
Poiché abbiamo già creato un array di indici di vertici con campi, li scriveremo con il metodo "IndexBuffer.SetData".
IndexBuffer
costruttore
Crea un'istanza della classe IndexBuffer che gestisce l'indice che fa riferimento ai dati dei vertici.
graficaDispositivo | Dispositivo grafico | Specifica l'oggetto GraphicsDevice da associare al buffer di indice. |
indexElementSize | IndexElementSize | Dimensione di un singolo indice di vertice. Specificare "SixteenBits" per 2 byte, "ThirtyTwoBits" per 4 byte e specificare BufferUsage.None. |
indexCount | Int | Specifica il numero di indici. |
uso | BufferUsage | Utilizzo del buffer dell'indice. Specificare BufferUsage.None, se non diversamente. |
IndexBuffer.SetData
metodo
Copiare la matrice di indici dei vertici nel buffer dell'indice.
T | ValoreTipo | Tipo di array di indici di vertici |
dati | T | Matrice di indici dei vertici da copiare |
disegno
// インデックスバッファをセット
this.GraphicsDevice.Indices = this.indexBuffer;
Se si desidera utilizzare un buffer di indice, impostare il buffer di indice sul dispositivo prima di disegnare il poligono.
// インデックスを使用してポリゴンを描画する
this.GraphicsDevice.DrawIndexedPrimitives(
PrimitiveType.TriangleList,
0,
0,
8,
0,
12
);
Se si usano buffer di indice e vertici, usare il metodo "GraphicsDevice.DrawIndexedPrimitives" per disegnare poligoni.
Il quarto argomento è il numero di vertici creati. Nell'esempio viene specificato "8" perché vengono condivisi 8 dati dei vertici.
Il sesto argomento specifica il numero di primitive. È "12" perché disegna 12 poligoni triangolari.
Per altri parametri numerici, 0 va bene.
GraphicsDevice.DrawIndexedPrimitives
metodo
Disegna una primitiva in base all'indice dei vertici e al buffer dei vertici specificati.
primitiveType | Tipo primitivo | Specifica la primitiva da disegnare. |
baseVertice | Int | Offset da aggiungere a ogni indice di vertice nel buffer dell'indice. Ad esempio, quando il primo indice dei vertici punta ai dati del vertice 2, se in questo argomento viene specificato "1", il primo indice dei vertici punterà ai dati del vertice 3. |
minVertexIndex | Int | Indice di vertice minimo del vertice utilizzato nella chiamata. Ad esempio, un valore minVertexIndex pari a 1 aumenta l'indice dei dati dei vertici di 1 (non aumenta il numero di buffer, pertanto non è possibile specificare l'ultimo elemento dei dati dei vertici). Se l'indice dei vertici punta ai dati del secondo vertice, punterà ai dati del primo vertice. |
numVertici | Int | Numero di dati dei vertici utilizzati. |
startIndex | Int | Offset iniziale dell'indice dei vertici. Ad esempio, se si specifica TriangleList come primitiveType, specificare "3, 6, 9,..." per ignorare i poligoni che iniziano il disegno. Se si specifica un valore diverso dal numero diviso per 3, il modello verrà compresso. (Perché tutti gli indici sono disattivati) |
primitiveCount | Int | Numero di primitive da disegnare. Il valore massimo che può essere specificato è "Numero di indici di vertice÷ Numero di vertici di primitive - startIndex" |
Tutti i codici
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);
}
}
}