微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

XNA4 加载模型文件 适用于WP7 Silverlight5

SKLReader


using System;
using System.Collections.Generic;
using System.Linq;using
System.Text;using System.IO;
namespace SknImporter
{
    class SklReader
    {
        public struct SklHeader
        {
public byte[] version;
            public int numObjects;
            public int skeletonHash;
            public int numElements;
        }
        public struct SklBone
        {
            //length :32           
            public int index;
            public string name;
            public int parent;
            public float scale;
            public float[,] matrix;
        }

        public List<SklBone> Bones = new List<SklBone>();
        public SklReader(string file)
        {
            SklHeader header = new SklHeader(); FileStream fs = File.Open(file,FileMode.Open); BinaryReader reader = new BinaryReader(fs);
            header.version = reader.ReadBytes(8); header.numObjects = reader.ReadInt32(); header.skeletonHash = reader.ReadInt32(); header.numElements = reader.ReadInt32();
            for (int b = 0; b < header.numElements; b++)
            {
                SklBone bone = new SklBone(); bone.index = b; bone.name = Encoding.ASCII.GetString(reader.ReadBytes(32)).Replace("\0",""); bone.parent = reader.ReadInt32(); bone.scale = reader.ReadSingle(); bone.matrix = new float[3,4]; for (int y = 0; y < 3; y++) { for (int x = 0; x < 4; x++) { bone.matrix[y,x] = reader.ReadSingle(); } }
                Bones.Add(bone);
            } fs.Close();
        }
    }
}

 

SknImporter


using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content.Pipeline;
using Microsoft.Xna.Framework.Content.Pipeline.Graphics;
using Microsoft.Xna.Framework.Content.Pipeline.Processors;
using System.IO;


// Todo: 将这些项替换为处理器输入和输出类型。


namespace SknImporter
{
    /// <summary>
    /// 此类将由 XNA Framework 内容管道实例化,
    /// 以便将自定义处理应用于内容数据,将对象转换用于类型 TInput 到
    /// 类型 TOnput 的改变。如果处理器希望改变数据但不更改其类型,
    /// 输入和输出类型可以相同。
    ///
    /// 这应当属于内容管道扩展库项目的一部分。
    ///
    /// Todo: 更改 ContentProcessor 属性以为此处理器指定
    /// 正确的显示名称
    /// </summary>
   [ContentImporter(".skn",CacheImportedData = true,DefaultProcessor = "SKN Processor")]
    public class SknImporter : ContentImporter<NodeContent>
    {
       ContentImporterContext importerContext;


       // The root NodeContent of our model
       private NodeContent rootNode;


       // All vertex data in the file
       private List<Vector3> positions;
       private List<Vector2> texCoords;
       private List<Vector3> normals;




       // The current mesh being constructed
       private MeshBuilder meshBuilder;


       private int textureCoordinateDataIndex;
       private int normalDataIndex;


