C#+Direct3D9.0开发实例之月亮绕着地球转

2016-02-19 15:52 114 1 收藏

今天图老师小编给大家介绍下C#+Direct3D9.0开发实例之月亮绕着地球转,平时喜欢C#+Direct3D9.0开发实例之月亮绕着地球转的朋友赶紧收藏起来吧!记得点赞哦~

【 tulaoshi.com - 编程语言 】

  一、建立空窗体

  新建一个工程,添加引用,并导入名称空间。

  加入一个设备对象变量:

  

private Microsoft.DirectX.Direct3D.Device device = null;

  添加初始化图形函数,并在这里面对设备对象进行实例化:

  

public void InitializeGraphics(){ PresentParameters presentParams = new PresentParameters(); presentParams.Windowed = true; presentParams.SwapEffect = SwapEffect.Flip; presentParams.AutoDepthStencilFormat = DepthFormat.D16; presentParams.EnableAutoDepthStencil = true; device = new Microsoft.DirectX.Direct3D.Device(0, Microsoft.DirectX.Direct3D.DeviceType.Hardware, this,  CreateFlags.HardwareVertexProcessing, presentParams);}

  当程序执行时,需要绘制场景,代码在这个函数里:

  

public void Render(){ // 清空设备,并准备显示下一帧。 device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, Color.Black , 1.0f, 0); // 设置照相机的位置 SetupCamera(); //开始场景 device.BeginScene(); if(meshLoaded) {  mesh.Render(meshLoc); } device.EndScene(); //显示设备内容。 device.Present();}

  设置照相机的位置:

  

private void SetupCamera(){ device.Transform.Projection = Matrix.PerspectiveFovLH((float)Math.PI / 4, this.Width / this.Height, 1.0f, 1000.00f); device.Transform.View = Matrix.LookAtLH(new Vector3(0.0f ,0.0f, 20.0f), new Vector3(0.0f,0.0f, 0.0f), new Vector3(0,1,0));}

  现在改变主函数,调用我们写的初始化函数,并显示场景:

  

[STAThread]static void Main(){ using (Form1 EarthForm = new Form1()) {  EarthForm.InitializeGraphics();  EarthForm.Show();  while(EarthForm.Created)  {   EarthForm.Render();   Application.DoEvents();  }  EarthForm.Dispose();}

  运行程序,会显示一个空的窗体。

  二、加入地球:

  在这一步里需创建一个3D网格对象,来作为要显示的地球,为此,在工程中新加入一个类Earth,此类可以包含所创建的网格对象的信息。

(本文来源于图老师网站,更多请访问http://www.tulaoshi.com/bianchengyuyan/)

  加入一些相关变量,含义见注释:

  

public class Earth : BaseEarth{ private Material[] mMaterials; //保存材质 private Texture[] mTextures; //保存纹理 private Matrix locationOffset; //用来保存网格对象的相对位置 private Mesh mMesh = null; //三角形网格对象 private Device meshDevice; //需要显示在哪个设备上。}

  在构造函数中,把Device设备拷贝到私有成员变量,这样就可以在这个类的其它方法内使用它,另外就是把位置变量进行赋值:

  

public Earth(ref Device device, Matrix location): base(ref device){ meshDevice = device; locationOffset = location;}

  下面这个函数是装入.X文件。

  

public bool LoadMesh(string meshfile){ ExtendedMaterial[] mtrl; try {  // 装载文件  mMesh = Mesh.FromFile(meshfile, MeshFlags.Managed, meshDevice, out mtrl);  // 如果有材质的话,装入它们  if ((mtrl != null) && (mtrl.Length  0))  {   mMaterials = new Material[mtrl.Length];   mTextures = new Texture[mtrl.Length];   // 得到材质和纹理   for (int i = 0; i  mtrl.Length; i++)   {    mMaterials[i] = mtrl[i].Material3D;    if ((mtrl[i].TextureFilename != null) && (mtrl[i].TextureFilename != string.Empty))    {     //前面得到的纹理的路径是相对路径,需要保存的是绝对路径,通过应用程序路径可以获得     mTextures[i] = TextureLoader.FromFile(meshDevice, @"...." + mtrl[i].TextureFilename);    }   }  }  return true; } catch {  return false; }}

  在这个方法内,使用Mesh.FromFile()这个方法,从给定的文件名中找到.X文件,并装入相关数据,一旦数据格式设置完成,可以从此文件中找到材质和贴图信息,并把它存放在数组中,并通过文件路径,得到纹理文件文件的路径,最后返回真值,如果整个过程出现错误,返回假值。

  下面这个Render()方法,是把此对象,即地球显示在设备对象上,此方法较简单,通过变形操作来得到网格对象的X,Y,Z坐标,接着设置网格对象的材质和纹理,最后,将每个材质和纹理应用到每个网格。

  

public void Render(Matrix worldTransform){ /把位置变为世界坐标 meshDevice.Transform.World = Matrix.Multiply(locationOffset, worldTransform); //绘制网格 for (int i = 0; i  mMaterials.Length; i++) {  meshDevice.Material = mMaterials[i];  meshDevice.SetTexture(0, mTextures[i]);  mMesh.DrawSubset(i); }}

  现在回到窗体代码中,添加引用网格对象的相关变量:

  

private Earth mesh = null;private Matrix meshLoc;private bool meshLoaded = false;

  在图形初始化函数中,需要对网格对象进行初始化。加入下面的代码:

  

meshLoc = Matrix.Identity;meshLoc.M41 = 2.0f;mesh = new Earth(ref device, meshLoc);if (mesh.LoadMesh(@"....earth.x")){ meshLoaded = true;}

  代码第一句把网格对象的位置定为原点,接着偏移X轴2个单位,接下来从文件中得到此.X文件。如果成功设置,meshLoaded置为真。注意,这里有一个.X文件,在源代码中有此文件。

  在设置相机的函数中,加入一盏灯光:

  

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;

  此灯光较简单,仅为一个直射型白光灯。

  最后,在Render()方法中,调用网格对象的Render()方法,以显示地球。

  三、使地球旋转

  前面用一个网格对象来建立地球,但此类没有平移,旋转及缩放等方法,下面就加入这些方法,因为这些方法具有通用性,因此可以新建一个类,把这些方法写在这些类中,使地球对象成为它的派生类。

  在工程中新添加一个类:BaseEarth;

  加入进行平移、旋转、缩放的变量:

  

private float xloc = 0.0f;private float yloc = 0.0f;private float zloc = 0.0f;private float xrot = 0.0f;private float yrot = 0.0f;private float zrot = 0.0f;private float xscale = 1.0f;private float yscale = 1.0f;private float zscale = 1.0f;

  加入相应的属性代码:

  

public float XLoc{ get {  return xloc; } set {  xloc = value; }}

  在Render()虚函数中,应用平移、旋转及缩放。

  

public virtual void Render(){ objdevice.MultiplyTransform(TransformType.World,Matrix.Translation(xloc, yloc, zloc)); objdevice.MultiplyTransform(TransformType.World,Matrix.RotationAxis(new Vector3(1.0f, 0.0f, 0.0f), xrot)); objdevice.MultiplyTransform(TransformType.World,Matrix.RotationAxis(new Vector3(0.0f, 1.0f, 0.0f), yrot)); objdevice.MultiplyTransform(TransformType.World,Matrix.RotationAxis(new Vector3(0.0f, 0.0f, 1.0f), zrot)); objdevice.MultiplyTransform(TransformType.World,Matrix.Scaling(xscale, yscale, zscale)); return;}

  现在回到地球类,需要将其改为新类的派生类,同时更改构造函数,另外,在Render()方法中,应先调用基类的Render()方法:

(本文来源于图老师网站,更多请访问http://www.tulaoshi.com/bianchengyuyan/)

  

public override void Render(){ base.Render(); //把位置变为世界坐标 // meshDevice.Transform.World = Matrix.Multiply(locationOffset, worldTransform); //绘制网格 。。。。。。}

  现在,由于在基类中可以设置对象位置,因此,可以把与locationOffset相关,即与设置位置的变量及语句注释掉。

  四、加入月球

  在这一步加入月球,实际上是再创建一个网格对象新实例,只是把纹理进行更改即可,为了代码模块性更好,把两个对象放在一个新类CModel中,在工程中新添加一个类CModel,并声明对象实例。

  

public class cModel{ private cMeshObject mesh1 = null; private cMeshObject mesh2 = null; private bool modelloaded;}

  把窗口代码中的Load()事件,放在CModel中,这次不仅生成了地球,而且生成了月球。

  

public void Load(ref Device device){ mesh1 = new Earth(ref device); mesh2 = new Earth(ref device); if (mesh1.LoadMesh(@"....earth2.x")) {  modelloaded = true; } else {  modelloaded = false; } if (mesh2.LoadMesh(@"....moon.x")) {  mesh2.XLoc += 20.0f;  modelloaded = true; } else {  modelloaded = false; }}

  下面的Update()方法中,参数dir 用来判断是顺时针旋转还是逆时针旋转,另外,地球和月球绕Y轴增加的角度大小不同,也就决定了二者旋转的速度不同。

  

public void Update(int dir){ if(dir  0) {  mesh1.YRot += 0.02f;  mesh2.YRot += 0.05f; } else if(dir  0) {  mesh1.YRot -= 0.02f;  mesh2.YRot -= 0.05f; }}

  在下面的render()方法中,生成显示月球和地球:

  

public void Render(ref Device device){ device.Transform.World = Matrix.Identity; if(modelloaded) {  mesh1.Render();  mesh2.Render(); }}

  把窗口代码中的加入灯光的方法,也放在此类中:

  

public void LoadLights(ref Device device){ device.Lights[0].Type = LightType.Directional; device.Lights[0].Diffuse = Color.White; device.Lights[0].Position = new Vector3(0.0f, 0.0f, 25.0f); device.Lights[0].Direction = new Vector3(0, 0, -1);}public void Light(ref Device device){ device.Lights[0].Update(); device.Lights[0].Enabled = true;}

  五、与鼠标交互操作

  为了实现与键盘、鼠标交互,新添加一个类:CMouse,添加引用Microsoft.DirectX.DirectInput,并添加命名空间。加入相关变量:

  

private Microsoft.DirectX.DirectInput.Device mouse = null;public System.Threading.AutoResetEvent MouseUpdated;private float x, y, z = 0.0f;private byte[] buttons;

  在下面的构造函数代码中,首先创建鼠标设备,并初始化回调事件:

  

public CMouse(System.Windows.Forms.Control control){ mouse = new Microsoft.DirectX.DirectInput.Device(SystemGuid.Mouse); mouse.SetCooperativeLevel(control, CooperativeLevelFlags.Background | CooperativeLevelFlags.NonExclusive); mouse.Properties.AxisModeAbsolute = false; MouseUpdated = new System.Threading.AutoResetEvent(false); mouse.SetEventNotification(MouseUpdated); mouse.Acquire(); Update();}

  下面的Update()方法中获得鼠标的坐标值,并赋给私有成员变量:

  

public void Update(){ MouseState state = mouse.CurrentMouseState; x = state.X; y = state.Y; z = state.Z; buttons = state.GetMouseButtons();}

  还需要有一个函数来检测鼠标左键是否按下:

  

public bool LeftButtonDown{ get {  bool a;  return a = (buttons[0] != 0); }}

  六、大结局

  现在已经做完了准备工作,返回到窗口代码中,需要对这里的代码重新进行一些调整:

  在图形初始化函数中创建一个CModel类及CMouse类:

  

private CModel model = null;private CMouse mouse = null;private bool leftbuttondown = false;private float mousexloc;

  添加对鼠标初始化的方法:

  

public void InitializeInput(){ mouse = new CMouse(this);}

  添加UpdateInputState()方法,当按下鼠标左键时,将leftbuttondown值设置为真,当鼠标抬起时,将mousexloc置0:

  

private void UpdateInputState(){ mouse.Update(); if (mouse.LeftButtonDown) {  if(leftbuttondown == false)  {   mousexloc = 0.0f;   leftbuttondown = true;  }  else  {   mousexloc = -mouse.X;  } } else {  leftbuttondown = false;  mousexloc = 0.0f; }}

  在此程序中,只对X值进行了操作,即只能左右转。

  Render()方法更新如下:

  

public void Render(){ UpdateInputState(); device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, Color.DarkGray, 1.0f, 0); SetupCamera(); device.BeginScene(); model.Update((int)mousexloc); model.Light(ref device); model.Render(ref device); device.EndScene(); device.Present();}

  最后更改Main()主函数:

  

static void Main(){ using (Form1 EarthForm = new Form1()) {  EarthForm.InitializeGraphics();  EarthForm.InitializeInput();  EarthForm.Show();  while(EarthForm.Created)  {   EarthForm.Render();   Application.DoEvents();  }  EarthForm.Dispose(); }

  运行程序,按下鼠标左键拖动,即可旋转月球与地球。

来源:http://www.tulaoshi.com/n/20160219/1610597.html

延伸阅读
首先,我们要认识的是device,这也是Direct3D的基本The Direct3D 设备所有的有关绘图的Direct3D类的根就是device类,你可以认为这个类就是你电脑中的真实设备,所有在你所绘制的场景中的的图形对象都是从这个类衍生出来的。在这里,device有三个构造函数,现在,我们只准备使用其中的一个,在后面的章节中,我们将介绍另外的构造函数。我们要...
题目:猴子吃桃问题:猴子第一天摘下若干个桃子,当即吃了一半,还不瘾,又多吃了一个,第二天早上又将剩下的桃子吃掉一半,又多吃了一个。以后天天早上都吃了前一天剩下的一半零一个。到第10天早上想再吃时,见只剩下一个桃子了。求第一天共摘了多少。 1.程序分析:采取逆向思维的方法,从后往前推断。 ...
标签: flash教程
本实例最终效果如图1所示: 图1 旋转三棱锥最终效果 1.首先启动,新建一个影片,设置影片舞台大小为253px*205px(单位为象素),影片背景色为白色. 2.为了方便下面的制作,这里依次选择查看/网格/显示网格菜单命令,打开影片的捕捉网格功能。 3.选择工具箱中的直线工具,在舞台中绘制出三棱锥的轮廓,...
出现问题 解决办法 本人win764位 ,打开游戏遇到3d错误,最终解决。参考其他朋友说的安装IE10会自动安装win7的Direct3D 11.1,尝试之后确实有效。 网上搜的很多都是流氓软件,用电脑管家的软件管理进行查找,安装时间比较长,耐心等待安装完重启电脑就能正常进入游戏!

经验教程

886

收藏

88
微博分享 QQ分享 QQ空间 手机页面 收藏网站 回到头部