欢迎光临
我们一直在努力

DirectX9 3D 快速上手 5-.NET教程,报表/图形/Office

建站超值云服务器,限时71元/月

directx9 3d 快速上手  5
by sssa2000

    这一章的内容相对很简单,控制mesh的移动,旋转等等,其实这一切都是在对矩阵进行操作。在 dx中,用到的变换有3种,一种是基于word坐标系的,一种是基于view坐标系的,还有一种是基于投影的变换。而这些变换都是通过矩阵的运算来实现的,在.net的托管环境下,实现这些操作相对于非托管来说简单一写,不用对矩阵的每个值运算。

关于矩阵的运算和变换的关系,很多文章都有分析,gameres也有很多这样的好文章,例如:http://dev.gameres.com/program/visual/3d/3dgame.mht 这里就有很详细的介绍。

我们这篇文章不研究细节,因为毕竟是快速开发,我们的目标就是用键盘控制读入的mesh的运动。

其实在前面一篇文章中我们就有提到几个函数,只是没有介绍。我们来看看我们这一篇中要用到的几个简单的函数,从字面我们就可以判断出这些函数有什么用:

 

matrix.rotatex方法:public void rotatex(    float angle);

matrix. rotatey方法:public void rotatey(    float angle);

matrix.rotatex方法:public void rotatez(    float angle);

matrix.translation方法:public static matrix translation(float offsetx, float offsety, float offsetz);

 

好,我们现在重新打开上一次的读入mesh的那个工程,我们现在要加入新的部分,既然是用键盘控制那么就要首先对键盘的状态进行分析:

         string status=null;//用于保存状态

protected override void onkeydown(system.windows.forms.keyeventargs e)

         {

              // handle the escape key for quiting

              if (e.keycode == keys.escape)

              {

                   // close the form and return

                   this.close();

                   return;

              }

              // handle left and right keys

              else if ((e.keycode == keys.left) || (e.keycode == keys.numpad4))

              {

                   status=”left”;  //向左旋转

              }

              else if ((e.keycode == keys.right) || (e.keycode == keys.numpad6))

              {

                   status=”right”;//向右旋转

              }

              else if((e.keycode ==keys.up )||(e.keycode ==keys.numpad8 ))

              {

                   status=”up”;//向上旋转

              }

              else if((e.keycode ==keys.down  )||(e.keycode ==keys.numpad2 ))

              {

                   status=”down”;//向下旋转

              }

              else if(e.keycode ==keys.enter)

              {

                   status=”stop”;//停止旋转

              }

              else if(e.keycode ==keys.w  )

              {

                   status=”goahead”;//向前

 

              }

              else if(e.keycode ==keys.s )

              {

                   status=”goback”;//向后

              }

              else if(e.keycode ==keys.a)

              {

                   status=”goleft”;//向左

              }

              else if(e.keycode ==keys.d )

              {

                   status=”goright”;//向右

              }

             

         }

很简单,以至于没什么可说的,下面就要对mesh进行移动,由于我们观察的运动都是相对运动,所以无论你是对摄像机进行操作还是进行世界变换都是可以的,随你所好。我们对drawmesh函数进行修改,主要是对状态的判断,然后对相应的矩阵进行变换:

        private void drawmesh(string stat)

              if(stat==”left”)

              {

                   angle=angle+0.1f;

                   device.transform.world = matrix.rotationy (angle);

              }

              else if(stat==”right”)

              {

                   angle=angle-0.1f;

                   device.transform.world = matrix.rotationy (angle);

              }

              else if(stat==”up”)

              {

                   angle=angle+0.1f;

                   device.transform.world = matrix.rotationx (angle);

 

 

              }

              else if(stat==”down”)

              {

                   angle=angle-0.1f;

                   device.transform.world = matrix.rotationx (angle);

 

              }

              else if(stat==”stop”)

              {

                   angle=0.0f;

                   //device.reset ()

              }

              else if(stat==”goahead”)

              {

                   v=v+0.1f;

              }

              else if(stat==”goback”)

              {

                   v=v-0.1f;

              }

              else if(stat==”goleft”)

              {

                   offsetx=offsetx+0.01f;

 

                   device.transform.world = matrix.translation(offsetx,0,0);

              }

              else if(stat==”goright”)

              {

                   offsetx=offsetx-0.01f;

                   device.transform.world = matrix.translation(offsetx,0,0);

 

              }

 

            for (int i = 0; i < meshmaterials.length; i++)

            {

                device.material = meshmaterials[i];

                device.settexture(0, meshtextures[i]);

                mesh.drawsubset(i);

            }

        }

public: void rotatex(
    float angle
);

public function rotatex(
    angle : float
);

