頂点バッファ (Vertex Buffers)

頂点バッファとは頂点データを格納するバッファです。

作成

作成方法には、おもに次のようなものがあります。

1.頂点バッファのサイズを指定

public VertexBuffer(
    Device device,               // 頂点バッファを作成するのに使用するデバイス
    int sizeOfBufferInBytes,     // 頂点バッファのサイズ
    Usage usage,                 // 頂点バッファの使用方法
    VertexFormats vertexFormat,  // バッファに格納される頂点のフォーマット
    Pool pool                    // 頂点バッファの配置されるメモリプールの定義
);

2.頂点の種類と頂点の最大数を指定

public VertexBuffer(
    Type typeVertexType,         // 頂点の種類
    int numVerts,                // 頂点の最大数
    Device device,               // 頂点バッファを作成するのに使用するデバイス
    Usage usage,                 // 頂点バッファの使用方法
    VertexFormats vertexFormat,  // バッファに格納される頂点のフォーマット
    Pool pool                    // 頂点バッファの配置されるメモリプールの定義
);

頂点の種類を表すtypeVertexTypeには、CustomVertex構造体の型をtypeof演算子などで取得して指定します。

頂点データの格納

VertexBuffer.SetData()メソッドにより、頂点データをロックして頂点バッファへの参照を取得できます。

public void SetData(
    object data,       // 頂点データ
    int lockAtOffset,  // 頂点データから参照するときのオフセット
    LockFlags flags    // データ書き込み時にバッファをロックする方法
);
LockFlags列挙型 (一部)
列挙子 説明
None バッファに対する読み取りと書き込みを許可する (ロックしない)。
Discard※1 ロックされている領域を書き込み専用で上書きする。
NoOverwrite※1 バッファのデータを上書きしない。
NoDirtyUpdate リソースのダーティー状態が変更されないようにする。
NoSystemLock  
ReadOnly バッファに書き込まない。
LockFlags 列挙型 | MSDN ※1 Discard、NoOverwriteは頂点バッファの使用方法 (コンストラクタのusage引数) でDynamicを指定している場合のみ有効

サンプルコード

ウィンドウがリサイズされるとデバイスがリセットされ、頂点バッファは破棄されます。よってそのときにはCreatedイベントで再作成する必要があります。ですので頂点バッファを作成するときには、最初からそのイベントハンドラを呼び出すようにすると良いでしょう。

VertexBuffer vertexBuffer = null;

// 頂点バッファを初期化
private InitVertexBuffer()
{
    vertexBuffer = new VertexBuffer(
        typeof( CustomVertex.PositionColored ),  // 頂点の種類
        2,                                       // 頂点の最大数
        device,                                  // 頂点バッファを作成するのに使用するデバイス
        0,                                       // 頂点バッファの使用方法
        CustomVertex.PositionColored.Format,     // バッファに格納される頂点のフォーマット
        Pool.Default                             // 頂点バッファの配置されるメモリプールの定
        );

    // イベントハンドラを登録
    vertexBuffer.Created += new EventHandler( vertexBuffer_Created );

    vertexBuffer_Created( vertexBuffer, null );
}

// 頂点バッファを作成
private void vertexBuffer_Created( object sender, EventArgs e )
{
    // 頂点データの作成
    CustomVertex.PositionColored[] vertex = new CustomVertex.PositionColored[ 2 ];

    vertex[ 0 ].Position = new Vector3( 0.0f, 0.0f, 0.0f );
    vertex[ 1 ].Position = new Vector3( 1.0f, 0.0f, 0.0f );

    vertex[ 0 ].Color = Color.Red.ToArgb();
    vertex[ 1 ].Color = Color.Red.ToArgb();

    // 頂点データを頂点バッファに格納
    vertexBuffer.SetData( vertex, 0, LockFlags.None );
}

Lock、Unlock

1. 頂点データをロックして、頂点バッファのGraphicsStreamを取得する。

public GraphicsStream Lock(
    int offsetToLock,  // 頂点データから参照するときのオフセット
    int sizeToLock,    // ロックする頂点データのバイト数
    LockFlags flags    // バッファをロックする方法
);

2. 現在のストリームに頂点データを書き込む

public override void Write(
    Array value   // ストリーム バッファへ書き込むデータを格納した配列
);

3. 頂点データのロックの解除

public void Unlock();

サンプルコード

CustomVertex.PositionColored[] vertex = new CustomVertex.PositionColored[ 2 ];

vertex[ 0 ].Position = new Vector3( 0.0f, 0.0f, 0.0f );
vertex[ 1 ].Position = new Vector3( 1.0f, 0.0f, 0.0f );


// 頂点データの範囲をロックし、頂点バッファ メモリを取得する
GraphicsStream graphicsStream = vertexBuffer.Lock( 0, 0, LockFlags.None );

// 現在のストリームに書き込み、書き込んだバイト数分ストリーム内の位置を先に進める
graphicsStream.Write( vertex );

// 頂点データのロックを解除する
vertexBuffer.Unlock();

または、

// 頂点データの範囲をロックし、頂点バッファ メモリを取得する
CustomVertex.PositionColored[] vertex
    = ( CustomVertex.PositionColored[] )vertexBuffer.Lock( 0, LockFlags.None );

vertex[ 0 ].Position = new Vector3( 0.0f, 0.0f, 0.0f );
vertex[ 1 ].Position = new Vector3( 1.0f, 0.0f, 0.0f );

// 頂点データのロックを解除する
vertexBuffer.Unlock();

描画

頂点バッファのデータは、次の手順により描画を実行します。

  1. SetStreamSourceにより、頂点バッファをデバイスのデータストリームにバインド
  2. デバイスのVertexFormatプロパティで頂点形式を指定
  3. DrawPrimitivesでデータストリームから読み込んで描画

1.データストリームへのバインド

public void SetStreamSource(
    int streamNumber,         // データストリームの数
    VertexBuffer streamData,  // 頂点バッファ オブジェクト
    int offsetInBytes         // ストリームの頂点ストライド
);

点バッファをデバイスのデータストリームにバインドします。これにより頂点データと、プリミティブ処理関数にデータを供給するデータストリームポートの1つを関連付けます。

2.頂点形式の設定

public VertexFormats VertexFormat { get; }

CustomVertex構造体のメンバから頂点形式を取得して、デバイスに設定します。

3.データストリームからの描画

public void DrawPrimitives(
    PrimitiveType primitiveType,  // 描画するプリミティブの種類
    int startVertex,              // データストリームからの読み出し開始位置
    int primitiveCount            // 描画するプリミティブの数
);

サンプルコード

// 描画処理
private void Draw()
{
    // データストリームへのバインド
    device.SetStreamSource( 0, vertexBuffer, 0 );

    // 頂点形式の設定
    device.VertexFormat = vertexBuffer.Description.VertexFormat;

    // データストリームからの描画
    device.DrawPrimitives( PrimitiveType.LineList, 0, 1 );
}