接下来我们要使用mesh读入.x文件,关于.x文件,其实可以说很多,我们可以用外部的工具例如3ds max来建立.3ds文件,然后利用微软提供给我们的工具转换成.x文件,如果你同时会用3ds你也许会问,那材质怎么办? 你不用担心,.x文件能自动的包含材质,和动画,所以利用mesh我们可以方便的八我们在3ds max的做品用在游戏中。
.x文件允许自定义的扩展,当然这个我们在以后的内容也会讲到,我们先看怎么使用,顺便提一句,还有一种用得比较多的文件格式.md3格式的文件,也就是quake3使用的文件,如果有机会我也会讲到。
关于3ds文件和.x转换可以参看gameres网站的文章http://www.gameres.com/articles/program/visual/3d/3dinapp.htm
接下来的过程简单的让你无法相信,请看:
private mesh mesh = null; //建立mesh对象
private material[] meshmaterials; //用于保存材质
private texture[] meshtextures; //用于保存纹理
private void loadmesh(string file)
{
extendedmaterial[] mtrl; //保存mesh子集信息,保存material信息
// 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);
}
}
}
}
如果你觉得这里代码比较混乱,没有关系,我们来理一理,首先要说的是mesh类还有两个主要的静态方法可以加载外部模型。这两个方法分别是mesh.formfile和mesh.fromstream。两个方法本质上来说都是一样的,stream方法有更多的重载以适应不同大小的流。mesh.formfile最简单,我们就先只介绍这个,这个方法有很多重载的版本,我们用的是参数最多的一个,这样其他的也都好理解了:
public static mesh fromfile(
string filename, //文件名
meshflags options,// 控制着去哪里以及如何加载数据
device device,// 渲染mesh的device
out graphicsstream adjacency,//保存每个面相邻的3个面
out extendedmaterial materials,// 保存了普通的direct3d材质和一个加载为纹理的字符串,常是使用的纹理或资源文件名
out effectinstance effects //描述了用于mesh的hlsl材质文件和值。
);
我们使用的是一个有4参数的方法:
public static mesh fromfile(
string filename,
meshflags options,
device device,
out extendedmaterial materials
);
接下来,如果读入的这个.x文件有材质或者纹理,就根据材质和纹理的大小建立数组以保存这些纹理和材质。因为mesh中可能有许多不同的子集,所以需要分别创建一个材质和纹理的数组以满足每一个子集的需要。mesh会自动地把每一个子集和这些子集的材质纹理一一对座。
这样我们就完成了一个loadmesh函数,这个函数我们可以用在以后任何需要读入.x文件的地方,十分的方便。
下面我们来看看我们的成果,当然我们还需要在绘图的地方加几句:
for (int i = 0; i < meshmaterials.length; i++)
{
device.material = meshmaterials[i];// 把保存的材质赋予device;
device.settexture(0, meshtextures[i]);// 把纹理赋予device,如果没有就为null
mesh.drawsubset(i);// 根据子集的id调用drawsubset方法
}
好了,现在我们可以在以往的框架的基础上编译一下了,我们可以看到已经读入了一个.x文件,不管怎么样 都是值得庆贺的。我们再看看sdk tutorial6的例子后,发现这个程序的结果可以旋转,其实也很好实现,我们只需要设置一下旋转矩阵就可以了,就像上一张我们讲的那样,在上面那段for前面加上一句就可以了:
device.transform.world = matrix.rotationyawpitchroll(yaw, pitch, roll) * matrix.translation(x, y, z);
好了这样我们也就达到目的了,你也可以随自己的意思设置变换矩阵,很cool吧?
好了,下面是完整的代码,如果大家有什么意见,发到我的blog上吧。大家一起进步。
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;
private mesh mesh = null;
private material[] meshmaterials;
private texture[] meshtextures;
/// <summary>
/// required designer variable.
/// </summary>
private system.componentmodel.container components = null;
private float angle = 0.0f;
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(@”..\..\tiny.x”);
}
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);
}
}
}
}
private void setupcamera()
{
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, 580.0f), new vector3(), 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();
device.beginscene();
// draw our mesh
drawmesh(angle / (float)math.pi, angle / (float)math.pi * 2.0f, angle / (float)math.pi / 4.0f, 0.0f, 0.0f, 0.0f);
device.endscene();
device.present();
this.invalidate();
}
private void drawmesh(float yaw, float pitch, float roll, float x, float y, float z)
{
angle += 0.01f;
device.transform.world = matrix.rotationyawpitchroll(yaw, pitch, roll) * matrix.translation(x, y, z);
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);
}
}
}
}
其实我们都已经发现,到目前为止我们的程序都是遵循一个固定的框架,有时候你发现程序很长,其实从框架角度来看,就没那么长了,怕看长代码的人可以注意一下,同时很多代码都是通用的。下次学习怎么操控mesh。
by sssa2000