頂点バッファを使用した2Dポリゴン

Page updated :

The page you are currently viewing does not support the selected display language.

表示される内容は前回とほとんど同じですが、今回はポリゴンを表示するのに頂点バッファというものを使用しています。

頂点バッファを使用した2Dポリゴン

今回のメインコードファイルを載せます。

MainSample.cs

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;

namespace MDXSample
{
    /// <summary>
    /// メインサンプルクラス
    /// </summary>
    public partial class MainSample : IDisposable
    {
        /// <summary>
        /// 頂点バッファ
        /// </summary>
        private VertexBuffer _vertexBuffer = null;


        /// <summary>
        /// アプリケーションの初期化
        /// </summary>
        /// <param name="topLevelForm">トップレベルウインドウ</param>
        /// <returns>全ての初期化がOKなら true, ひとつでも失敗したら false を返すようにする</returns>
        /// <remarks>
        /// false を返した場合は、自動的にアプリケーションが終了するようになっている
        /// </remarks>
        public bool InitializeApplication(MainForm topLevelForm)
        {
            // フォームの参照を保持
            this._form = topLevelForm;

            try
            {
                // Direct3D デバイス作成
                this.CreateDevice(topLevelForm);

                // フォントの作成
                this.CreateFont();
            }
            catch (DirectXException ex)
            {
                // 例外発生
                MessageBox.Show(ex.ToString(), "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return false;
            }

            // 三角形ポリゴンを表示するための頂点バッファを作成
            this._vertexBuffer = new VertexBuffer(typeof(CustomVertex.TransformedColored),
                3, this._device, Usage.None, CustomVertex.TransformedColored.Format, Pool.Managed);

            // 3点の情報を格納するためのメモリを確保
            CustomVertex.TransformedColored[] vertices = new CustomVertex.TransformedColored[3];

            // 各頂点を設定
            vertices[0] = new CustomVertex.TransformedColored(
                200.0f, 50.0f, 0.0f, 1.0f, Color.Red.ToArgb());
            vertices[1] = new CustomVertex.TransformedColored(
                350.0f, 50.0f + 150.0f * (float)Math.Sqrt(3), 0.0f, 1.0f, Color.Blue.ToArgb());
            vertices[2] = new CustomVertex.TransformedColored(
                50.0f, 50.0f + 150.0f * (float)Math.Sqrt(3), 0.0f, 1.0f, Color.Green.ToArgb());

            // 頂点バッファをロックする
            using (GraphicsStream data = this._vertexBuffer.Lock(0, 0, LockFlags.None))
            {
                // 頂点データを頂点バッファに書き込みます
                data.Write(vertices);

                // 頂点バッファのロックを解除します
                this._vertexBuffer.Unlock();
            }

            return true;
        }

        /// <summary>
        /// メインループ処理
        /// </summary>
        public void MainLoop()
        {
            // 描画内容を単色でクリア
            this._device.Clear(ClearFlags.Target, Color.DarkBlue, 1.0f, 0);

            // 「BeginScene」と「EndScene」の間に描画内容を記述する
            this._device.BeginScene();


            // 頂点バッファをデバイスのデータストリームにバインド
            this._device.SetStreamSource(0, this._vertexBuffer, 0);

            // 描画する頂点のフォーマットをセット
            this._device.VertexFormat = CustomVertex.TransformedColored.Format;

            // レンダリング(描画)
            this._device.DrawPrimitives(PrimitiveType.TriangleList, 0, 1);


            // 文字列の描画
            this._font.DrawText(null, "頂点バッファを使用した2Dポリゴン表示", 0, 0, Color.White);

            // 描画はここまで
            this._device.EndScene();

            // 実際のディスプレイに描画
            this._device.Present();
        }

        /// <summary>
        /// リソースの破棄をするために呼ばれる
        /// </summary>
        public void Dispose()
        {
            // 頂点バッファを解放
            if (this._vertexBuffer != null)
            {
                this._vertexBuffer.Dispose();
            }

            // フォントのリソースを解放
            if (this._font != null)
            {
                this._font.Dispose();
            }

            // Direct3D デバイスのリソース解放
            if (this._device != null)
            {
                this._device.Dispose();
            }
        }
    }
}
MainSamplePartial.cs ファイルのコードはこちらです。

MainSamplePartial.cs

>using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;

namespace MDXSample
{
    public partial class MainSample
    {
        /// <summary>
        /// メインフォーム
        /// </summary>
        private MainForm _form = null;

