[Atelier Blue アトリエブルー]HomeプログラミングManaged DirectX3D>物体の回転と移動

物体の回転と移動

ここまでの事柄ではあまり数学を気にすることなく3Dが行えたと思います。しかし、本格的な3Dをするに当たってはそれなりの知識が必要です。別に数学の本を読めとは言いません。ですが、3Dについて説明している本を読むことは理解への手伝いにもなりますし、新しい表現を行うに当たっても必要となってきます。

今回はオブジェクトの回転と移動を行ってみましょう。使う関数は「Matrix.Rotation(回転)」と「Matrix.Translation(平行移動)」です。キー入力によってオブジェクトを動かせるようにしてあるので、色々と遊んで3Dでの回転と移動の感覚をつかんでみてください。ただし、すごく直感に反する動きをするのでご注意を。直感に反しない方はこちら

サンプル

前方投影面が見えますね。

ソースコード

キーの説明

実行ファイル

ものぐさな方は上をどうぞ

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
    {
        //0:x
        //1:y
        //2:z
        float []point =new float [3];
        float []roll =new float[3];
        int select =0;



        public md3d2():base()
        {
            this.MinimumSize=new Size(80,60);
            this.ClientSize = new Size(300,300);
            this.Text ="Direct3D-My";
            this.KeyDown+=new KeyEventHandler(md3d2_KeyDown);
        }

        private Device device_;
        private PresentParameters presentParam_;


        /// <summary>
        /// 立方体メッシュ
        /// </summary>
        private Mesh boxMesh_;

        /// <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_);


                //メッシュを作成
                creatMesh();

                return true;
            }
            catch
            {
                return false;
            }

        }


        /// <summary>
        /// メッシュを作成する
        /// </summary>
        private void creatMesh()
        {
            boxMesh_ = Mesh.Box(device_,2,2,2);
        }

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

            //回転と移動を行う
            device_.Transform.World =
                Matrix.RotationX(roll[0])
                *Matrix.RotationY(roll[1])
                *Matrix.RotationZ(roll[2])
                *Matrix.Translation(point[0],point[1],point[2]);


            //カメラの設定を行う
            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_.RenderState.Lighting =false;
            //ライトの設定
            device_.Lights[0].Direction =Vector3.Normalize(new Vector3(-1,-2,-3));
            device_.Lights[0].Type = LightType.Directional;

            device_.Lights[0].Diffuse = Color.FromArgb(255,255,255);
            device_.Lights[0].Ambient = Color.FromArgb(40,40,40);

            device_.Lights[0].Enabled =true;
            device_.Lights[0].Update();



            //マテリアルの設定
            Material mat =new Material();
            mat.AmbientColor = new ColorValue(1.0f,1.0f,1.0f);
            mat.DiffuseColor = new ColorValue(1.0f,1.0f,1.0f);
            device_.Material = mat;


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

            device_.BeginScene();

            boxMesh_.DrawSubset(0);


            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_);
                }
            }
        }

        private void md3d2_KeyDown(object sender, KeyEventArgs e)
        {
            switch(e.KeyCode)
            {
            case Keys.X:
                select=0;
                break;
            case Keys.Y:
                select=1;
                break;
            case Keys.Z:
                select =2;
                break;

            case Keys.Down:
                point[select]-=(float)0.2;
                break;
            case Keys.Up:
                point[select]+=(float)0.2;
                break;
            case Keys.Left:
                roll[select]-=(float)Math.PI/180f;
                break;
            case Keys.Right:
                roll[select]+=(float)Math.PI/180f;
                break;
            }
        }
    }

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

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

説明事項

特にありません。今までやって来たことしか使っていないつもりです。

ただ、今回は皆さんに自分で試してもらいたいことがあります。それは、掛け算の順番の変更です。かなり前の入門で説明していましたが、皆さんは覚えているでしょうか?

//回転と移動を行う
device_.Transform.World =
    Matrix.RotationX(roll[0])
    *Matrix.RotationY(roll[1])
    *Matrix.RotationZ(roll[2])
    *Matrix.Translation(point[0],point[1],point[2]);

ここの部分の掛け算の順番を変更し、実行してみてください。何か変化があるはずです(何もこらないという方は移動を回転の前に持ってきてみてください)。さて、これはどうしてでしょうか?まあ、れっきとした理由があるのですが、めんどくさいのでパスです。

補足事項

回転の部分3行も使っていてめんどくさいですね。実はこれ、1行にまとめることも出来ます。

Matrix.RotationYawPitchRoll(roll[1],roll[0],roll[2])

1行ずつよりは自由度が減りますが、この方が楽かもしれません。

さらに補足、よく分からない数学的事情が行列(matrix)には付いてくるらしいです。ただし、そこについては私の守備範囲外となるので書きません。誰か3Dの数学についての説明書いてもらえませんか?このサイトで是非公開させてください。ただし無報酬ですけど。


ページの一番上へ
前のページへ 一覧に戻る 次のページへ
初版2006-4-23 最終更新2006-5-9
[Atelier Blue アトリエブルー]HomeプログラミングManaged DirectX3D>物体の回転と移動