[Atelier Blue アトリエブルー]HomeプログラミングManaged DirectX3D>三角形を描く

三角形を描く

それでは早速本当の描画に入りましょう。と言うわけで3Dでも良いんですが、とりあえずは、2Dっぽい3Dをしましょう。

Vertex

Vertexの意味を知っているでしょうか?日本語に訳すと「頂点」という意味なのです。

ここでちょっと問題です。0次元の世界にあるのはなんでしょう?

A. 簡単。「点」ですね。

では1次元に存在するのはなんでしょう?

A. 「点」と「線」です。

二次元では何が存在するでしょう?

A. 「点」と「線」と「面」ですね。

では3次元では?

A. 「点」と「線」と「面」と「立体」の四つですね。

(すいません。この考え方、実は自信ないです)



では次。点と点を繋げると何が出来るでしょうか?

A. 答えは「線」です。

では線と線を繋げると何が出来るでしょうか?

A. 答えは面です。

では面と面を繋げると何が出来るでしょうか?

A. 立体です。

立体は3次元ですね。つまり

「点を繋げれば線でも面でも立体でも作る事が出来る」

と言う事が言いたかったのです。

CustomVertex.TransformedColored

と、ひとしきり頭を柔らかくしたところで本題に入ります。Direct3Dでは頂点を繋げる事によって、「線」や「面」や「立体」を表します。

冒頭でもいったように頂点は英語で「Vertex」です。つまり「Vertex(今回はその中でもCustomVertexを利用します)」を使ってDirect3Dに面や立体の形を伝えるのです。

よし、これで表示できると思った方々もうちょっとお待ち下さい。Direct3Dには表示する対象であるオブジェクトの他にもう一つ重要な物があるのです。それはカメラです。

3Dのゲームをした事があれば分かると思いますが、3Dでは視点変更を自由に行う事が来ます。つまり、オブジェクトをどの視点から見るのかを決めなければ描画を行う事ができないのです。(かっこよく言うと「画が決まらない」のです)

ですが、ゲームのスコアなどのように、カメラが何処を向いていても同じ場所に表示されて欲しいオブジェクトもありますよね?

というわけでやっと登場です。Transformed(変形させられた)頂点これこそが、カメラが何処を向いていようとも同じ場所に表示を行う事が出来る頂点データなのです。

後半のColoredは色が付けられるという事だけなので今回はあまり重要でありません。

ソースコード

using System;
using System.Drawing;
using System.Windows.Forms;
using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;

namespace Project1
{
    /// <summary>
    /// md3d1 の概要の説明です。
    /// </summary>
    public class MD3D1:Form
    {
        //クライアント領域のサイズ
        const int clientHeight =600;
        const int clientWight =800;

        public MD3D1():base()
        {
            //最小サイズを設定
            this.MinimumSize = new Size(60,60);

            //下は任意です。
            //クライアント領域サイズ
            this.ClientSize =new Size(clientWight,clientHeight);
            //ウィンドウの名前(かっこいいのを付けてあげてください)
            this.Text ="Direct3D-My";
        }

        private Device device_;

        /// <summary>
        /// Direct3Dの初期化を行います。
        /// </summary>
        /// <returns>初期化が成功したかどうか</returns>
        public bool DXInitialize()
        {
            try
            {
                //プレゼンテーションパラメータを作成
                PresentParameters pp = new PresentParameters();

                //ウィンドウモード
                pp.Windowed =true;

                //スワップエフェクトを設定。
                pp.SwapEffect = SwapEffect.Discard;

                //デバイスを作成
                device_ = new Device(0,DeviceType.Hardware,this
                    ,CreateFlags.HardwareVertexProcessing,pp);

                //#################################################追加
                //頂点バッファを作成
                this.creatVertex();
                //#################################################ここまで
                //初期化成功
                return true;
            }
            catch
            {
                //初期化失敗
                return false;
            }

        }

