Zobrazení rámečků pomocí indexačních bufferů
shrnutí
K vytvoření rámečku používám hodně polygonů. Přitom se používá vyrovnávací paměť indexu, která snižuje množství dat v datech vrcholů.
Provozní prostředí
Požadavky
Podporované verze XNA |
|
Podporované platformy |
|
Požadovaná verze Vertex Shader systému Windows | 2.0 |
Windows Požadovaná verze pixel shaderu | 2.0 |
Provozní prostředí
nástupiště |
|
hmota
O krabici
Krabice se skládá ze šesti ploch, z nichž jedna se skládá ze dvou trojúhelníkových mnohoúhelníků. To znamená, že celkový počet trojúhelníkových mnohoúhelníků je "2×6 = 12". Navíc, protože trojúhelníkový mnohoúhelník má tři vrcholy, celkový počet vrcholů je "12×3 = 36". Při tvorbě pouze s "VertexBufferem" je tedy možné jej zobrazit jako box, pokud si určíte informaci o pozici tak, aby 36 kusů dat bylo ve tvaru boxu a zapíšete ji. (Pro TriangleStrip je vyžadováno 24 znaků)
Ale představte si krabici. Rohů krabice je 8 kusů. Osm by mělo stačit pro informace o poloze. Se zvyšujícím se počtem dat vrcholů to vyvíjí tlak na paměť. Abychom to nějak snížili, používáme "IndexBuffer".
Potřebujete pouze 8 informací o poloze, ale pro mnohoúhelník potřebujete vždy 36 vrcholů. Účelem použití "IndexBuffer" je tedy sdílení dat o 8 vrcholech.
pole
<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枚目のポリゴン
};
Pole je deklarováno jako "IndexBuffer", ale pod ním je předem vytvořeno "pole čísel vrcholů". Toto pole vyhrazuje pole pro 36 vrcholů, ale význam každého čísla spočívá v tom, kolik dat vrcholů z osmi dat vrcholů každý trojúhelníkový mnohoúhelník používá. Pokud se podíváte pozorně, můžete vidět, že data uvnitř jsou zapsána s indexem mezi "0 ~ 7". Je to dobře vidět v komentářích.
Mimochodem, typ pole je "Int16[]", ale může být i "short[]" (2 bajty). V některých případech je pole vytvořeno s "int" (4 bajty), ale to se používá, když počet vrcholů překročí "65535". Pokud počet vrcholů nikdy nepřekročí toto číslo, vytvořte pole 2bajtových dat, abyste snížili spotřebu paměti.
vytvoření
// 頂点の数
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);
Vytváření vyrovnávacích pamětí vrcholů. Původně je nutné vytvořit 36 vrcholů, ale při použití indexbufferu stačí vytvořit pouze 8 vrcholů.
// インデックスバッファを作成
this.indexBuffer = new IndexBuffer(this.GraphicsDevice,
IndexElementSize.SixteenBits, 3 * 12, BufferUsage.None);
// 頂点インデックスを書き込む
this.indexBuffer.SetData(vertexIndices);
Vytváření vyrovnávacích pamětí indexů. Druhý argument určuje počet bitů indexu vrcholu, který má být zapsán. Protože jeden index má 2 bajty, zadejte "IndexElementSize.SixteenBits".
Třetím argumentem je počet indexů. V tomto případě nakreslíme 12 polygonů, takže zadejte 36, což je počet vrcholů × polygonů trojúhelníkových polygonů. Samozřejmě není problém, pokud zadáte počet prvků v indexovém poli tak, jak je, ale tentokrát jsou čísla pro přehlednost záměrně oddělena.
Protože jsme již vytvořili pole vrcholových indexů s poli, zapíšeme je metodou "IndexBuffer.SetData".
IndexBuffer
konstruktor
Vytvoří instanci třídy IndexBuffer, která spravuje index, který odkazuje na data vrcholů.
grafické zařízení | Grafické zařízení | Určuje objekt GraphicsDevice, který se má přidružit k vyrovnávací paměti indexu. |
indexElementSize | IndexElementSize | Velikost jednoho indexu vrcholu. Zadejte "SixteenBits" pro 2 bajty, "ThirtyTwoBits" pro 4 bajty a zadejte BufferUsage.None. |
Počet indexů | Int | Určuje počet indexů. |
zvyk | Využití vyrovnávací paměti | Využití vyrovnávací paměti indexu. Zadejte BufferUsage.None, pokud není uvedeno jinak. |
IndexBuffer.SetData
metoda
Zkopírujte pole indexů vrcholů do vyrovnávací paměti indexu.
T | Typ hodnoty | Typ pole indexu vrcholu |
data | T | Pole indexů vrcholů, které se má zkopírovat |
kreslení
// インデックスバッファをセット
this.GraphicsDevice.Indices = this.indexBuffer;
Pokud chcete použít indexovou vyrovnávací paměť, nastavte indexovou vyrovnávací paměť na zařízení před kreslením mnohoúhelníku.
// インデックスを使用してポリゴンを描画する
this.GraphicsDevice.DrawIndexedPrimitives(
PrimitiveType.TriangleList,
0,
0,
8,
0,
12
);
Pokud používáte vyrovnávací paměti indexů a vrcholů, použijte ke kreslení mnohoúhelníků metodu "GraphicsDevice.DrawIndexedPrimitives".
Čtvrtým argumentem je počet vytvořených vrcholů. V ukázce je zadána hodnota "8", protože jsou sdílena data 8 vrcholů.
Šestý argument určuje počet primitiv. Je to "12", protože kreslí 12 trojúhelníkových mnohoúhelníků.
U ostatních číselných parametrů je 0 v pořádku.
GraphicsDevice.DrawIndexedPrimitives
metoda
Nakreslí základní díl na základě určeného indexu vrcholu a vyrovnávací paměti vrcholů.
primitivType | PrimitivType | Určuje základní objekt, který se má nakreslit. |
Základní vrchol | Int | Odsazení, které se má přidat ke každému indexu vrcholu ve vyrovnávací paměti indexu. Pokud například první index vrcholu odkazuje na data vrcholu 2, pokud je v tomto argumentu zadáno "1", bude první index vrcholu odkazovat na data vrcholu 3. |
minVertexIndex | Int | Minimální index vrcholu vrcholu použitého ve volání. Například hodnota minVertexIndex 1 zvýší index dat vrcholů o 1 (nezvýší počet vyrovnávacích pamětí, takže nelze určit poslední prvek dat vrcholu). Pokud index vrcholu odkazuje na data druhého vrcholu, bude odkazovat na data prvního vrcholu. |
numVertices | Int | Počet použitých dat vrcholů. |
StartIndex | Int | Počáteční odsazení indexu vrcholu. Pokud například určíte TriangleList jako primitiveType, zadejte "3, 6, 9,...", abyste přeskočili polygony, které začínají kreslit. Pokud zadáte jinou hodnotu než číslo dělené 3, model se zhroutí. (Protože všechny indexy jsou vypnuté.) |
primitiveCount | Int | Počet primitiv, která se mají nakreslit. Maximální hodnota, kterou lze zadat, je "Počet indexů vrcholů÷ Počet vrcholů primitiv - startIndex" |
Všechny kódy
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);
}
}
}