三角形ポリゴンを描画する

C# DirectX で三角形ポリゴンの頂点座標を設定して描画します。

前田稔(Maeda Minoru)の超初心者のプログラム入門

プロジェクトの設定

  1. DirectX 3D で Form を表示 に習って、空のプロジェクトから作成します。
    次のファイルを格納して、プロジェクトに取り込んで下さい。
    /***************************************************/
    /*★ 頂点座標を設定して、三角形を描画    前田 稔 ★*/
    /***************************************************/
    using System;
    using System.Drawing;
    using System.Windows.Forms;
    using Microsoft.DirectX;
    using Microsoft.DirectX.Direct3D;
    
    namespace VerticesTutorial
    {
        public class Vertices : Form
        {
            Device device = null;           // Our rendering device
            VertexBuffer vertexBuffer = null;
    
            // Vertices の Constructor
            public Vertices()
            {
                // Set the initial size of our form
                this.ClientSize = new System.Drawing.Size(300,300);
                // And its caption
                this.Text = "Direct3D Triangle";
            }
    
            // Graphics の初期化
            public bool InitializeGraphics()
            {
                try
                {
                    // Now let's setup our D3D stuff
                    PresentParameters presentParams = new PresentParameters();
                    presentParams.Windowed=true;
                    presentParams.SwapEffect = SwapEffect.Discard;
                    device = new Device(0, DeviceType.Hardware, this, CreateFlags.SoftwareVertexProcessing, presentParams);
                    this.OnCreateDevice(device, null);
                    return true;
                }
                catch (DirectXException)
                { 
                    return false; 
                }
            }
    
            public void OnCreateDevice(object sender, EventArgs e)
            {
                Device dev = (Device)sender;
                // Now Create the VertexBuffer を生成して、OnCreateVertexBuffer で座標を格納
                vertexBuffer = new VertexBuffer(typeof(CustomVertex.TransformedColored), 3, dev, 0, CustomVertex.TransformedColored.Format, Pool.Default);
                vertexBuffer.Created += new System.EventHandler(this.OnCreateVertexBuffer);
                this.OnCreateVertexBuffer(vertexBuffer, null);
            }
    
            public void OnCreateVertexBuffer(object sender, EventArgs e)
            {
                VertexBuffer vb = (VertexBuffer)sender;
                GraphicsStream stm = vb.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);
                vb.Unlock();
            }
    
            // Frame の描画メソッド
            private void Render()
            {
                if (device == null)     return;
    
                device.RenderState.CullMode = Cull.CounterClockwise;
                //device.RenderState.CullMode = Cull.Clockwise;
                //device.RenderState.CullMode = Cull.None;
    
                //Clear the backbuffer to a blue color (ARGB = 000000ff)
                device.Clear(ClearFlags.Target, System.Drawing.Color.Blue, 1.0f, 0);
                //Begin the scene
                device.BeginScene();
    
                device.SetStreamSource( 0, vertexBuffer, 0);
                device.VertexFormat = CustomVertex.TransformedColored.Format;
                device.DrawPrimitives(PrimitiveType.TriangleList, 0, 1);
                //End the scene
                device.EndScene();
                device.Present();
            }
    
            // Window の描画 OnPaint() をオーバーロード
            protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
            {
                this.Render();      // Render on painting
            }
    
            // OnKeyPress() をオーバーロード
            protected override void OnKeyPress(System.Windows.Forms.KeyPressEventArgs e)
            {
                if ((int)(byte)e.KeyChar == (int)System.Windows.Forms.Keys.Escape)
                    this.Close();   // Esc was pressed
            }
    
            //☆ Main() メソッド
            static void Main() 
            {
    
                // using で資源の解放を確実に行う
                using (Vertices frm = new Vertices())
                {
                    if (!frm.InitializeGraphics())  // Initialize Direct3D
                    {
                        MessageBox.Show("Could not initialize Direct3D.  This tutorial will exit.");
                        return;
                    }
                    frm.Show();
    
                    // While the form is still valid, render and process messages
                    while(frm.Created)
                    {
                        frm.Render();
                        Application.DoEvents();
                    }
                }
            }
    
        }
    }
    
  2. 三角形ポリゴンの作成と描画の方法を説明します。
    DirectX3D の初期化を行う InitializeGraphics() です。
    正常に起動されたとき try を、失敗したとき catch が実行されます。
    new Device() で DirectX の Device を取得します。
    device を引数にして OnCreateDevice() で三角形ポリゴンの領域を生成するメソッドを呼び出します。
        public bool InitializeGraphics()
        {
            try
            {
                // Now let's setup our D3D stuff
                PresentParameters presentParams = new PresentParameters();
                presentParams.Windowed=true;
                presentParams.SwapEffect = SwapEffect.Discard;
                device = new Device(0, DeviceType.Hardware, this, CreateFlags.SoftwareVertexProcessing, presentParams);
                this.OnCreateDevice(device, null);
                return true;
            }
            catch (DirectXException)
            { 
                return false; 
            }
        }
        
  3. 三角形ポリゴンの領域を生成するメソッド OnCreateDevice() です。
    new VertexBuffer で領域を確保して、OnCreateVertexBuffer() の第一引数として渡します。
        VertexBuffer vertexBuffer = null;
    
        public void OnCreateDevice(object sender, EventArgs e)
        {
            Device dev = (Device)sender;
            // Now Create the VertexBuffer を生成して、OnCreateVertexBuffer で座標を格納
            vertexBuffer = new VertexBuffer(typeof(CustomVertex.TransformedColored), 3, dev, 0,
                           CustomVertex.TransformedColored.Format, Pool.Default);
            vertexBuffer.Created += new System.EventHandler(this.OnCreateVertexBuffer);
            this.OnCreateVertexBuffer(vertexBuffer, null);
        }
        
  4. 三角形ポリゴンの頂点座標を設定するメソッド OnCreateVertexBuffer です。
    VertexBuffer の領域を sender で受け取って vb に格納します。
    vb を Lock() してポインタを stm に取得します。
    ウインドウ上のピクセル座標で、三個の頂点(X,Y,Z)と頂点の色を verts[] に設定します。
    座標と色はページ先頭の画像を参照して下さい。
    verts[] を stm に書き込むと、頂点データが VertexBuffer に書き込まれます。
        public void OnCreateVertexBuffer(object sender, EventArgs e)
        {
            VertexBuffer vb = (VertexBuffer)sender;
            GraphicsStream stm = vb.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);
            vb.Unlock();
        }
        
  5. メッセージループや OnPaint() から呼び出される描画メソッドです。
    device.SetStreamSource() で頂点データが設定されている VertexBuffer を指定して DrawPrimitives() で三角形を描画します。
        private void Render()
        {
            if (device == null)     return;
    
            //Clear the backbuffer to a blue color (ARGB = 000000ff)
            device.Clear(ClearFlags.Target, System.Drawing.Color.Blue, 1.0f, 0);
            //Begin the scene
            device.BeginScene();
    
            device.SetStreamSource( 0, vertexBuffer, 0);
            device.VertexFormat = CustomVertex.TransformedColored.Format;
            device.DrawPrimitives(PrimitiveType.TriangleList, 0, 1);
            //End the scene
            device.EndScene();
            device.Present();
        }
        

