您的位置:首页 > 其它

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

2012-10-25 20:29 176 查看
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);

}

}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: