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

Posted

篇首语:少年意气强不羁,虎胁插翼白日飞。本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识大全 C#+Direct3D9.0开发实例之月亮绕着地球转相关的知识,希望对你有一定的参考价值。

C#+Direct3D9.0开发实例之月亮绕着地球转  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!

一 建立空窗体   新建一个工程 添加引用 并导入名称空间   加入一个设备对象变量 private Microsoft DirectX Direct D Device device = null;  添加初始化图形函数 并在这里面对设备对象进行实例化 public void InitializeGraphics() PresentParameters presentParams = new PresentParameters(); presentParams Windowed = true; presentParams SwapEffect = SwapEffect Flip; presentParams AutoDepthStencilFormat = DepthFormat D ; presentParams EnableAutoDepthStencil = true; device = new Microsoft DirectX Direct D Device( Microsoft DirectX Direct D DeviceType Hardware this  CreateFlags HardwareVertexProcessing presentParams);  当程序执行时 需要绘制场景 代码在这个函数里 public void Render() // 清空设备 并准备显示下一帧  device Clear(ClearFlags Target | ClearFlags ZBuffer Color Black f ); // 设置照相机的位置 SetupCamera(); //开始场景 device BeginScene(); if(meshLoaded)   mesh Render(meshLoc);  device EndScene(); //显示设备内容  device Present();  设置照相机的位置 private void SetupCamera() device Transform Projection = Matrix PerspectiveFovLH((float)Math PI / this Width / this Height f f); device Transform View = Matrix LookAtLH(new Vector ( f f f) new Vector ( f f f) new Vector ( ));  现在改变主函数 调用我们写的初始化函数 并显示场景 [STAThread]static void Main()  using (Form EarthForm = new Form ())   EarthForm InitializeGraphics();  EarthForm Show();  while(EarthForm Created)     EarthForm Render();   Application DoEvents();    EarthForm Dispose();  运行程序 会显示一个空的窗体 二 加入地球   在这一步里需创建一个 D网格对象 来作为要显示的地球 为此 在工程中新加入一个类Earth 此类可以包含所创建的网格对象的信息   加入一些相关变量 含义见注释 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 > ))     mMaterials = new Material[mtrl Length];   mTextures = new Texture[mtrl Length];   // 得到材质和纹理   for (int i = ; i < mtrl Length; i++)       mMaterials[i] = mtrl[i] Material D;    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 = ; i < mMaterials Length; i++)   meshDevice Material = mMaterials[i];  meshDevice SetTexture( mTextures[i]);  mMesh DrawSubset(i);   现在回到窗体代码中 添加引用网格对象的相关变量 private Earth mesh = null;private Matrix meshLoc;private bool meshLoaded = false;  在图形初始化函数中 需要对网格对象进行初始化 加入下面的代码 meshLoc = Matrix Identity;meshLoc M = f;mesh = new Earth(ref device meshLoc);if (mesh LoadMesh(@ \\ \\earth x )) meshLoaded = true;  代码第一句把网格对象的位置定为原点 接着偏移X轴 个单位 接下来从文件中得到此 X文件 如果成功设置 meshLoaded置为真 注意 这里有一个 X文件 在源代码中有此文件   在设置相机的函数中 加入一盏灯光 device Lights[ ] Type = LightType Directional;device Lights[ ] Diffuse = Color White;device Lights[ ] Direction = new Vector ( );device Lights[ ] Update();device Lights[ ] Enabled = true;

  此灯光较简单 仅为一个直射型白光灯 最后 在Render()方法中 调用网格对象的Render()方法 以显示地球

  

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

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

  加入相应的属性代码

   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 Vector ( f f f) xrot)); objdevice MultiplyTransform(TransformType World Matrix RotationAxis(new Vector ( f f f) yrot)); objdevice MultiplyTransform(TransformType World Matrix RotationAxis(new Vector ( f f f) zrot)); objdevice MultiplyTransform(TransformType World Matrix Scaling(xscale yscale zscale)); return;

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

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

  现在 由于在基类中可以设置对象位置 因此 可以把与locationOffset相关 即与设置位置的变量及语句注释掉 四 加入月球   在这一步加入月球 实际上是再创建一个网格对象新实例 只是把纹理进行更改即可 为了代码模块性更好 把两个对象放在一个新类CModel中 在工程中新添加一个类CModel 并声明对象实例

   public class cModel private cMeshObject mesh = null; private cMeshObject mesh = null; private bool modelloaded;

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

   public void Load(ref Device device) mesh = new Earth(ref device); mesh = new Earth(ref device); if (mesh LoadMesh(@ \\ \\earth x ))   modelloaded = true;  else   modelloaded = false;  if (mesh LoadMesh(@ \\ \\moon x ))   mesh XLoc += f;  modelloaded = true;  else   modelloaded = false; 

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

   public void Update(int dir) if(dir > )   mesh YRot += f;  mesh YRot += f;  else if(dir < )   mesh YRot = f;  mesh YRot = f; 

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

   public void Render(ref Device device) device Transform World = Matrix Identity; if(modelloaded)   mesh Render();  mesh Render(); 

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

   public void LoadLights(ref Device device) device Lights[ ] Type = LightType Directional; device Lights[ ] Diffuse = Color White; device Lights[ ] Position = new Vector ( f f f); device Lights[ ] Direction = new Vector ( ); public void Light(ref Device device) device Lights[ ] Update(); device Lights[ ] Enabled = true;

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

   private Microsoft DirectX DirectInput Device mouse = null;public System Threading AutoResetEvent MouseUpdated;private float x y z = f;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[ ] != ); 

  六 大结局   现在已经做完了准备工作 返回到窗口代码中 需要对这里的代码重新进行一些调整   在图形初始化函数中创建一个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置

   private void UpdateInputState() mouse Update(); if (mouse LeftButtonDown)   if(leftbuttondown == false)     mousexloc = f;   leftbuttondown = true;    else     mousexloc = mouse X;    else   leftbuttondown = false;  mousexloc = f; 

  在此程序中 只对X值进行了操作 即只能左右转   Render()方法更新如下

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

  最后更改Main()主函数

   static void Main()  using (Form EarthForm = new Form ())   EarthForm InitializeGraphics();  EarthForm InitializeInput();  EarthForm Show();  while(EarthForm Created)     EarthForm Render();   Application DoEvents();    EarthForm Dispose(); 

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