       private int[] positionMap;
       public override NodeContent Import(string filename,ContentImporterContext context)
       {

           //这句话需要被注释掉,实际使用的话
           System.Diagnostics.Debugger.Launch();
           importerContext = context;


           string sklPath = Path.GetDirectoryName(filename) + "\\" + Path.GetFileNameWithoutExtension(filename) + ".skl";
           importerContext.AddDependency(sklPath);








           rootNode = new NodeContent();
           rootNode.Identity = new ContentIdentity(filename);


           SklReader sklReader = new SklReader(sklPath);
           SknReader sknReader = new SknReader(filename);
           positions = new List<Vector3>();
           texCoords = new List<Vector2>();
           normals = new List<Vector3>();


           importerContext.Logger.LogWarning(null,rootNode.Identity,sklReader.Bones.Count.ToString("X2"));


           foreach (var item in sknReader.materialList)
           {
               for (int i = item.startVertex; i < item.numVertices; i++)
               {
                   SkinModelVertex vertex = sknReader.modelData.verteces;


                   positions.Add(new Vector3(sknReader.modelData.verteces.position[0],
                                            sknReader.modelData.verteces.position[1],
                                            sknReader.modelData.verteces.position[2]));


                   texCoords.Add(new Vector2(sknReader.modelData.verteces.texcoords[0],
                                            sknReader.modelData.verteces.texcoords[1]));


                   normals.Add(new Vector3(sknReader.modelData.verteces.normal[0],
                                           sknReader.modelData.verteces.normal[1],
                                           sknReader.modelData.verteces.normal[2]));
               }


               StartMesh(item.name);
               Buildindex(sknReader);
               MeshContent mc = FinishMesh();
               positions.Clear();
               texCoords.Clear();
               normals.Clear();
               mc.Children.Add(BuildBone(sklReader));
               rootNode.Children.Add(mc);
           }


           #region Testing Build Mesh with Bones
           //foreach (var item in sknReader.materialList)
           //{
           //    for (int i = item.startVertex; i < item.numVertices; i++)
           //    {
           //        SkinModelVertex vertex = sknReader.modelData.verteces;


           //        texCoords.Add(new Vector2(vertex.texcoords[0],
           //                                 vertex.texcoords[1]));


           //        normals.Add(new Vector3(vertex.normal[0],
           //                                vertex.normal[1],
           //                                vertex.normal[2]));
           //    }
           //}




           //foreach (var bone in sklReader.Bones)
           //{
           //    List<SkinModelVertex> exsitVexter = new List<SkinModelVertex>();
           //    List<int> addedVertex = new List<int>();
           //    foreach (var vertex in sknReader.modelData.verteces)
           //    {
           //        for (int i = 0; i < 4; i++)
           //        {
           //            if(vertex.boneIndex == bone.index)
           //            {
           //                exsitVexter.Add(vertex);
           //                positions.Add(new Vector3(
           //                                    vertex.position[0],
           //                                    vertex.position[1],
           //                                    vertex.position[2]));
           //            }
           //        }
           //    }
           //    StartMesh(bone.name);
           //    BuildindexByBone(sknReader,exsitVexter);
           //    MeshContent mc = FinishMesh();
           //    rootNode.Children.Add(mc);
           //    positions.Clear();
           //}
           #endregion


           return rootNode;
       }
       private BoneContent BuildBone(SklReader sklReader)
       {
           List<BoneContent> bone = new List<BoneContent>();
           foreach (var item in sklReader.Bones)
           {
               BoneContent bc = new BoneContent();
               bc.Transform = new Matrix(
                    item.matrix[0,0],item.matrix[0,1],2],3],
                    item.matrix[1,item.matrix[1,
                    item.matrix[2,item.matrix[2,
                    0f,0f,0f);
               bc.Name = item.name;
               bone.Add(bc);
           }
           BoneContent rootBone = new BoneContent();
           BoneContent tmpBone;
           int max = bone.Count - 1;


           while (max > 0)
           {
               if (sklReader.Bones[max].parent >= 0)
                   tmpBone = bone[sklReader.Bones[max].parent];
               else
                   tmpBone = rootBone;
               tmpBone.Children.Add(bone[max]);
               bone.RemoveAt(max);
               max--;
           }


           return rootBone;
       }
       private void AddTriangLevertex(int index)
       {
           Vector2 texCoord = Vector2.Zero;
           texCoord = texCoords[index];
           meshBuilder.SetVertexChannelData(textureCoordinateDataIndex,
               texCoord);


           Vector3 normal = Vector3.Zero;
           normal = normals[index];
           meshBuilder.SetVertexChannelData(normalDataIndex,
               normal);


           meshBuilder.AddTriangLevertex(index);
       }
       private void Buildindex(SknReader sknReader)
       {
           for (int i = 0; i < sknReader.modelData.numIndices / 3; i++)
           {
               int a = sknReader.modelData.indices[i * 3];
               int b = sknReader.modelData.indices[i * 3 + 1];
               int c = sknReader.modelData.indices[i * 3 + 2];
               AddTriangLevertex(a);
               AddTriangLevertex(b);
               AddTriangLevertex(c);
           }
       }
       private void BuildindexByBone(SknReader sknReader,List<SkinModelVertex> vertes)
       {
           int i = 0;
           foreach (var item in vertes)
           {
               Vector2 texCoord = Vector2.Zero;
               texCoord = texCoords[item.index];
               meshBuilder.SetVertexChannelData(textureCoordinateDataIndex,
                   texCoord);


               Vector3 normal = Vector3.Zero;
               normal = normals[item.index];
               meshBuilder.SetVertexChannelData(normalDataIndex,
                   normal);


               meshBuilder.AddTriangLevertex(positionMap);
               i++;
           }
       }
       private void StartMesh(string name)
       {
           meshBuilder = MeshBuilder.StartMesh(name);


           // Obj files need their winding orders swapped
           meshBuilder.SwapWindingOrder = true;


           meshBuilder.MergeDuplicatePositions = true;


           // Add additional vertex channels for texture coordinates and normals
           textureCoordinateDataIndex = meshBuilder.CreateVertexChannel<Vector2>(
               VertexChannelNames.TextureCoordinate(0));
           normalDataIndex =
               meshBuilder.CreateVertexChannel<Vector3>(VertexChannelNames.normal());


           // Add each position to this mesh with CreatePosition
           positionMap = new int[positions.Count];
           for (int i = 0; i < positions.Count; i++)
           {
               // positionsMap redirects from the original positions in the order
               // they were read from file to indices returned from CreatePosition
               positionMap = meshBuilder.CreatePosition(positions);
           }
       }


       private MeshContent FinishMesh()
       {
           MeshContent meshContent = meshBuilder.FinishMesh();


           //// Groups without any geometry are just for transform
           //if (meshContent.Geometry.Count > 0)
           //{
           //    // Add the mesh to the model
           //   // rootNode.Children.Add(meshContent);
           //}
           ////else
           ////{
           ////    // Convert to a general NodeContent
           ////    NodeContent nodeContent = new NodeContent();
           ////    nodeContent.Name = meshContent.Name;


           ////    // Add the transform-only node to the model
           ////    rootNode.Children.Add(nodeContent);
           ////}


           meshBuilder = null;


           return meshContent;
       }


    }
}


SknReader


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Runtime.InteropServices;


namespace SknImporter
{
    [StructLayout(LayoutKind.Sequential)]
    public struct SkinModelHeader
    {
        //Structure for the Header in skn files
        public int magic;
        public short numMaterials;
        public short numObjects;
    };
    [StructLayout(LayoutKind.Sequential)]
    public struct SkinModelMaterial
    {
        //Structure for a material block in skn files
        public int matIndex;