        /// <summary>
        /// Direct3D デバイス
        /// </summary>
        private Device _device = null;

        /// <summary>
        /// Direct3D 用フォント
        /// </summary>
        private Microsoft.DirectX.Direct3D.Font _font = null;


        /// <summary>
        /// Direct3D デバイスの作成
        /// </summary>
        /// <param name="topLevelForm">トップレベルウインドウ</param>
        private void CreateDevice(MainForm topLevelForm)
        {
            // PresentParameters。デバイスを作成する際に必須
            // どのような環境でデバイスを使用するかを設定する
            PresentParameters pp = new PresentParameters();

            // ウインドウモードなら true、フルスクリーンモードなら false を指定
            pp.Windowed = true;

            // スワップ効果。とりあえず「Discard」を指定。
            pp.SwapEffect = SwapEffect.Discard;

            try
            {
                // デバイスの作成
                this.CreateDevice(topLevelForm, pp);
            }
            catch (DirectXException ex)
            {
                // 例外発生
                throw ex;
            }
        }
        /// <summary>
        /// Direct3D デバイスの作成
        /// </summary>
        /// <param name="topLevelForm">トップレベルウインドウ</param>
        /// <param name="presentationParameters">PresentParameters 構造体</param>
        private void CreateDevice(MainForm topLevelForm, PresentParameters presentationParameters)
        {
            // 実際にデバイスを作成します。
            // 常に最高のパフォーマンスで作成を試み、
            // 失敗したら下位パフォーマンスで作成するようにしている。
            try
            {
                // ハードウェアによる頂点処理、ラスタライズを行う
                // 最高のパフォーマンスで処理を行えます。
                // ビデオカードによっては実装できない処理が存在します。
                this._device = new Device(0, DeviceType.Hardware, topLevelForm.Handle,
                    CreateFlags.HardwareVertexProcessing, presentationParameters);
            }
            catch (DirectXException ex1)
            {
                // 作成に失敗
                Debug.WriteLine(ex1.ToString());
                try
                {
                    // ソフトウェアによる頂点処理、ハードウェアによるラスタライズを行う
                    this._device = new Device(0, DeviceType.Hardware, topLevelForm.Handle,
                        CreateFlags.SoftwareVertexProcessing, presentationParameters);
                }
                catch (DirectXException ex2)
                {
                    // 作成に失敗
                    Debug.WriteLine(ex2.ToString());
                    try
                    {
                        // ソフトウェアによる頂点処理、ラスタライズを行う
                        // パフォーマンスはとても低いです。
                        // その代わり、ほとんどの処理を制限なく行えます。
                        this._device = new Device(0, DeviceType.Reference, topLevelForm.Handle,
                            CreateFlags.SoftwareVertexProcessing, presentationParameters);
                    }
                    catch (DirectXException ex3)
                    {
                        // 作成に失敗
                        // 事実上デバイスは作成できません。
                        throw ex3;
                    }
                }
            }
        }