这里我们处理小车前后移动的时候,没有直接使用世界变换,而是对摄影机进行了操作,这也很好理解,为了达到这个目的,我把setupcamera函数小小的修改了一下:

  private void setupcamera(float deep )

        {

            device.transform.projection = matrix.perspectivefovlh((float)math.pi / 4, this.width / this.height, 1.0f, 10000.0f);

            device.transform.view = matrix.lookatlh(new vector3(0,0, 10.0f+deep), new vector3(), new vector3(0,1,0));

            device.lights[0].type = lighttype.directional;

            device.lights[0].diffuse = color.white;

            device.lights[0].direction = new vector3(0, -1, -1);

            device.lights[0].update();

            device.lights[0].enabled = true;

        }

我给它加了一个参数,这个参数就是摄像机在z轴的位置,我们只需要修改摄像机在z轴的位置就可以实现透视效果,用这个方法实现我们这个简单的需求是很恰当的

这里再来对这里面的2个函数分析一下:

device.transform.projection用来获取或者设置投影变换矩阵,它本身也是一个matrix型的变量。matrix.perspectivefovlh方法:

public static matrix perspectivefovlh(
    float fieldofviewy, //y方向的视觉范围,弧度表示,即y方向的视域角
    float aspectratio, //视觉范围的长宽比
    float znearplane, //近裁减平面      
    float zfarplane//远裁减平面
);

和非托管的相比,仅仅少了一个参数。定义宽高比的作用是,如果用户改变了窗口的大小,那么仍然就可以正确的显示物体的大小。最后两个参数是 近远裁减平面,必须为这两个平面指定2个z值,一般来说,假设物体将在z轴的1.0f和1000f之间运动时,就分别把这两个参数设为1.0f,1000.0f。

再来看看另外方法:matrix.lookatlh方法。 在使用观察矩阵来建立一个立体的照相机模型后,允许玩家通过一系列不同的观察点来看世界,使用matrix.lookatlh方法建立的照相机模型,是一种十分高效的照相机模型,但是注意,这一种模型不能绕所有的轴做三维转动。

public static matrix lookatlh(
    vector3 cameraposition,//相机位置
    vector3 cameratarget,   //相机的方向
    vector3 cameraupvector  //相机的up向量
);

其中第二个参数为相机的面对方向,假设相机面对的是z轴的方向,那么就设置为(0,0,1)。好,现在也许有人要问,那如果面对的是z轴的负方向呢?这也就是第3个参数的目的,第三个参数定一个up向量,所以如果相机是正着放的,那么第3个参数就应该是(0,1,0),如果是倒着放的就是(0,-1,0)。所以如果面对的是z的负方向,第三个参数就是(0,-1,0)。

利用这个方法我们可以轻易的建立一个跟随式的相机(follow-up camera),例如实现第一人称视角,只需要把第2个参数指向跟随物体的方向,把相机位置设置为这个物体的周围。前面我们提过,这类相机不能绕自身旋转。

好,让我们来简单实现这个功能,我们想让汽车前进后退的时候能让摄像机来跟随它,首先,我们必须得到读入的mesh的x,y,z这样才能给摄像机提供第一个参数,其次我们要确定朝向,在这里,很好确定,因为汽车就是朝z方向开的,好了,都确定下来我们就可以写代码了。为了得到mesh的位置,就要使用mesh内置的定点缓冲。

……………………………………..

             loadmesh(@”..\.. r.x”);

             vb=mesh.vertexbuffer; //取得读入mesh的中心

              try

              {

                   vector3 max;

                   vector3 min;

                   graphicsstream gs = vb.lock(0, 0, lockflags.none);

                   geometry.computeboundingbox(gs, mesh.numbervertices, mesh.vertexformat, out min, out max); //取得mesh的边框

                   float tx = (max.x – min.x)/2;

                   float ty =( max.y – min.y)/2;

                   float tz =( max.z – min.z);

                   pos.x =tx-0.9f;  //试出来的,这样才能使摄像机近似在车子中心

                   pos.y =ty+0.6f;

                   pos.z =tz-1.8f;

                   //float cameraheadingh=

                   lookat = new vector3 (0,0,1);

              }

              finally

              {

                   vb.unlock();

                   vb.dispose();

              }

修改keydown并且修改setupcamera函数判断摄像机的选择。

private void setupcamera(float deep )

        {

            device.transform.projection = matrix.perspectivefovlh((float)math.pi / 4, this.width / this.height, 1.0f, 10000.0f);

              if(camera%2!=0)

                device.transform.view = matrix.lookatlh(new vector3(0,0, 10.0f+deep), new vector3(), new vector3(0,1,0));

              else

                   device.transform .view =matrix.lookatlh (pos,new vector3 (0,1,0),new vector3 (0,1,0));

 

            device.lights[0].type = lighttype.directional;

            device.lights[0].diffuse = color.white;

            device.lights[0].direction = new vector3(0, -1, -1);

            device.lights[0].update();

            device.lights[0].enabled = true;

        }

 

