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

24 篇文章 0 订阅
15 篇文章 0 订阅

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], item.matrix[0, 2], item.matrix[0, 3],
                    item.matrix[1, 0], item.matrix[1, 1], item.matrix[1, 2], item.matrix[1, 3],
                    item.matrix[2, 0], item.matrix[2, 1], item.matrix[2, 2], item.matrix[2, 3],
                    0f, 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,-20,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);
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值