【演習】

  1. ポリゴンには裏と表があります。
    反時計周りになるように、頂点の順序を入れ替えてみて下さい。
    ポリゴンが裏向きになって描画されなくなります。
        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=50;verts[1].Y=250;verts[1].Z=0.5f; verts[1].Rhw=1; verts[1].Color = System.Drawing.Color.LightPink.ToArgb();
        verts[2].X=250;verts[2].Y=250;verts[2].Z=0.5f; verts[2].Rhw=1; verts[2].Color = System.Drawing.Color.Brown.ToArgb();
        
  2. 三角形のポリゴンを組み合わせて四角形を描画してみて下さい。
  3. カリングと座標系の説明は Windows Guid を参照して下さい。

【NOTE】

以前作成した DirectX のプロジェクトが、実行時にエラーメッセージが表示されて動かなくなりました。 (^_^;)
現在の実行環境は Windows7 & Visual Studio .NET 2005 & DirectX November2008 です。
  1. エラーメッセージ
    BadImageFormatException はハンドルされませんでした。
  2. 原因
    Windows7 で C# を使ったときの既定値は 64bit で DirectX の DLL(32bit)を呼び出すことが出来ません。
    そこで C# で DirectX を組む時は 32bit に設定します。
    1. Any CPU の右のリストボックスをクリックして、構成マネージャを呼び出します。
    2. <新規作成>から X86 を作成します。
    3. 元の画面に戻ると、Any CPU が X86 に変わり 32bit のモードになります。

    これで、以前作成した DirectX のプロジェクトが動くようになりました。 ヽ(^^ )
  3. 2014/08/08 デスクトップモードで DirectX を動かしてみました。
    ストアアプリの DirectX は 超初心者のプログラム入門(DirectX Windows8) を参照して下さい。
    Windows 8.1 + DirectX9 の環境でC#で作成した DirectX の実行を確認しました。
    DirectX9 をインストールしてインクルードファイルとライブラリファイルのパスを設定して下さい。
    CPU モードを X86 に設定して下さい。
    C# Direct Draw, C# DirectX Sprite, C# DirectX 3D の実行を確認しました。

超初心者のプログラム入門(C# Frame Work)