这样就完成了这个功能,不过这里只是简单模拟一下,只有在前进后退的时候才有效果,不过由于没有参照物,在前进后退的时候看不出画面的变化。下面贴出完整的代码:

using system;

using system.drawing;

using system.collections;

using system.componentmodel;

using system.windows.forms;

using system.data;

using microsoft.directx;

using microsoft.directx.direct3d;

 

namespace chapter5code

{

     /// <summary>

     /// summary description for form1.

     /// </summary>

     public class form1 : system.windows.forms.form

     {

        private device device = null;

         presentparameters presentparams =null;

        private mesh mesh = null;

        private material[] meshmaterials;

        private texture[] meshtextures;

 

         private mesh mesh2=null;

         material[] meshmaterials2;

         texture[] meshtextures2;

 

        string status=null; //小车状态,向左转动还是向右转动,或者停止

         private vertexbuffer vb = null;

         vector3 pos;

         vector3 lookat;

 

         int camera=1;

         float angle=0.0f;

         float v=0.1f;

         float offsetx=0.1f;

 

         /// <summary>

         /// required designer variable.

         /// </summary>

         private system.componentmodel.container components = null;

 

         public form1()

         {

              //

              // required for windows form designer support

              //

              initializecomponent();

 

            this.setstyle(controlstyles.allpaintinginwmpaint | controlstyles.opaque, true);

         }

 

        /// <summary>

        /// we will initialize our graphics device here

        /// </summary>

        public void initializegraphics()

        {

            // set our presentation parameters

            presentparameters presentparams = new presentparameters();

 

            presentparams.windowed = true;

            presentparams.swapeffect = swapeffect.discard;

            presentparams.autodepthstencilformat = depthformat.d16;

            presentparams.enableautodepthstencil = true;

 

            // create our device

            device = new device(0, devicetype.hardware, this, createflags.softwarevertexprocessing, presentparams);

            // load our mesh

             loadmesh(@”..\.. r.x”);

 

              vb=mesh.vertexbuffer; //取得读入mesh的中心

              try

              {

                   vector3 max;

                   vector3 min;

                   graphicsstream gs = vb.lock(0, 0, lockflags.none);

                   geometry.computeboundingbox(gs, mesh.numbervertices, mesh.vertexformat, out min, out max);

                   float tx = (max.x – min.x)/2;

                   float ty =( max.y – min.y)/2;

                   float tz =( max.z – min.z);

                   pos.x =tx-0.9f;

                   pos.y =ty+0.6f;

                   pos.z =tz-1.8f;

                   //float cameraheadingh=

                   lookat = new vector3 (0,0,1);

 

              }

              finally

              {

                   vb.unlock();

                   vb.dispose();

              }

        }

 

        private void loadmesh(string file)

        {

            extendedmaterial[] mtrl;

 

            // load our mesh

            mesh = mesh.fromfile(file, meshflags.managed, device, out mtrl);

             // if we have any materials, store them

            if ((mtrl != null) && (mtrl.length > 0))

            {

                meshmaterials = new material[mtrl.length];

                meshtextures = new texture[mtrl.length];

 

                // store each material and texture

                for (int i = 0; i < mtrl.length; i++)

                {

                    meshmaterials[i] = mtrl[i].material3d;

                    if ((mtrl[i].texturefilename != null) && (mtrl[i].texturefilename != string.empty))

                    {

                        // we have a texture, try to load it

                        meshtextures[i] = textureloader.fromfile(device, @”..\..\” + mtrl[i].texturefilename);

                    }

                }

            }

        }

 

 

 

         protected override void onkeydown(system.windows.forms.keyeventargs e)

         {

              // handle the escape key for quiting

              if (e.keycode == keys.escape)

              {

                   // close the form and return

                   this.close();

                   return;

              }

              // handle left and right keys

              else if ((e.keycode == keys.left) || (e.keycode == keys.numpad4))

              {

                   status=”left”;

              }

              else if ((e.keycode == keys.right) || (e.keycode == keys.numpad6))

              {

                   status=”right”;

              }

              else if((e.keycode ==keys.up )||(e.keycode ==keys.numpad8 ))

              {

                   status=”up”;

              }

              else if((e.keycode ==keys.down  )||(e.keycode ==keys.numpad2 ))

              {

                   status=”down”;

              }

              else if(e.keycode ==keys.enter)

              {

                   status=”stop”;

              }

              else if(e.keycode ==keys.w  )

              {

                   status=”goahead”;

 

              }

              else if(e.keycode ==keys.s )

              {

                   status=”goback”;

              }

              else if(e.keycode ==keys.a)

              {

                   status=”goleft”;

              }

              else if(e.keycode ==keys.d )

              {

                   status=”goright”;

              }

              else if(e.keycode ==keys.c)

              {

                   camera++;

              }

 

             

 

         }

 