        //#################################################追加
        /// <summary>
        /// 頂点バッファ
        /// </summary>
        private VertexBuffer vertexBuffer_;

        /// <summary>
        /// 頂点バッファ作成関数
        /// </summary>
        private void creatVertex()
        {
            //頂点バッファ領域を確保
            vertexBuffer_ = new VertexBuffer(
                typeof(CustomVertex.TransformedColored), 3, device_, 0
                , CustomVertex.TransformedColored.Format, Pool.Managed);

            //バッファをロック
            GraphicsStream stm = vertexBuffer_.Lock(0,0,0);

            //頂点データの配列を作成
            CustomVertex.TransformedColored[] verts
                = new CustomVertex.TransformedColored[3];

            //頂点データ
            verts[0].X=150;verts[0].Y=50;verts[0].Z=0.5f; verts[0].Rhw=1;
            verts[0].Color = System.Drawing.Color.Aqua.ToArgb();
            verts[1].X=250;verts[1].Y=250;verts[1].Z=0.5f;verts[1].Rhw=1;
            verts[1].Color = System.Drawing.Color.Brown.ToArgb();
            verts[2].X=50;verts[2].Y=250;verts[2].Z=0.5f; verts[2].Rhw=1;
            verts[2].Color = System.Drawing.Color.LightPink.ToArgb();


            //頂点データをバッファに書き込み
            stm.Write(verts);

            //バッファのロックを解除
            vertexBuffer_.Unlock();
        }
        //#################################################ここまで

        public void Render()
        {
            if(device_==null)return;
            if(this.WindowState ==FormWindowState.Minimized)return;

            //クリア処理
            device_.Clear(ClearFlags.Target,Color.Blue,1.0f,0);

            //描画開始
            device_.BeginScene();

            //#################################################追加

            //頂点バッファをセット
            device_.SetStreamSource(0,vertexBuffer_,0);
            //頂点バッファのフォーマットをセット
            device_.VertexFormat = CustomVertex.TransformedColored.Format;
            //描画
            device_.DrawPrimitives(PrimitiveType.TriangleList,0,1);

            //#################################################ここまで

            //描画終わり
            device_.EndScene();

            //更新
            device_.Present();
        }
    }

    /// <summary>
    /// エントリクラス
    /// </summary>
    class Program
    {
        public static void Main()
        {
            using(MD3D1 dxform =new MD3D1())
            {
                //Direct3Dの初期化を実行
                if(!dxform.DXInitialize())
                {
                    MessageBox.Show("Direct3Dの初期化に失敗しました。"
                        ,"初期化の失敗");
                    return;
                }

                //ウィンドウを表示
                dxform.Show();

                //メッセージループ
                //フォームがある間だけまわるようにする
                while(dxform.Created)
                {
                    //描画する
                    dxform.Render();
                    //たまっているメッセージを処理する
                    Application.DoEvents();
                }
            }
        }
    }
}

ごめんなさい、長いです。

頂点バッファの作り方

頂点バッファの作り方は下のような感じです。

  1. 頂点バッファを用意する
  2. 頂点データを用意する
  3. 頂点バッファをロックし、頂点データを書き込む

それでは1つ1つ説明していきます。

VertexBuffer

public VertexBuffer(
    Type typeVertexType,
    int numVerts,
    Device device,
    Usage usage,
    VertexFormats vertexFormat,
    Pool pool
);

Type typeVertexType

Vertexのタイプを指定します。つまり、typeofです。

int numVerts

頂点の数です。使う数の分だけ指定してください。あんまり大きいとエラーを起こされるかもしれません。

Device device

デバイスを指定してください。

Usage usage

仕様用途を設定します。これを設定するとDirect3Dでの最適化などに影響があります。特に設定しなくても良いので、通常は「0」で良いようです。

VertexFormats vertexFormat

頂点バッファのフォーマットを指定します。

Pool pool

