×

Managed DirectX +C# 开发(入门篇)4

Kalet Kalet 发表于2009-03-20 12:00:14 浏览180 评论0

抢沙发发表评论

第六章 Mesh对象

一、什么是Mesh?

前面已经接触过Mesh类,在这里则对它进行详细介绍
Managed DirectX +C# 开发(入门篇)4
Mesh可以用来储存任何类型的图形数据,但主要用来封装复杂的模型。Mesh类同样也有一些用来提高渲染物体性能的方法。使用Mesh可以从外部文件读入3D的模型文件,比如MaYa文件,这样就可以在3D Max或MaYa等软件中做好模型,然后读入程序。

Mesh对象内部也包含了很多几何体的模型。

Mesh对象包位于Direct3D扩展库(D3DX Direct3D Extensions library)中。注意添加对Direct3DX.dll程序集的引用。

Mesh类有三个构造函数。Mesh类有几个静态方法用来创建或加载不同的模型。


所有的Mesh对象都包含了一个顶点缓冲和一个索引缓存,除此之外,他还包含了一个属性缓冲(attribute buffer)。

二、使用Mesh

在前面,已经使用以下方法建立了Mesh对象:

private Mesh mesh = null;

mesh = Mesh.Box(device,2.0f,2.0f,2.0f);

这样就建立了一个长宽高都为2的立方体。


如果创建一个圆柱或园台或园锥则是这样的:

mesh = Mesh.Cylinder(device,2.0f,2.0f,2.0f,36,36);

第二和第三个参数Radius1,Radius2 表示圆柱体的下底面和上底面半径,必须为非负;第四个参数Length 表示圆柱体在Z方向的高度;第五个参数Slices 表示沿中心轴的片段数量,第六个参数Stacks 表示沿主轴的“堆数量。(类似于由经、纬线分成的水平和垂直方向上的块数;


创建一个多边形方法是:

mesh = Mesh.Polygon(device,2.0f,8);

第二个参数Length 表示多边形每一边的长度,第三个参数Sides表示有多少条边

mesh = Mesh.Sphere(device,2.0f,36,36);

第二个参数Radius表示球体的半径,第三个参数Slices和第四个参数Stacks的含义与Cylinder的相同。

mesh = Mesh.Torus(device,0.5f,2.0f,36,18)

第二个参数InnerRadius 圆环的内径,第三个参数OutterRadius 圆环的外径,第四个Sides横截面上的面数,第五个参数Rings横截面上的环数,前两个值必须为非负数,后两个必须大于等于三。


如果创建一个茶壶,则代码为:

       mesh1=Mesh.Teapot(device);

执行结果:


现在看看Render()函数:

private void Render()

         {

              if (device == null)

                   return;

              device.Clear(ClearFlags.Target, System.Drawing.Color.Black , 1.0f, 0);

              SetupCamera();

              device.BeginScene();

                  

              Material boxMaterial = new Material();

              boxMaterial.Ambient = Color.Pink;

              boxMaterial.Diffuse = Color.White;

              device.Material = boxMaterial;

             

              device.Transform.World=Matrix.Translation(0,50,0);

              device.Transform.World=Matrix.Identity;

              mesh1.DrawSubset(0);
Managed DirectX +C# 开发(入门篇)4
              device.EndScene();

              device.Present();

             

         }

此次和前面不同的是,给场景设置了一个材质,所谓材质是指可以指定物体如何反射环境光以及散射光,及镜面高光,还可以指定物体是否完全反射光线。 设置完成后,把材质赋予了device的Material属性,这样Direct3D就知道渲染时使用哪种材质。


代码mesh1.DrawSubset(0);代码里传递了一个参数0;这是什么意思呢?

Mesh会被分为一系列的子集(subsets),同时使用DrawSubset()方法来渲染。使用Mesh类创建的普通图元总是只有一个基于0的子集。所以使用了mesh.DrawSubset(0)

三、读入外部文件

使用Mesh.FormFile()和Mesh.FromStream()这两个方法可以读入外部的.X文件,但3Dmax建立的模型默认并不是.X文件,因此,你需要导出为.X文件,或使用专门工具进行转化。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材质文件和值。

);

adjacency参数是一个“out”参数,表示在这个方法结束后adjacency会被分配并且传递出去,它将返回相邻信息。ExtendedMaterial类保存了普通的Direct3D材质和一个加载为纹理的字符串。这个字符串通常是使用的纹理或资源文件名,因为加载纹理是由程序来进行的,也可以是任何用户提供的字符串。EffectInstance参数描述了用于mesh的HLSL材质文件和值。可以根据需要选择具有不同参数的方法重载。

在程序中,如果读入的这个.X文件有材质或者纹理,就需要根据材质和纹理的大小建立数组以保存这些纹理和材质。因为mesh中可能有许多不同的子集,所以需要分别创建一个材质和纹理的数组以针对于每一个子集。Mesh会自动地把每一个子集和这些子集的材质纹理一一对座。

使用循环可以把ExtenedMaterial中的数据拷贝到meshMaterials中。如果子集中还包含纹理信息的话,可以使用TextureLoader.FromFile方法来创建纹理。这个方法接受两个参数,device以及作为纹理的文件名,这个方法可要比以前使用的System.Drawing.Bitmap快许多。

以下为读入一外部文件的一段代码:

private void LoadMesh(string file)

        {

            ExtendedMaterial[] mtrl;


            // 载入mesh

            mesh = Mesh.FromFile(file, MeshFlags.Managed, device, out mtrl);

             // 如果有材质,则保存它们;

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

           {

                meshMaterials = new Material[mtrl.Length];

                meshTextures = new Texture[mtrl.Length];


                // 存储每一个材质和纹理;

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

                {

                    meshMaterials[i] = mtrl[i].Material3D;

                    if ((mtrl[i].TextureFilename != null) && (mtrl[i].TextureFilename != string.Empty))

                    {

                        //如果有纹理,则载入;

                        meshTextures[i] = TextureLoader.FromFile(device, @"..\..\" + mtrl[i].TextureFilename);

                    }

                }
Managed DirectX +C# 开发(入门篇)4
            }

        }


群贤毕至

访客