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

来源:互联网 发布:淘宝是cs还是bs 编辑:程序博客网 时间:2024/06/05 19:07
  
第六章 Mesh对象
一、什么是Mesh?
前面已经接触过Mesh类,在这里则对它进行详细介绍
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);
              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);
                    }
                }
            }
        }
 
 
 
原创粉丝点击