        private void setupcamera(float deep )

        {

            device.transform.projection = matrix.perspectivefovlh((float)math.pi / 4, this.width / this.height, 1.0f, 10000.0f);

              if(camera%2!=0)

                device.transform.view = matrix.lookatlh(new vector3(0,0, 10.0f+deep), new vector3(), new vector3(0,1,0));

              else

                   device.transform .view =matrix.lookatlh (pos,new vector3 (0,1,0),new vector3 (0,1,0));

 

            //device.renderstate.ambient = color.darkblue;

            device.lights[0].type = lighttype.directional;

            device.lights[0].diffuse = color.white;

            device.lights[0].direction = new vector3(0, -1, -1);

            device.lights[0].update();

            device.lights[0].enabled = true;

 

        }

 

        protected override void onpaint(system.windows.forms.painteventargs e)

        {

            device.clear(clearflags.target | clearflags.zbuffer, color.cornflowerblue, 1.0f, 0);

 

            setupcamera(v );

 

            device.beginscene();

 

            // draw our mesh

            drawmesh(status);

 

            device.endscene();

 

            device.present();

 

            this.invalidate();

        }

 

        private void drawmesh(string stat)

        {

         //   angle += 0.01f;

 

        //    device.transform.world = matrix.rotationyawpitchroll(yaw, pitch, roll) * matrix.translation(x, y, z);

              if(stat==”left”)

              {

                   angle=angle+0.1f;

                   device.transform.world = matrix.rotationy (angle);

              }

              else if(stat==”right”)

              {

                   angle=angle-0.1f;

                   device.transform.world = matrix.rotationy (angle);

              }

              else if(stat==”up”)

              {

                   angle=angle+0.1f;

                   device.transform.world = matrix.rotationx (angle);

 

 

              }

              else if(stat==”down”)

              {

                   angle=angle-0.1f;

                   device.transform.world = matrix.rotationx (angle);

 

              }

              else if(stat==”stop”)

              {

                   angle=0.0f;

                   //device.reset ()

              }

              else if(stat==”goahead”)

              {

                   v=v+0.1f;

              }

              else if(stat==”goback”)

              {

                   v=v-0.1f;

              }

              else if(stat==”goleft”)

              {

                   offsetx=offsetx+0.001f;

 

                   device.transform.world = matrix.translation(offsetx,0,0);

                   //device.transform .view =matrix.translation(offsetx,0,0);

              //   pos.x -=offsetx;

              //   device.transform .view =matrix.lookatlh(pos,new vector3 (0,0,1),new vector3 (0,1,0));

              }

              else if(stat==”goright”)

              {

                   offsetx=offsetx-0.001f;

                   device.transform.world = matrix.translation(offsetx,0,0);

 

 

              }

 

 

            for (int i = 0; i < meshmaterials.length; i++)

            {

                device.material = meshmaterials[i];

                device.settexture(0, meshtextures[i]);

                mesh.drawsubset(i);

            }

        }

 

        /// <summary>

         /// clean up any resources being used.

         /// </summary>

         protected override void dispose( bool disposing )

         {

              if( disposing )

              {

                   if (components != null)

                   {

                       components.dispose();

                  }

              }

              base.dispose( disposing );

         }

 

         #region windows form designer generated code

         /// <summary>

         /// required method for designer support – do not modify

         /// the contents of this method with the code editor.

         /// </summary>

         private void initializecomponent()

         {

              this.components = new system.componentmodel.container();

              this.size = new size(800,600);

              this.text = “form1”;

         }

         #endregion

 

         /// <summary>

         /// the main entry point for the application.

         /// </summary>

        static void
main
()

        {

            using (form1 frm = new form1())

            {

                // show our form and initialize our graphics engine

                frm.show();

                frm.initializegraphics();

                application.run(frm);

            }

        }

     }

}

 

好幸库,结束。

赞(0)
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com 特别注意:本站所有转载文章言论不代表本站观点! 本站所提供的图片等素材,版权归原作者所有,如需使用,请与原作者联系。未经允许不得转载:IDC资讯中心 » DirectX9 3D 快速上手 5-.NET教程,报表/图形/Office
分享到: 更多 (0)