        public string name;
        public int startVertex;
        public int numVertices;
        public int startIndex;
        public int numIndices;
    };
    [StructLayout(LayoutKind.Sequential)]
    public struct SkinModelVertex
    {
        //Vertex block in skn files
        public float[] position;
        public char[] boneIndex;
        public float[] weights;
        public float[] normal;
        public float[] texcoords;
        public int index;
    };


    public struct SkinModelData
    {
        //data block in skn files
        public int numIndices;
        public int numVertices;
        public List<short> indices;
        public List<SkinModelVertex> verteces;
    };


    class SknReader
    {
        public SkinModelData modelData = new SkinModelData();
        public List<SkinModelMaterial> materialList = new List<SkinModelMaterial>();
        FileStream fileStream;
        string fpath;
        public SknReader(string path)
        {
            fpath = path;
            fileStream = System.IO.File.Open(path,FileMode.Open);


            BinaryReader reader = new BinaryReader(fileStream);


            int headerSize = Marshal.SizeOf(typeof(SkinModelHeader));
            //SkinModelHeader header =(SkinModelHeader)BytesToStruct(reader.ReadBytes(headerSize),typeof(SkinModelHeader));
            SkinModelHeader header = new SkinModelHeader();
            header.magic = reader.ReadInt32();
            header.numObjects = reader.ReadInt16();
            header.numMaterials = reader.ReadInt16();


            if (header.numMaterials == 1)
            {
                int matCount = reader.ReadInt32();
                if (matCount > 0)
                {
                    SkinModelMaterial mat = new SkinModelMaterial();
                    for (int mc = 0; mc < matCount; mc++)
                    {
                        mat.matIndex = mc;
                        mat.name = ASCIIEncoding.ASCII.GetString(reader.ReadBytes(64)).Replace("\0","");
                        mat.startVertex = reader.ReadInt32();
                        mat.numVertices = reader.ReadInt32();
                        mat.startIndex = reader.ReadInt32();
                        mat.numIndices = reader.ReadInt32();
                        materialList.Add(mat);
                    }
                }
            }


            modelData.numIndices = reader.ReadInt32();
            modelData.numVertices = reader.ReadInt32();
            modelData.indices = new List<short>();
            modelData.verteces = new List<SkinModelVertex>();
            for (int i = 0; i < modelData.numIndices; i++)
            {
                short idx = 0;
                idx = reader.ReadInt16();
                modelData.indices.Add(idx);
            }


            for (int i = 0; i < modelData.numVertices; i++)
            {
                SkinModelVertex vertex = new SkinModelVertex();
                vertex.index = i;
                vertex.position = new float[3];
                vertex.boneIndex = new char[4];
                vertex.weights = new float[4];
                vertex.normal = new float[3];
                vertex.texcoords = new float[2];


                vertex.position[0] = reader.ReadSingle();
                vertex.position[1] = reader.ReadSingle();
                vertex.position[2] = reader.ReadSingle();


                // vertex.boneIndex = reader.ReadInt32();


                vertex.boneIndex[0] = reader.ReadChar();
                vertex.boneIndex[1] = reader.ReadChar();
                vertex.boneIndex[2] = reader.ReadChar();
                vertex.boneIndex[3] = reader.ReadChar();


                vertex.weights[0] = reader.ReadSingle();
                vertex.weights[1] = reader.ReadSingle();
                vertex.weights[2] = reader.ReadSingle();
                vertex.weights[3] = reader.ReadSingle();


                vertex.normal[0] = reader.ReadSingle();
                vertex.normal[1] = reader.ReadSingle();
                vertex.normal[2] = reader.ReadSingle();


                vertex.texcoords[0] = reader.ReadSingle();
                vertex.texcoords[1] = reader.ReadSingle();


                modelData.verteces.Add(vertex);
            }
            reader.Close();
        }
    }
}


DEMO CODE


using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Media; namespace LOL_MOD_disPLAY {     /// <summary>     /// 这是游戏的主类型     /// </summary>     public class Game1 : Microsoft.Xna.Framework.Game     {         GraphicsDeviceManager graphics;         SpriteBatch spriteBatch;         Camera camera;         public Game1()         {             graphics = new GraphicsDeviceManager(this);             Content.RootDirectory = "Content";             graphics.PreferredBackBufferWidth = 800;             graphics.PreferredBackBufferHeight = 600;         }         /// <summary>         /// 允许游戏在开始运行之前执行其所需的任何初始化。         /// 游戏能够在此时查询任何所需服务并加载任何非图形         /// 相关的内容调用 base.Initialize 将枚举所有组件         /// 并对其进行初始化。         /// </summary>         protected override void Initialize()         {             // Todo: 在此处添加初始化逻辑             base.Initialize();         }         /// <summary>         /// 对于每个游戏会调用一次 LoadContent,         /// 用于加载所有内容。         /// </summary>         ///         Model teemo;         Texture2D texture;         string name = "Ryze";         protected override void LoadContent()         {             // 创建新的 SpriteBatch,可将其用于绘制纹理。             spriteBatch = new SpriteBatch(GraphicsDevice);             teemo = Content.Load<Model>(name);             texture = Content.Load<Texture2D>(name+"_texture");             camera = new Camera(this);             this.Components.Add(camera);             // Todo: 在此处使用 this.Content 加载游戏内容         }         /// <summary>         /// 对于每个游戏会调用一次 UnloadContent,         /// 用于取消加载所有内容。         /// </summary>         ///         protected override void UnloadContent()         {             // Todo: 在此处取消加载任何非 ContentManager 内容         }         /// <summary>         /// 允许游戏运行逻辑,例如更新全部内容、         /// 检查冲突、收集输入信息以及播放音频。         /// </summary>         /// <param name="gameTime">提供计时值的快照。</param>         protected override void Update(GameTime gameTime)         {             // 允许游戏退出             if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.pressed)                 this.Exit();             // Todo: 在此处添加更新逻辑             base.Update(gameTime);         }         /// <summary>         /// 当游戏该进行自我绘制时调用此项。         /// </summary>         /// <param name="gameTime">提供计时值的快照。</param>         protected override void Draw(GameTime gameTime)         {             GraphicsDevice.Clear(Color.CornflowerBlue);             Matrix world = Matrix.CreateWorld(new Vector3(-0,-20,-0),Vector3.UnitZ,Vector3.Up) ;             Model model = teemo;             Matrix[] modelTransforms = new Matrix[model.Bones.Count];             model.copyAbsoluteBoneTransformsTo(modelTransforms);             foreach (ModelMesh mesh in model.Meshes)             {                 foreach (BasicEffect effect in mesh.Effects)                 {                     effect.TextureEnabled = true;                     effect.Texture = texture;                     effect.World =Matrix.CreateTranslation(new Vector3 (0,0))* Matrix.CreateRotationY((float)gameTime.TotalGameTime.TotalMilliseconds / 1000f) * modelTransforms[mesh.ParentBone.Index] * world ;                     effect.View = camera.View;                     effect.Projection = camera.Projection;                 }                 mesh.Draw();             }             // Todo: 在此处添加绘图代码             base.Draw(gameTime);         }     } }

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