科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道基础软件C#+Direct3D9.0开发实例之月亮绕着地球转

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

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

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

作者:dandanCool 来源:blog 2007年11月13日

关键字: 开发实例 Direct3D C#

  • 评论
  • 分享微博
  • 分享邮件
 一、建立空窗体

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

  加入一个设备对象变量:

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,此类可以包含所创建的网格对象的信息。

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

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()方法,以显示地球。


    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章