cha138/Article/program/net/201311/13213

相关参考

宇宙探秘 月亮起源之谜

   每当我们举头望明月之时,总不禁自问:这美丽的天体是哪里来的呢?尽管我们从小都听过许许多多有关月亮的传说,但我们心里清楚,神话终究不能取代科学。那么,月亮起源的科学解

为什么晚上太阳公公要回家?

首先要知道宇宙中的星体都是转动的,日月同辉是一种天文现象,地球自转,月球绕地球转,地球又带着月亮一起绕太阳转,月亮和太阳的位置就不断变化。  因为地球会自转,晚上地球转到了太阳的另一半,有一面是面对太

我国明代哲学家王守仁认为“心外无物”,月亮、太阳以及世界上的万物都存在于人心之中,都是心之意念的产物。这是__的思

我国明代哲学家王守仁认为“心外无物”,月亮、太阳以及世界上的万物都存在于人心之中,都是心之意念的产物。这是_____的思想。A、客观唯心主义B、主观唯心主义C、机械唯物主义D、庸俗唯物主义答案:B解析

月亮变你也变之满月篇

人们常说,“月有阴睛圆缺,人有悲欢离合”。此语也形象地说明。我们的命运与月亮一样变化不定,人月同理。现在。科学家已经有了充分的依据证明。我们的身体与情绪确实随着月亮的阴睛圆缺发生着微妙的变化。满月,即

月亮变你也变之残月篇

人们常说“月有阴晴圆缺,人有悲欢离合”,此语也形象地说明,我们的命运与月亮一样变化不定,人月同理。现在,科学家已经有了充分的依据证明,我们的身体与情绪确实随着月亮的阴晴圆缺发生着微妙的变化。残月就是月

月亮变你也变之新月篇

人们常说“月有阴晴圆缺,人有悲欢离合”,此语也形象地说明,我们的命运与月亮一样变化不定,人月同理。现在,科学家已经有了充分的依据证明,我们的身体与情绪确实随着月亮的阴晴圆缺发生着微妙的变化。有一种人,

知识大全 请问~一年里,为什么农历要多闰一个月?

请问~一年里,为什么农历要多闰一个月??今年农历闰五月。为什么农历会闰月呢?原来,在我国流传很广的农历,主要是依据月亮绕地球一周时间的多少.而又兼顾到地球和太阳的关系定出来的。阴历的月份是是按月亮绕地

知识大全 VC.NET的Direct3D极速入门宝典

VC.NET的Direct3D极速入门宝典  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  听说D

知识大全 实例解析C++/CLI之代理与事件

实例解析C++/CLI之代理与事件  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!在C++/CLI中

知识大全 实例解析C++/CLI之静态构造函数

实例解析C++/CLI之静态构造函数  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!就某些类而言当在