データの管理の仕方を指定します。とりあえずは「Managed」にしておいてください。自動管理

VertexBuffer.Lock()

public GraphicsStream Lock(
    int offsetToLock,
    int sizeToLock,
    LockFlags flags
);

頂点データをロックし、CPUがデータを操作できるようにします。

int offsetToLock

ロックを始める位置を指定する。バッファ全体をロックするときには「0」を指定する。

int sizeToLock

ロックする大きさを指定する。バッファ全体をロックするときには「0」を指定する。

LockFlags flags

とりあえず「0」を指定する。

頂点データを作る

今回利用した頂点データに含まれるデータは次の通りです。

とりあえず「x」「y」はそのまま座標に対応します。

「z」は「0.0f ~ 1.0f」の間に指定しておけば間違いないです。「0」にすると一番近くになり「1」にすると一番遠くなります。(ここでの近さ遠さは前後の判定に使うものです)

「Color」はColor構造体ではありません。int型です。そのため、「ToArgb()」メソッドを利用して型を変換しています。

「Rhw」については同次座標についての知識が必要になります。今回は「1」を指定しておいてください。

GraphicsStream.Write()

これを実行する事によって、LockしたVertexBufferへデータを書き込みできます。

VertexBuffer.Unlock()

ロックしたVertexBufferをロック解除状態にします。それだけです。


描画を行う

描画を行います。そのためには次の三つの動作を行わなければなりません。

  1. 頂点バッファを渡す
  2. 補助情報を渡す
  3. 描画命令を出す

簡単ですね。1つ注意をしなければならないのは何処で呼び出しを行うかです。これらは全て描画処理にはいるので「BeginScene」と「EndScine」の間に書いてください

Device.SetStraemSource

頂点バッファを描画のためにDirect3Dに渡すためのメソッドです。

public void SetStreamSource(
    int streamNumber,
    VertexBuffer streamData,
    int offsetInBytes
);

int streamNumber

Direct3Dには頂点の受け皿となる頂点ストリームと呼ばれる物がいくつかあります。Direct3Dはセットされた頂点ストリームからデータを取り出して、オブジェクトを描画します。今回はとりあえず0番のストリームを指定しておきましょう。複数のストリームを使う方法はまた後ほど。

VertexBuffer streamData

頂点バッファをセットしてください。

int offsetInBytes

頂点バッファの何番目からをセットするかを決めます。全部描画したいときは0番を指定します。

Device.VertexFormat

プロパティです。頂点バッファのフォーマットを教えてあげる必要があります。素直に教えましょう。

Device.DrawPrimitives()

「Primitives」日本語に訳すとなんでしょうか?答えは「基本、基本要素」みたいな感じになります。(他の意味もあります)要するに、頂点バッファのデータを利用して、何か基本的な図形を描くメソッドです。何を描くのかって?「点」か「線」か「三角形」ですよ。

public void DrawPrimitives(
    PrimitiveType primitiveType,
    int startVertex,
    int primitiveCount
);

PrimitiveType primitiveType

ここ重要です。ですが、説明は次回にしましょう。とりあえず三角形を描きたいので、「PrimitiveType.TriangleList」です。

int startVertex

頂点バッファのどのデータから始めるかを指定します。全部の時は「0」です。(なんかこんな引数ばっかですね。一体何個オフセットを指定したいのやら…)

int primitiveCount

何個描画するかを決める数です。今回は1です。頂点の数ではないので気を付けて。



これで三角形が表示されればOKです。ごめんなさい。長いです。しかも、説明ばっかりで「実践」的じゃないですね。次回はパパッとまとめましょう。と言うわけで、次回は「PrimitiveType」についての説明です。


ページの一番上へ
前のページへ 一覧に戻る 次のページへ
初版2006-3-9 最終更新2006-5-13
[Atelier Blue アトリエブルー]HomeプログラミングManaged DirectX3D>三角形を描く