2Dポリゴンの表示

תאריך יצירת דף :

הדף שאתה מציג כעת אינו תומך בשפת התצוגה שנבחרה.

Direct3D なので3Dをやるべきなのですが、ちょっと説明することが多くなってしまうので、最初は認識しやすい2Dポリゴンを使って説明します。

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 CustomVertex.TransformedColored[] _vertices = new CustomVertex.TransformedColored[3];


        /// <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._vertices[0] = new CustomVertex.TransformedColored(
                200.0f, 50.0f, 0.0f, 1.0f, Color.Red.ToArgb());
            this._vertices[1] = new CustomVertex.TransformedColored(
                350.0f, 50.0f + 150.0f * (float)Math.Sqrt(3), 0.0f, 1.0f, Color.Blue.ToArgb());
            this._vertices[2] = new CustomVertex.TransformedColored(
                50.0f, 50.0f + 150.0f * (float)Math.Sqrt(3), 0.0f, 1.0f, Color.Green.ToArgb());

            return true;
        }

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

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


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

            // 描画
            this._device.DrawUserPrimitives(PrimitiveType.TriangleList, 1, this._vertices);


            // 文字列の描画
            this._font.DrawText(null, "2Dポリゴン表示", 0, 0, Color.White);


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

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

        /// <summary>
        /// リソースの破棄をするために呼ばれる
        /// </summary>
        public void 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;
            }
        }
    }
}

まず最初にポリゴンについて簡単に説明します。詳しいことはヘルプや書籍を参考にしてください。

ポリゴンはトップの画像を見てもらうとおり、3Dの三角形の面のことです(今回は2Dですが)。3D上でよくモデルが動くシーンなどを見かけることが多いですが、あれは非常に多くのポリゴンを組み合わせて形作っているのです。この三角形ポリゴンを構成するには頂点データというものが必要です。頂点データには位置や色など複数のデータを持たせることでポリゴンを実現させています。

ポリゴン

上でポリゴンは三角形と言いましたが、四角形や多角形もポリゴンといいます。でも大抵の場合最小単位のポリゴンは三角形です。


/// <summary>
/// 座標変換済み頂点データ
/// </summary>
private CustomVertex.TransformedColored[] _vertices = new CustomVertex.TransformedColored[3];

上記で説明したとおり、ポリゴンを成り立たせるには頂点データが必要なので、それを持つデータを定義しなければなりません。大抵ひとつの頂点には複数のデータを持たせることが多いので構造体で定義することが多いです。

しかし、Managed DirectX では一般的に使われる頂点データの型はすでに定義されていることが多いです。今回使用する「CustomVertex.TransformedColored」もそのうちのひとつで、座標変換済み頂点データとして使われます。

座標変換済み頂点データというなにやら難しい言葉が出てきましたが、今は深く考える必要はありません。簡単に言い直せば2Dのポリゴンを表示させるのに使えるということが分かればいいです。逆にこの構造体は3D空間上では使用できません。

CustomVertex.TransformedColored は下のようなデータを持っています。

CustomVertex.TransformedColored 構造体

X スクリーン座標での位置X
Y スクリーン座標での位置Y
Z 深度値。通常 0.0 ~ 1.0
Rhw 同次 w の逆数。通常 1.0
Color 頂点の色

今回は三角形ポリゴンをひとつだけ表示するので、三角形に必要な頂点3つ分の構造体を作成します。


// フォントの作成
this.CreateFont();

フォントの作成をメソッドにまとめました。


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

ここで3つ頂点データを設定しています。各パラメータは上にある表の通りですが、簡単に説明します。

CustomVertex.TransformedColored コンストラクタ

CustomVertex.TransformedColored 構造体を作成
xvalue そのままスクリーン座標での位置Xになります。一番左が 0 で右に行くほど大きくなります。
yvalue そのままスクリーン座標での位置Yになります。一番上が 0 で下に行くほど大きくなります。
zvalue 深度値ですが今回関係ないので 0.0f でいいです。
rhwvalue 同次 w の逆数という分かりにくい表現ですが、気にせず 1.0f でいいです。
c 頂点の色。頂点と頂点の間の色は綺麗に線形補間されます。

位置指定で Math.Sqrt という平方根を使用していますが、綺麗な正三角形になるように計算しているだけなのであまり気にしないでください。

色を指定するのに「Color」構造体で定義されている色を使用していますが、「int」に変換しないといけないので「Color.ToArgb」メソッドを使用して変換してます。


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

// 描画
this._device.DrawUserPrimitives(PrimitiveType.TriangleList, 1, this._vertices);

ようやくメインループの描画部分です。ここでは上の2行を使って描画しています。

まず最初にデバイスにどのような頂点データを使用するかを示さなければなりません。これには Device.VertexFormat に柔軟な頂点フォーマットを指定します。これは CustomVertex.TransformedColored.Format ですでに定義されているのでそれを渡しています。

次にポリゴンのレンダリングを行います。各引数の意味は下のとおりです。ちなみに描画とレンダリングはほとんど同じ意味で使用されます。

Device.DrawUserPrimitives メソッド

指定した頂点データでポリゴンを描画します。
primitiveType レンダリングするプリミティブのタイプを指定します。プリミティブとは点や線、面のことで、PrimitiveType 列挙型から指定します。今回は三角形ひとつなので「PrimitiveType.TriangleList」を指定しています。
primitiveCount レンダリングするプリミティブの数です。今回は三角形ひとつなので「1」を指定。
vertexStreamZeroData 使用するユーザーメモリ頂点データ。作成した頂点データを渡します。

ちなみに「PrimitiveType」を図で表す下のようになります。

PrimitiveType
※この図は表裏関係を考慮していません。あくまでもイメージです。