Anzeigen von Boxen mithilfe von Indexpuffern
Zusammenfassung
Ich verwende viele Polygone, um eine Box zu erstellen. Dabei wird ein Indexpuffer verwendet, um die Datenmenge in den Vertex-Daten zu reduzieren.
Betriebsumgebung
Voraussetzungen
Unterstützte XNA-Versionen |
|
Unterstützte Plattformen |
|
Erforderliche Vertex-Shader-Version für Windows | 2.0 |
Erforderliche Pixel-Shader-Version für Windows | 2.0 |
Betriebsumgebung
Bahnsteig |
|
Substanz
Über die Box
Die Box besteht aus sechs Flächen, von denen eine aus zwei dreieckigen Polygonen besteht. Das bedeutet, dass die Gesamtzahl der dreieckigen Polygone "2×6 = 12" beträgt. Da das dreieckige Polygon drei Eckpunkte hat, beträgt die Summe der Eckpunkte "12×3 = 36". Daher ist es beim Erstellen nur mit "VertexBuffer" möglich, es als Box anzuzeigen, wenn Sie die Positionsinformationen so festlegen, dass 36 Daten in Form einer Box sind und diese schreiben. (24 sind für TriangleStrip erforderlich)
Aber stellen Sie sich eine Schachtel vor. Die Ecken der Schachtel sind 8 Stück. Acht sollten für Standortinformationen ausreichen. Wenn die Anzahl der Vertexdaten zunimmt, übt dies einen Druck auf den Arbeitsspeicher aus. Um dies etwas zu reduzieren, verwenden wir "IndexBuffer".
Sie benötigen nur 8 Positionsinformationen, aber Sie benötigen immer 36 Eckpunkte für ein Polygon. Daher besteht der Zweck der Verwendung von "IndexBuffer" darin, 8 Vertex-Daten gemeinsam zu nutzen.
Feld
<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枚目のポリゴン
};
Das Feld wird als "IndexBuffer" deklariert, aber ein "Vertex-Nummern-Array" wird vorab erstellt. Dieses Array reserviert ein Array für 36 Scheitelpunkte, aber die Bedeutung jeder Zahl gibt an, wie viele der acht Scheitelpunktdaten jedes Dreieckspolygon verwendet. Wenn Sie genau hinsehen, können Sie erkennen, dass die Daten darin mit einem Index zwischen "0 ~ 7" geschrieben sind. Das ist in den Kommentaren leicht zu erkennen.
Der Typ des Arrays ist übrigens "Int16[]", es kann aber auch "short[]" (2 Bytes) sein. In einigen Fällen wird ein Array mit "int" (4 Bytes) erstellt, aber dies wird verwendet, wenn die Anzahl der Vertices "65535" überschreitet. Wenn die Anzahl der Scheitelpunkte diese Zahl nie überschreitet, erstellen Sie ein Array mit 2-Byte-Daten, um den Speicherverbrauch zu reduzieren.
Kreation
// 頂点の数
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);
Erstellen von Vertexpuffern. Ursprünglich ist es notwendig, 36 Eckpunkte zu erstellen, aber durch die Verwendung eines Indexpuffers müssen Sie nur 8 Eckpunkte erstellen.
// インデックスバッファを作成
this.indexBuffer = new IndexBuffer(this.GraphicsDevice,
IndexElementSize.SixteenBits, 3 * 12, BufferUsage.None);
// 頂点インデックスを書き込む
this.indexBuffer.SetData(vertexIndices);
Erstellen von Indexpuffern. Das zweite Argument gibt die Anzahl der Bits des Vertex-Index an, die geschrieben werden sollen. Da ein Index 2 Byte groß ist, geben Sie "IndexElementSize.SixteenBits" an.
Das dritte Argument ist die Anzahl der Indizes. In diesem Fall zeichnen wir 12 Polygone, also geben wir 36 an, was der Anzahl der Eckpunkte × Polygone der dreieckigen Polygone entspricht. Natürlich ist es kein Problem, wenn Sie die Anzahl der Elemente im Index-Array so angeben, wie sie ist, aber dieses Mal sind die Zahlen aus Gründen der Übersichtlichkeit absichtlich getrennt.
Da wir bereits ein Array von Vertex-Indizes mit Feldern erstellt haben, werden wir diese mit der Methode "IndexBuffer.SetData" schreiben.
IndexBuffer
Konstruktor
Erstellt eine Instanz der IndexBuffer-Klasse, die den Index verwaltet, der auf die Vertexdaten verweist.
Grafikgerät | Grafikgerät | Gibt das GraphicsDevice an, das dem Indexpuffer zugeordnet werden soll. |
indexElementSize | IndexElementSize | Die Größe eines einzelnen Vertex-Indexes. Geben Sie "SixteenBits" für 2 Bytes, "ThirtyTwoBits" für 4 Byte an, und geben Sie BufferUsage.None an. |
indexAnzahl | Int | Gibt die Anzahl der Indizes an. |
Verwendung | BufferUsage | Verwendung des Indexpuffers. Geben Sie BufferUsage.None an, sofern nicht anders angegeben. |
IndexBuffer.SetData
Methode
Kopieren Sie das Array der Vertex-Indizes in den Indexpuffer.
T | WertTyp | Typ des Vertexindex-Arrays |
Daten | T | Zu kopierendes Vertex-Index-Array |
Zeichnung
// インデックスバッファをセット
this.GraphicsDevice.Indices = this.indexBuffer;
Wenn Sie einen Indexpuffer verwenden möchten, legen Sie den Indexpuffer auf dem Gerät fest, bevor Sie das Polygon zeichnen.
// インデックスを使用してポリゴンを描画する
this.GraphicsDevice.DrawIndexedPrimitives(
PrimitiveType.TriangleList,
0,
0,
8,
0,
12
);
Wenn Sie Index- und Vertexpuffer verwenden, verwenden Sie die "GraphicsDevice.DrawIndexedPrimitives"-Methode, um Polygone zu zeichnen.
Das vierte Argument ist die Anzahl der erstellten Scheitelpunkte. Im Beispiel wird "8" angegeben, da 8 Scheitelpunktdaten gemeinsam genutzt werden.
Das sechste Argument gibt die Anzahl der Primitive an. Es ist "12", weil es 12 dreieckige Polygone zeichnet.
Für andere numerische Parameter ist 0 in Ordnung.
GraphicsDevice.DrawIndexedPrimitives
Methode
Zeichnet einen Grundkörper basierend auf dem angegebenen Vertex-Index und Vertex-Puffer.
primitiver Typ | Primitiver Typ | Gibt das zu zeichnende Grundelement an. |
baseVertex | Int | Der Offset, der jedem Vertexindex im Indexpuffer hinzugefügt werden soll. Wenn z. B. der erste Vertexindex auf Vertexdaten 2 verweist und in diesem Argument "1" angegeben ist, zeigt der erste Vertexindex auf Vertexdaten 3. |
minVertexIndex | Int | Der minimale Vertex-Index des Vertexes, der im Aufruf verwendet wird. Ein minVertexIndex von 1 erhöht z. B. den Index der Vertexdaten um 1 (die Anzahl der Puffer wird nicht erhöht, sodass das letzte Element der Vertexdaten nicht angegeben werden kann). Wenn der Vertexindex auf die zweiten Vertexdaten zeigt, verweist er auf die ersten Vertexdaten. |
numVertices | Int | Die Anzahl der verwendeten Vertex-Daten. |
startIndex | Int | Der Anfangsoffset des Vertex-Indexes. Wenn Sie z. B. TriangleList als primitiveType angeben, geben Sie "3, 6, 9,..." an, um die Polygone zu überspringen, die mit dem Zeichnen beginnen. Wenn Sie einen anderen Wert als die Zahl angeben, die durch 3 geteilt wird, wird das Modell ausgeblendet. (Da alle Indizes ausgeschaltet sind) |
primitiveCount | Int | Die Anzahl der zu zeichnenden Grundkörper. Der maximale Wert, der angegeben werden kann, ist "Anzahl der Vertex-Indizes÷ Anzahl der Vertices der Primitive - startIndex" |
Alle Codes
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);
}
}
}