[Atelier Blue アトリエブルー]HomeプログラミングManaged DirectX3D>本当の3D

本当の3D

なんだかちょっとごたごたですが、いよいよ本当の3Dに取りかかります。もちろん最初は3角形です。

ソースコード

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

namespace Project2
{
    /// <summary>
    /// md3d2 の概要の説明です。
    /// </summary>
    public class md3d2:Form
    {

        public md3d2():base()
        {
            //最小サイズを設定
            this.MinimumSize=new Size(80,60);
            //ウィンドウの名前(かっこいいのを付けてあげてください)
            this.Text ="Direct3D-My";
        }

        private Device device_;
        private PresentParameters presentParam_;

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

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

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

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

                creatVertex();

                //初期化成功
                return true;
            }
            catch
            {
                //初期化失敗
                return false;
            }

        }

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

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

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

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

            //頂点データ
            verts[0].Position =new Vector3(0,2.0f,0);
            verts[0].Color = System.Drawing.Color.LightPink.ToArgb();
            verts[1].Position =new Vector3(1.0f,0,0);
            verts[1].Color = System.Drawing.Color.Aqua.ToArgb();
            verts[2].Position =new Vector3(-1.0f,0,0);
            verts[2].Color = System.Drawing.Color.Brown.ToArgb();



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

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

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

            //カメラの設定を行う
            device_.Transform.View = Matrix.LookAtLH(
                new Vector3( 0.0f, 0.0f,-5.0f ),
                new Vector3( 0.0f, 0.0f, 0.0f ),
                new Vector3( 0.0f, 1.0f, 0.0f ) );
            device_.Transform.Projection =
                Matrix.PerspectiveFovLH((float)Math.PI / 4,
                (float)this.ClientSize.Width / (float)this.ClientSize.Height,
                3.0f, 15.0f);


            device_.Clear(ClearFlags.Target,Color.Blue,1.0f,0);

            device_.BeginScene();

            device_.SetStreamSource(0,vertexBuffer_,0);
            device_.VertexFormat = CustomVertex.PositionColored.Format;
            device_.DrawPrimitives(PrimitiveType.TriangleList,0,1);

            device_.EndScene();

            try
            {
                //更新
                device_.Present();
            }
            catch(DeviceLostException)
            {
                resetDevice();
            }

        }

        /// <summary>
        /// デバイスのリセットを行う
        /// </summary>
        private void resetDevice()
        {
            int result;
            if(!device_.CheckCooperativeLevel(out result))
            {
                if(result ==(int)ResultCode.DeviceLost)
                {
                    //ちょっと待つ
                    System.Threading.Thread.Sleep(10);
                }
                else if(result ==(int)ResultCode.DeviceNotReset)
                {
                    device_.Reset(presentParam_);
                }
            }
        }
    }

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

                while(dxform.Created)
                {
                    dxform.Render();
                    Application.DoEvents();
                }
            }
        }
    }
}


カメラ

3Dには視点が必要と前に言いましたが、とうとうカメラが出て参りました。カメラの設定はわりと決まり切っています。(でも、本格的なってくればカメラも頻繁に動かしますよ)とりあえずカメラの部分だけ抜き出します。

//カメラの設定を行う
device_.Transform.View = Matrix.LookAtLH(
    new Vector3( 0.0f, 0.0f,-5.0f ),
    new Vector3( 0.0f, 0.0f, 0.0f ),
    new Vector3( 0.0f, 1.0f, 0.0f ) );
device_.Transform.Projection =
    Matrix.PerspectiveFovLH((float)Math.PI / 4,
    (float)this.ClientSize.Width / (float)this.ClientSize.Height,
    3.0f, 15.0f);

こういうとき図を書けば分かり易いのでしょうけどとりあえず言葉だけで説明します。

public static Matrix LookAtLH(
    Vector3 cameraPosition,
    Vector3 cameraTarget,
    Vector3 cameraUpVector
);

この関数名前のまんまです。カメラのポジション、見ている点、どちらの方向がカメラの上方向であるかをそれぞれセットします。「Vector3」というのは浮動小数点(Single型)が三つ並んでいるだけです。三つあるときは左から「X,Y,Z」です。とりあえず、これによって作られた物をしかるべき所に代入する事によって一つ目の作業は完了です。

public static Matrix PerspectiveFovLH(
    float fieldOfViewY,
    float aspectRatio,
    float znearPlane,
    float zfarPlane
);

こちらはさっきよりも難しいかもしれません。1つ1つ説明していきましょう。

float fieldOfViewY

横方向の視野の広さです。見える範囲の角度を表す数値でラジアンを利用します。(ラジアンが分からない方。π=180°と言う事です)狭いほど物が大きく見えます。

float aspectRatio

アスペクト比です。つまり縦横の比率です。「横÷縦」で計算します。

float znearPlane

前方投影面までの距離です。

float zfarPlane

後方投影面までの距離です。


前方投影面と、後方投影面について説明します。現実世界では奥行きに限界はありません。ですが、パソコンでの処理では無限のものを扱うことは出来ません。そのため、見える限界を設定します。つまり、見える範囲は「前方投影面と後方投影面に挟まれ、視野の広さに応じた領域内」ということになります。

これでカメラについては一通り終わりです。図が無くても分かりましたか?

今回の頂点形式

今回は本物の3Dという事で3次元空間上に頂点を置きます。(ついでなので色も付けます)そのために今回利用する頂点形式は「PositionColored」です。(まんまな名前です)必要な数値はPositionとColorの二つです。Positionには今回利用した「Vector3」を利用します。

とりあえず表示

前回行ったデバイス消失のコードも付け加えてあります。

ちょっと失敗した三角形

なんか失敗ましたね。色が付いていません。

ライトを使わない設定にする

というわけでキレイに表示するためにはもう一手間。下の一行をカメラの設定の次に加えてください。

device_.RenderState.Lighting=false;

これで出来たと思います。この設定はライトをオフにする設定です。今回はライトを設定していないので設定した色の通りに表示してもらうための設定です。ライトについては後々説明します。

成功した三角形

そういうわけで次回は回転させてみようと思います。


ページの一番上へ
前のページへ 一覧に戻る 次のページへ

2006-4-15 頂点数が「6」になっていたので「3」に修正


初版2006-3-11 最終更新2006-5-13
[Atelier Blue アトリエブルー]HomeプログラミングManaged DirectX3D>本当の3D