        /// <summary>
        /// フォントの作成
        /// </summary>
        private void CreateFont()
        {
            try
            {
                // フォントデータの構造体を作成
                FontDescription fd = new FontDescription();

                // 構造体に必要なデータをセット
                fd.Height = 12;
                fd.FaceName = "MS ゴシック";

                // フォントを作成
                this._font = new Microsoft.DirectX.Direct3D.Font(this._device, fd);
            }
            catch (DirectXException ex)
            {
                // 例外発生
                throw ex;
            }
        }
    }
}

/// <summary>
/// 頂点バッファ
/// </summary>
private VertexBuffer _vertexBuffer = null;

前回はポリゴンを表示する際に頂点データを描画時に直接転送していました。しかし、この方法は毎回データを送らないといけないため、処理に時間がかかってしまう可能性があります。

そこで今回は頂点バッファと言うものを使用してポリゴンを描画します。頂点バッファを使用すると頂点データをビデオメモリに配置することができ、描画時のパフォーマンスがよくなります。特に3Dモデルなど頂点数が多い場合にその効果は大きいです。

頂点バッファを使用するには「VertexBuffer」クラスを使用するので宣言しておきます。


// 三角形ポリゴンを表示するための頂点バッファを作成
this._vertexBuffer = new VertexBuffer(typeof(CustomVertex.TransformedColored),
    3, this._device, Usage.None, CustomVertex.TransformedColored.Format, Pool.Managed);

ポリゴンの作成ですが、まず頂点バッファを作成します。使用するパラメータは下の通りです。また、前回とまったく同じポリゴンを作成するので、頂点データに使う構造体や各頂点データのパラメータについての説明は省きます。

VertexBuffer コンストラクタ

ポリゴンを表示するための頂点バッファを作成
typeVertexType 使用する頂点データ構造体のタイプクラスを指定します。「typeof」を使用してクラスを指定するとType クラスに変換されるので、それを使用します。
numVerts 頂点の数です。三角形ポリゴンひとつなので 3 を渡します。
device Direct3D デバイスを渡します。
usage 使用法。特に無ければ「Usage.None」でいいです。
vertexFormat 使用する頂点データ構造体の頂点フォーマットを指定します。
pool リソースを配置する有効なメモリ クラスの指定。特に無ければ「Pool.Managed」でよい。

// 3点の情報を格納するためのメモリを確保
CustomVertex.TransformedColored[] vertices = new CustomVertex.TransformedColored[3];

// 各頂点を設定
vertices[0] = new CustomVertex.TransformedColored(
    200.0f, 50.0f, 0.0f, 1.0f, Color.Red.ToArgb());
vertices[1] = new CustomVertex.TransformedColored(
    350.0f, 50.0f + 150.0f * (float)Math.Sqrt(3), 0.0f, 1.0f, Color.Blue.ToArgb());
vertices[2] = new CustomVertex.TransformedColored(
    50.0f, 50.0f + 150.0f * (float)Math.Sqrt(3), 0.0f, 1.0f, Color.Green.ToArgb());

頂点バッファを作成したら、頂点バッファにセットするための頂点データを作成します。パラメータは前回と同じです。


// 頂点バッファをロックする
using (GraphicsStream data = this._vertexBuffer.Lock(0, 0, LockFlags.None))
{
    // 頂点データを頂点バッファにコピーします
    data.Write(vertices);

    // 頂点バッファをロック解除します
    this._vertexBuffer.Unlock();
}

頂点データを作成したら、頂点バッファに書き込みます。頂点バッファに書き込むときは必ずメモリをロックする必要があります。上記の引数で「Lock」メソッドを使用すると、ロックされた頂点バッファを取得できるので、「Write」メソッドで作成した頂点データを書き込みます。「Lock」メソッドの引数は特に何もなければこのままでいいです。その後、頂点バッファのロックを解除します。必ず「Lock」と「Unlock」の数は一致させる必要があります。そうでないと描画する際に失敗してしまいます。

GraphicsStream は using を使用して明示的に破棄していますが、必ずしも必要ありません。


// 頂点バッファをデバイスのデータストリームにバインド
this._device.SetStreamSource(0, this._vertexBuffer, 0);

// 描画する頂点のフォーマットをセット
this._device.VertexFormat = CustomVertex.TransformedColored.Format;

// レンダリング(描画)
this._device.DrawPrimitives(PrimitiveType.TriangleList, 0, 1);

描画部分です。前回より1行分増えています。

まず「Device.SetStreamSource」メソッドで使用する頂点バッファを指定します。引数に関しては特に無ければこのままでいいでしょう。

次に前回と同じく頂点データのフォーマットを指定します。

最後にポリゴンを描画しますが、前回と違うメソッドを使用しています。しかし、さほど大きな違いは無いです。

Device.DrawPrimitives メソッド

指定した頂点バッファでポリゴンを描画します。
primitiveType レンダリングするプリミティブのタイプを指定します。PrimitiveType 列挙型から指定します。今回は三角形ひとつなので「PrimitiveType.TriangleList」を指定しています。
startVertex 読み込む最初の頂点のインデックスです。通常 0。
primitiveCount レンダリングするプリミティブの数です。今回は三角形ひとつなので「1」を指定。

// 頂点バッファを解放
if (this._vertexBuffer != null)
{
    this._vertexBuffer.Dispose();
}

作成した頂点バッファを破棄しています。