Init
This commit is contained in:
423
Assets/Scripts/JiuJie/JiuJIeTest.cs
Normal file
423
Assets/Scripts/JiuJie/JiuJIeTest.cs
Normal file
@ -0,0 +1,423 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Xml;
|
||||
using Unity.Collections;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
|
||||
namespace DefaultNamespace
|
||||
{
|
||||
public class JiuJIeTest : MonoBehaviour
|
||||
{
|
||||
public const string meshXml = @"E:\local_workspace\ogre-1.9.1\Build\bin\debug\Npc_cunzhang1.mesh.xml";
|
||||
|
||||
private void Start()
|
||||
{
|
||||
LoadV2();
|
||||
}
|
||||
|
||||
private void LoadV2()
|
||||
{
|
||||
OgreMeshData meshData = new OgreMeshData();
|
||||
meshData.ReadXml(meshXml);
|
||||
|
||||
string baseDir = Path.GetDirectoryName(meshXml);
|
||||
string skeletonXml = Path.Combine(baseDir, meshData.SkeletonLink + ".xml");
|
||||
|
||||
OgreSkeletonData skeletonData = new OgreSkeletonData();
|
||||
skeletonData.ReadXml(skeletonXml);
|
||||
|
||||
Transform meshParent = new GameObject("mesh").transform;
|
||||
meshParent.SetParent(transform, false);
|
||||
|
||||
Transform skeletonParent = new GameObject("skeleton").transform;
|
||||
skeletonParent.SetParent(transform, false);
|
||||
|
||||
Material defaultMaterial = new Material(Shader.Find("Standard"));
|
||||
|
||||
var dic = new Dictionary<string, Transform>();
|
||||
Transform[] bones = new Transform[skeletonData.Bones.Length];
|
||||
for (int i = 0; i < skeletonData.Bones.Length; i++)
|
||||
{
|
||||
OgreSkeletonBone bone = skeletonData.Bones[i];
|
||||
GameObject go = new GameObject(bone.Name);
|
||||
go.transform.SetParent(skeletonParent, false);
|
||||
go.transform.position = bone.Pos;
|
||||
go.transform.rotation = bone.Rot;
|
||||
go.transform.localScale = bone.Scale;
|
||||
dic.Add(go.name, go.transform);
|
||||
bones[i] = go.transform;
|
||||
}
|
||||
|
||||
// 设置层级
|
||||
for (int i = 0; i < skeletonData.BoneHierarchies.Length; i++)
|
||||
{
|
||||
OgreBoneHierarchy h = skeletonData.BoneHierarchies[i];
|
||||
dic[h.Bone].SetParent(dic[h.Parent], false);
|
||||
}
|
||||
|
||||
Matrix4x4[] bindposes = new Matrix4x4[bones.Length];
|
||||
for (int i = 0; i < bones.Length; i++)
|
||||
{
|
||||
var bone = bones[i];
|
||||
bindposes[i] = bone.worldToLocalMatrix * transform.localToWorldMatrix;
|
||||
}
|
||||
|
||||
#if SubMeshs
|
||||
for (int i = 0; i < meshData.SubMeshName.Length; i++)
|
||||
{
|
||||
OgreSubMeshName subMeshName = meshData.SubMeshName[i];
|
||||
OgreSubMesh subMesh = meshData.SubMesh[subMeshName.Index];
|
||||
|
||||
GameObject meshGo = new GameObject(subMeshName.Name);
|
||||
meshGo.transform.SetParent(meshParent, false);
|
||||
var smr = meshGo.AddComponent<SkinnedMeshRenderer>();
|
||||
smr.sharedMaterial = defaultMaterial;
|
||||
|
||||
// 找到这个subMesh最大的索引
|
||||
int min = subMesh.Triangles.Min();
|
||||
int max = subMesh.Triangles.Max();
|
||||
int len = max - min + 1;
|
||||
|
||||
Mesh mesh = new Mesh();
|
||||
mesh.SetVertices(meshData.Vertices, min, len);
|
||||
mesh.SetNormals(meshData.Normals, min, len);
|
||||
for (int j = 0; j < meshData.UVs.Length; j++)
|
||||
mesh.SetUVs(j, meshData.UVs[j], min, len);
|
||||
|
||||
int[] triangles = subMesh.Triangles.ToArray();
|
||||
for (int j = 0; j < triangles.Length; j++)
|
||||
triangles[j] -= min;
|
||||
mesh.SetTriangles(triangles, 0);
|
||||
|
||||
// 骨骼权重
|
||||
List<OgreBoneWeight>[] weights = new List<OgreBoneWeight>[len];
|
||||
|
||||
// 每个顶点的骨骼数量
|
||||
NativeArray<byte> bonesPerVertex = new NativeArray<byte>(len, Allocator.Temp);
|
||||
for (int k = 0; k < meshData.BoneWeights.Length; k++)
|
||||
{
|
||||
OgreBoneWeight bw = meshData.BoneWeights[k];
|
||||
if (bw.VertexIndex >= min && bw.VertexIndex <= max)
|
||||
{
|
||||
int vertexIndex = bw.VertexIndex - min;
|
||||
weights[vertexIndex] ??= new();
|
||||
weights[vertexIndex].Add(bw);
|
||||
bonesPerVertex[vertexIndex] += 1; // 记录骨骼数量
|
||||
}
|
||||
}
|
||||
|
||||
NativeArray<BoneWeight1> boneWeights = new NativeArray<BoneWeight1>(weights.Sum(f => f.Count), Allocator.Temp);
|
||||
int addIndex = 0;
|
||||
foreach (var list in weights)
|
||||
{
|
||||
foreach (var w in list.OrderByDescending(f => f.Weight))
|
||||
{
|
||||
boneWeights[addIndex] = new BoneWeight1
|
||||
{
|
||||
boneIndex = w.BoneIndex,
|
||||
weight = w.Weight
|
||||
};
|
||||
addIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
mesh.SetBoneWeights(bonesPerVertex, boneWeights);
|
||||
mesh.bindposes = bindposes;
|
||||
|
||||
smr.sharedMesh = mesh;
|
||||
smr.bones = bones;
|
||||
smr.rootBone = dic[skeletonData.BoneHierarchies[0].Parent];
|
||||
}
|
||||
#else
|
||||
|
||||
Mesh mesh = new Mesh();
|
||||
mesh.SetVertices(meshData.Vertices);
|
||||
mesh.SetNormals(meshData.Normals);
|
||||
for (int j = 0; j < meshData.UVs.Length; j++)
|
||||
mesh.SetUVs(j, meshData.UVs[j]);
|
||||
|
||||
int indexCount = meshData.SubMesh.Sum(f => f.FaceCount) * 3;
|
||||
NativeArray<int> triangles = new NativeArray<int>(indexCount, Allocator.Temp);
|
||||
int triangleIdx = 0;
|
||||
foreach (var item in meshData.SubMesh)
|
||||
{
|
||||
foreach (var idx in item.Triangles)
|
||||
{
|
||||
triangles[triangleIdx] = idx;
|
||||
triangleIdx += 1;
|
||||
}
|
||||
}
|
||||
|
||||
mesh.SetIndexBufferParams(indexCount, IndexFormat.UInt32);
|
||||
mesh.SetIndexBufferData(triangles, 0, 0, indexCount);
|
||||
mesh.subMeshCount = meshData.SubMeshName.Length;
|
||||
mesh.bindposes = bindposes;
|
||||
|
||||
int indexStart = 0;
|
||||
for (int i = 0; i < meshData.SubMesh.Length; i++)
|
||||
{
|
||||
OgreSubMesh ogreSubMesh = meshData.SubMesh[i];
|
||||
mesh.SetSubMesh(i, new SubMeshDescriptor(indexStart * 3, ogreSubMesh.FaceCount * 3));
|
||||
indexStart += ogreSubMesh.FaceCount;
|
||||
}
|
||||
|
||||
// 骨骼权重
|
||||
int verticesCount = meshData.Vertices.Length;
|
||||
var boneWeightArr = meshData.BoneWeights.OrderBy(f => f.VertexIndex).ThenByDescending(f => f.Weight).ToArray();
|
||||
|
||||
// 每个顶点的骨骼数量
|
||||
NativeArray<byte> bonesPerVertex = new NativeArray<byte>(verticesCount, Allocator.Temp);
|
||||
NativeArray<BoneWeight1> boneWeights = new NativeArray<BoneWeight1>(meshData.BoneWeights.Length, Allocator.Temp);
|
||||
int addIndex = 0;
|
||||
for (int k = 0; k < boneWeightArr.Length; k++)
|
||||
{
|
||||
OgreBoneWeight bw = boneWeightArr[k];
|
||||
int vertexIndex = bw.VertexIndex;
|
||||
bonesPerVertex[vertexIndex] += 1; // 记录骨骼数量
|
||||
boneWeights[addIndex++] = new BoneWeight1 { boneIndex = bw.BoneIndex, weight = bw.Weight };
|
||||
}
|
||||
|
||||
mesh.SetBoneWeights(bonesPerVertex, boneWeights);
|
||||
|
||||
var smr = meshParent.gameObject.AddComponent<SkinnedMeshRenderer>();
|
||||
smr.sharedMesh = mesh;
|
||||
smr.sharedMaterial = defaultMaterial;
|
||||
smr.bones = bones;
|
||||
smr.rootBone = dic[skeletonData.BoneHierarchies[0].Parent];
|
||||
#endif
|
||||
Animation ani = gameObject.GetComponent<Animation>();
|
||||
foreach (var clip in skeletonData.Clips)
|
||||
{
|
||||
clip.legacy = true;
|
||||
ani.AddClip(clip, clip.name);
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadV1()
|
||||
{
|
||||
XmlDocument meshDoc = new XmlDocument();
|
||||
meshDoc.Load(meshXml);
|
||||
|
||||
XmlElement rootNode = meshDoc.DocumentElement;
|
||||
XmlNode sharedGeometryNode = rootNode.GetElementsByTagName("sharedgeometry")[0];
|
||||
XmlNode submeshesNode = rootNode.GetElementsByTagName("submeshes")[0];
|
||||
XmlNode submeshnamesNode = rootNode.GetElementsByTagName("submeshnames")[0];
|
||||
|
||||
int vertexCount = int.Parse(sharedGeometryNode.Attributes["vertexcount"].Value);
|
||||
|
||||
Vector3[] vertices = new Vector3[vertexCount];
|
||||
Vector3[] normals = new Vector3[vertexCount];
|
||||
|
||||
// vertex
|
||||
XmlNode vertexBufferNode1 = sharedGeometryNode.ChildNodes[0];
|
||||
bool isPositions = bool.Parse(vertexBufferNode1.Attributes["positions"].Value);
|
||||
bool isNormals = bool.Parse(vertexBufferNode1.Attributes["normals"].Value);
|
||||
for (int i = 0; i < vertexBufferNode1.ChildNodes.Count; i++)
|
||||
{
|
||||
XmlNode vertexNode = vertexBufferNode1.ChildNodes[i];
|
||||
if (isPositions)
|
||||
{
|
||||
XmlNode posNode = vertexNode["position"];
|
||||
vertices[i] = posNode.ReadVector3();
|
||||
}
|
||||
|
||||
if (isNormals)
|
||||
{
|
||||
XmlNode normalNode = vertexNode["normal"];
|
||||
normals[i] = normalNode.ReadVector3();
|
||||
}
|
||||
}
|
||||
|
||||
// uv
|
||||
XmlNode vertexBufferNode2 = sharedGeometryNode.ChildNodes[1];
|
||||
int coordsNum = int.Parse(vertexBufferNode2.Attributes["texture_coords"].Value);
|
||||
Vector2[][] uvs = new Vector2[coordsNum][];
|
||||
for (int i = 0; i < coordsNum; i++)
|
||||
uvs[i] = new Vector2[vertexCount];
|
||||
|
||||
for (int i = 0; i < vertexBufferNode2.ChildNodes.Count; i++)
|
||||
{
|
||||
XmlNode vertexNode = vertexBufferNode2.ChildNodes[i];
|
||||
for (int j = 0; j < vertexNode.ChildNodes.Count; j++)
|
||||
{
|
||||
XmlNode texcoordNode = vertexNode.ChildNodes[j];
|
||||
uvs[j][i] = texcoordNode.ReadUV2();
|
||||
}
|
||||
}
|
||||
|
||||
Mesh mesh = new Mesh();
|
||||
mesh.vertices = vertices;
|
||||
mesh.normals = normals;
|
||||
for (int i = 0; i < coordsNum; i++)
|
||||
mesh.SetUVs(i, uvs[i]);
|
||||
|
||||
XmlNode boneassignments = rootNode.SelectSingleNode("boneassignments");
|
||||
BoneWeight[] boneWeights = new BoneWeight[vertices.Length];
|
||||
|
||||
for (int i = 0; i < boneassignments.ChildNodes.Count; i++)
|
||||
{
|
||||
XmlElement item = boneassignments.ChildNodes[i] as XmlElement;
|
||||
int vIdx = int.Parse(item.GetAttribute("vertexindex"));
|
||||
int boneIdx = int.Parse(item.GetAttribute("boneindex"));
|
||||
float weight = float.Parse(item.GetAttribute("weight"));
|
||||
|
||||
BoneWeight boneWeight = boneWeights[vIdx];
|
||||
if (boneWeight.boneIndex0 == 0)
|
||||
{
|
||||
boneWeight.boneIndex0 = boneIdx;
|
||||
boneWeight.weight0 = weight;
|
||||
}
|
||||
else if (boneWeight.boneIndex1 == 0)
|
||||
{
|
||||
boneWeight.boneIndex1 = boneIdx;
|
||||
boneWeight.weight1 = weight;
|
||||
}
|
||||
else if (boneWeight.boneIndex2 == 0)
|
||||
{
|
||||
boneWeight.boneIndex2 = boneIdx;
|
||||
boneWeight.weight2 = weight;
|
||||
}
|
||||
else if (boneWeight.boneIndex3 == 0)
|
||||
{
|
||||
boneWeight.boneIndex3 = boneIdx;
|
||||
boneWeight.weight3 = weight;
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError($"超过4个顶点: vertexindex={vIdx}");
|
||||
}
|
||||
|
||||
boneWeights[vIdx] = boneWeight;
|
||||
}
|
||||
|
||||
// 总共数量
|
||||
int totalCount = 0;
|
||||
int[] indexRange = new int[submeshesNode.ChildNodes.Count];
|
||||
for (int i = 0; i < submeshesNode.ChildNodes.Count; i++)
|
||||
{
|
||||
XmlNode node = submeshesNode.ChildNodes[i];
|
||||
XmlNode facesNode = node.FirstChild;
|
||||
int count = int.Parse(facesNode.Attributes["count"].Value);
|
||||
if (i == 0)
|
||||
{
|
||||
indexRange[i] = count;
|
||||
}
|
||||
else
|
||||
{
|
||||
indexRange[i] = indexRange[i - 1] + count;
|
||||
}
|
||||
|
||||
totalCount += count;
|
||||
}
|
||||
|
||||
int[] triangles = new int[totalCount * 3];
|
||||
int triangleIdx = 0;
|
||||
for (int i = 0; i < submeshesNode.ChildNodes.Count; i++)
|
||||
{
|
||||
XmlNode node = submeshesNode.ChildNodes[i];
|
||||
XmlNode facesNode = node.FirstChild;
|
||||
int count = int.Parse(facesNode.Attributes["count"].Value);
|
||||
|
||||
for (int j = 0; j < facesNode.ChildNodes.Count; j++, triangleIdx += 3)
|
||||
{
|
||||
XmlNode faceNode = facesNode.ChildNodes[j];
|
||||
int v1 = int.Parse(faceNode.Attributes["v1"].Value);
|
||||
int v2 = int.Parse(faceNode.Attributes["v2"].Value);
|
||||
int v3 = int.Parse(faceNode.Attributes["v3"].Value);
|
||||
triangles[triangleIdx] = v1;
|
||||
triangles[triangleIdx + 1] = v2;
|
||||
triangles[triangleIdx + 2] = v3;
|
||||
}
|
||||
}
|
||||
|
||||
mesh.SetIndexBufferParams(triangles.Length, IndexFormat.UInt32);
|
||||
mesh.SetIndexBufferData(triangles, 0, 0, triangles.Length);
|
||||
mesh.subMeshCount = indexRange.Length;
|
||||
mesh.boneWeights = boneWeights;
|
||||
|
||||
for (int i = 0; i < submeshesNode.ChildNodes.Count; i++)
|
||||
{
|
||||
XmlNode node = submeshesNode.ChildNodes[i];
|
||||
XmlNode facesNode = node.FirstChild;
|
||||
int count = int.Parse(facesNode.Attributes["count"].Value);
|
||||
mesh.SetSubMesh(i, new SubMeshDescriptor((indexRange[i] - count) * 3, count * 3));
|
||||
}
|
||||
|
||||
|
||||
OgreSkeletonData ogreSkeletonData = new OgreSkeletonData();
|
||||
// ogreSkeletonData.ReadXml(skeletonXml);
|
||||
|
||||
// 创建骨骼
|
||||
Transform skeleton = new GameObject("skeleton").transform;
|
||||
skeleton.SetParent(transform, false);
|
||||
|
||||
var dic = new Dictionary<string, Transform>();
|
||||
List<Transform> bones = new List<Transform>();
|
||||
for (int i = 0; i < ogreSkeletonData.Bones.Length; i++)
|
||||
{
|
||||
OgreSkeletonBone bone = ogreSkeletonData.Bones[i];
|
||||
GameObject go = new GameObject(bone.Name);
|
||||
go.transform.SetParent(skeleton, false);
|
||||
go.transform.position = bone.Pos;
|
||||
go.transform.rotation = bone.Rot;
|
||||
go.transform.localScale = bone.Scale;
|
||||
dic.Add(go.name, go.transform);
|
||||
bones.Add(go.transform);
|
||||
}
|
||||
|
||||
// 设置层级
|
||||
for (int i = 0; i < ogreSkeletonData.BoneHierarchies.Length; i++)
|
||||
{
|
||||
OgreBoneHierarchy h = ogreSkeletonData.BoneHierarchies[i];
|
||||
dic[h.Bone].SetParent(dic[h.Parent], false);
|
||||
}
|
||||
|
||||
Matrix4x4[] bindposes = new Matrix4x4[bones.Count];
|
||||
for (int i = 0; i < bones.Count; i++)
|
||||
{
|
||||
var bone = bones[i];
|
||||
bindposes[i] = bone.worldToLocalMatrix * skeleton.localToWorldMatrix;
|
||||
}
|
||||
|
||||
mesh.bindposes = bindposes;
|
||||
mesh.RecalculateBounds();
|
||||
|
||||
SkinnedMeshRenderer skinnedMeshRenderer = gameObject.AddComponent<SkinnedMeshRenderer>();
|
||||
skinnedMeshRenderer.bones = bones.ToArray();
|
||||
skinnedMeshRenderer.sharedMesh = mesh;
|
||||
// skinnedMeshRenderer.sharedMaterial =
|
||||
skinnedMeshRenderer.bounds = mesh.bounds;
|
||||
skinnedMeshRenderer.rootBone = dic[ogreSkeletonData.BoneHierarchies[0].Parent];
|
||||
|
||||
Animation animation = gameObject.GetComponent<Animation>();
|
||||
foreach (var clip in ogreSkeletonData.Clips)
|
||||
{
|
||||
clip.legacy = true;
|
||||
// clip.wrapMode = WrapMode.Loop;
|
||||
animation.AddClip(clip, clip.name);
|
||||
}
|
||||
|
||||
// animation.Play("Stand");
|
||||
}
|
||||
|
||||
private bool isPlayLoop = false;
|
||||
|
||||
private void OnGUI()
|
||||
{
|
||||
isPlayLoop = GUILayout.Toggle(isPlayLoop, "循环播放");
|
||||
Animation animation = gameObject.GetComponent<Animation>();
|
||||
foreach (AnimationState state in animation)
|
||||
{
|
||||
if (GUILayout.Button(state.name))
|
||||
{
|
||||
state.clip.wrapMode = isPlayLoop ? WrapMode.Loop : WrapMode.Default;
|
||||
animation.Play(state.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
11
Assets/Scripts/JiuJie/JiuJIeTest.cs.meta
generated
Normal file
11
Assets/Scripts/JiuJie/JiuJIeTest.cs.meta
generated
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8b3c1bd47b6760f4e991d38836ab7ca2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
374
Assets/Scripts/JiuJie/OgreXmlData.cs
Normal file
374
Assets/Scripts/JiuJie/OgreXmlData.cs
Normal file
@ -0,0 +1,374 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Xml;
|
||||
using UnityEngine;
|
||||
|
||||
namespace DefaultNamespace
|
||||
{
|
||||
public struct OgreBoneWeight
|
||||
{
|
||||
public int VertexIndex;
|
||||
public int BoneIndex;
|
||||
public float Weight;
|
||||
}
|
||||
|
||||
public struct OgreSubMeshName
|
||||
{
|
||||
public string Name;
|
||||
public int Index;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 定义submesh的顶点索引
|
||||
/// </summary>
|
||||
public struct OgreSubMesh
|
||||
{
|
||||
public string Material; // 材质名字
|
||||
public int FaceCount; // 面数量
|
||||
public int[] Triangles;
|
||||
}
|
||||
|
||||
public class OgreMeshData
|
||||
{
|
||||
public Vector3[] Vertices;
|
||||
public Vector3[] Normals;
|
||||
public Vector2[][] UVs;
|
||||
public OgreBoneWeight[] BoneWeights;
|
||||
public string SkeletonLink;
|
||||
|
||||
public OgreSubMesh[] SubMesh;
|
||||
public OgreSubMeshName[] SubMeshName;
|
||||
|
||||
public void ReadXml(string filename)
|
||||
{
|
||||
XmlDocument meshDoc = new XmlDocument();
|
||||
meshDoc.Load(filename);
|
||||
|
||||
XmlElement rootNode = meshDoc.DocumentElement;
|
||||
XmlNode sharedGeometryNode = rootNode.GetElementsByTagName("sharedgeometry")[0];
|
||||
XmlNode submeshesNode = rootNode.GetElementsByTagName("submeshes")[0];
|
||||
XmlNode submeshnamesNode = rootNode.GetElementsByTagName("submeshnames")[0];
|
||||
|
||||
int vertexCount = int.Parse(sharedGeometryNode.Attributes["vertexcount"].Value);
|
||||
|
||||
Vertices = new Vector3[vertexCount];
|
||||
Normals = new Vector3[vertexCount];
|
||||
|
||||
// vertex
|
||||
XmlNode vertexBufferNode1 = sharedGeometryNode.ChildNodes[0];
|
||||
bool isPositions = bool.Parse(vertexBufferNode1.Attributes["positions"].Value);
|
||||
bool isNormals = bool.Parse(vertexBufferNode1.Attributes["normals"].Value);
|
||||
for (int i = 0; i < vertexBufferNode1.ChildNodes.Count; i++)
|
||||
{
|
||||
XmlNode vertexNode = vertexBufferNode1.ChildNodes[i];
|
||||
if (isPositions)
|
||||
{
|
||||
XmlNode posNode = vertexNode["position"];
|
||||
Vertices[i] = posNode.ReadVector3();
|
||||
}
|
||||
|
||||
if (isNormals)
|
||||
{
|
||||
XmlNode normalNode = vertexNode["normal"];
|
||||
Normals[i] = normalNode.ReadVector3();
|
||||
}
|
||||
}
|
||||
|
||||
// uv
|
||||
XmlNode vertexBufferNode2 = sharedGeometryNode.ChildNodes[1];
|
||||
int coordsNum = int.Parse(vertexBufferNode2.Attributes["texture_coords"].Value);
|
||||
UVs = new Vector2[coordsNum][];
|
||||
for (int i = 0; i < coordsNum; i++)
|
||||
UVs[i] = new Vector2[vertexCount];
|
||||
|
||||
for (int i = 0; i < vertexBufferNode2.ChildNodes.Count; i++)
|
||||
{
|
||||
XmlNode vertexNode = vertexBufferNode2.ChildNodes[i];
|
||||
for (int j = 0; j < vertexNode.ChildNodes.Count; j++)
|
||||
{
|
||||
XmlNode texcoordNode = vertexNode.ChildNodes[j];
|
||||
UVs[j][i] = texcoordNode.ReadUV2();
|
||||
}
|
||||
}
|
||||
|
||||
XmlNode skeletonlinkNode = rootNode.SelectSingleNode("skeletonlink");
|
||||
if (skeletonlinkNode != null)
|
||||
{
|
||||
this.SkeletonLink = ((XmlElement)skeletonlinkNode).GetAttribute("name");
|
||||
}
|
||||
|
||||
XmlNode boneassignments = rootNode.SelectSingleNode("boneassignments");
|
||||
if (boneassignments is { HasChildNodes: true })
|
||||
{
|
||||
BoneWeights = new OgreBoneWeight[boneassignments.ChildNodes.Count];
|
||||
for (int i = 0; i < boneassignments.ChildNodes.Count; i++)
|
||||
{
|
||||
XmlElement item = boneassignments.ChildNodes[i] as XmlElement;
|
||||
int vIdx = int.Parse(item.GetAttribute("vertexindex"));
|
||||
int boneIdx = int.Parse(item.GetAttribute("boneindex"));
|
||||
float weight = float.Parse(item.GetAttribute("weight"));
|
||||
OgreBoneWeight ogreBoneWeight = new OgreBoneWeight
|
||||
{
|
||||
VertexIndex = vIdx,
|
||||
BoneIndex = boneIdx,
|
||||
Weight = weight
|
||||
};
|
||||
this.BoneWeights[i] = ogreBoneWeight;
|
||||
}
|
||||
}
|
||||
|
||||
// subMesh
|
||||
int subMeshCount = submeshesNode.ChildNodes.Count;
|
||||
SubMesh = new OgreSubMesh[subMeshCount];
|
||||
for (int i = 0; i < subMeshCount; i++)
|
||||
{
|
||||
XmlNode node = submeshesNode.ChildNodes[i];
|
||||
XmlNode facesNode = node.FirstChild;
|
||||
string material = node.Attributes["material"].Value;
|
||||
int count = int.Parse(facesNode.Attributes["count"].Value);
|
||||
SubMesh[i] = new OgreSubMesh
|
||||
{
|
||||
Material = material,
|
||||
FaceCount = count,
|
||||
Triangles = new int[count * 3]
|
||||
};
|
||||
|
||||
int triangleIdx = 0;
|
||||
for (int j = 0; j < facesNode.ChildNodes.Count; j++, triangleIdx += 3)
|
||||
{
|
||||
XmlNode faceNode = facesNode.ChildNodes[j];
|
||||
int v1 = int.Parse(faceNode.Attributes["v1"].Value);
|
||||
int v2 = int.Parse(faceNode.Attributes["v2"].Value);
|
||||
int v3 = int.Parse(faceNode.Attributes["v3"].Value);
|
||||
SubMesh[i].Triangles[triangleIdx] = v1;
|
||||
SubMesh[i].Triangles[triangleIdx + 1] = v2;
|
||||
SubMesh[i].Triangles[triangleIdx + 2] = v3;
|
||||
}
|
||||
}
|
||||
|
||||
// subMeshName
|
||||
ReadSubMeshNames(submeshnamesNode);
|
||||
}
|
||||
|
||||
private void ReadSubMeshNames(XmlNode subMeshNameNode)
|
||||
{
|
||||
int count = subMeshNameNode.ChildNodes.Count;
|
||||
this.SubMeshName = new OgreSubMeshName[count];
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
XmlElement item = (XmlElement)subMeshNameNode.ChildNodes[i];
|
||||
string name = item.GetAttribute("name");
|
||||
int index = int.Parse(item.GetAttribute("index"));
|
||||
this.SubMeshName[i] = new OgreSubMeshName
|
||||
{
|
||||
Name = name,
|
||||
Index = index
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class OgreSkeletonData
|
||||
{
|
||||
public string BlendMode { get; private set; }
|
||||
public OgreSkeletonBone[] Bones { get; private set; }
|
||||
public OgreBoneHierarchy[] BoneHierarchies { get; private set; }
|
||||
public AnimationClip[] Clips { get; private set; }
|
||||
|
||||
public void ReadXml(string filename)
|
||||
{
|
||||
XmlDocument xml = new XmlDocument();
|
||||
xml.Load(filename);
|
||||
|
||||
var root = xml.DocumentElement;
|
||||
this.BlendMode = root.GetAttribute("blendmode");
|
||||
|
||||
XmlNode bonesNode = root.ChildNodes[0];
|
||||
this.Bones = new OgreSkeletonBone[bonesNode.ChildNodes.Count];
|
||||
for (int i = 0; i < bonesNode.ChildNodes.Count; i++)
|
||||
{
|
||||
OgreSkeletonBone bone = new OgreSkeletonBone();
|
||||
|
||||
XmlElement boneNode = bonesNode.ChildNodes[i] as XmlElement;
|
||||
bone.Id = int.Parse(boneNode.GetAttribute("id"));
|
||||
bone.Name = boneNode.GetAttribute("name");
|
||||
bone.Pos = Vector3.zero;
|
||||
bone.Rot = Quaternion.identity;
|
||||
bone.Scale = Vector3.one;
|
||||
|
||||
if (boneNode.SelectSingleNode("position") is XmlElement posNode)
|
||||
{
|
||||
bone.Pos = posNode.ReadVector3();
|
||||
}
|
||||
|
||||
if (boneNode.SelectSingleNode("rotation") is XmlElement rotNode)
|
||||
{
|
||||
// 弧度
|
||||
float angle = float.Parse(rotNode.GetAttribute("angle"));
|
||||
float deg = Mathf.Rad2Deg * angle;
|
||||
XmlElement axisNode = (XmlElement)rotNode.FirstChild;
|
||||
Vector3 axis = axisNode.ReadVector3();
|
||||
bone.Rot = Quaternion.AngleAxis(deg, axis).normalized;
|
||||
}
|
||||
|
||||
if (boneNode.SelectSingleNode("scale") is XmlElement scaleNode)
|
||||
{
|
||||
bone.Scale = scaleNode.ReadVector3();
|
||||
}
|
||||
|
||||
this.Bones[i] = bone;
|
||||
}
|
||||
|
||||
XmlNode bonehierarchyNode = root.ChildNodes[1];
|
||||
this.BoneHierarchies = new OgreBoneHierarchy[bonehierarchyNode.ChildNodes.Count];
|
||||
for (int i = 0; i < bonehierarchyNode.ChildNodes.Count; i++)
|
||||
{
|
||||
XmlElement item = bonehierarchyNode.ChildNodes[i] as XmlElement;
|
||||
OgreBoneHierarchy h = new OgreBoneHierarchy();
|
||||
h.Bone = item.GetAttribute("bone");
|
||||
h.Parent = item.GetAttribute("parent");
|
||||
BoneHierarchies[i] = h;
|
||||
}
|
||||
|
||||
XmlNode animationsNode = root.SelectSingleNode("animations");
|
||||
if (animationsNode != null)
|
||||
{
|
||||
int animsNum = animationsNode.ChildNodes.Count;
|
||||
Clips = new AnimationClip[animsNum];
|
||||
for (int i = 0; i < animsNum; i++)
|
||||
{
|
||||
XmlElement anim = animationsNode.ChildNodes[i] as XmlElement;
|
||||
string name = anim.GetAttribute("name");
|
||||
float length = float.Parse(anim.GetAttribute("length"));
|
||||
|
||||
AnimationClip animationClip = new AnimationClip();
|
||||
animationClip.name = name;
|
||||
Clips[i] = animationClip;
|
||||
|
||||
XmlNode tracksNode = anim.FirstChild;
|
||||
for (int j = 0; j < tracksNode.ChildNodes.Count; j++)
|
||||
{
|
||||
XmlElement trackNode = tracksNode.ChildNodes[j] as XmlElement;
|
||||
string boneName = trackNode.GetAttribute("bone");
|
||||
|
||||
OgreSkeletonBone boneData = FindBone(boneName);
|
||||
|
||||
AnimationCurve posX = new AnimationCurve();
|
||||
AnimationCurve posY = new AnimationCurve();
|
||||
AnimationCurve posZ = new AnimationCurve();
|
||||
|
||||
// 欧拉角
|
||||
AnimationCurve rotX = new AnimationCurve();
|
||||
AnimationCurve rotY = new AnimationCurve();
|
||||
AnimationCurve rotZ = new AnimationCurve();
|
||||
AnimationCurve rotW = new AnimationCurve();
|
||||
|
||||
XmlNode keyframesNode = trackNode.FirstChild;
|
||||
for (int k = 0; k < keyframesNode.ChildNodes.Count; k++)
|
||||
{
|
||||
XmlElement keyframeNode = keyframesNode.ChildNodes[k] as XmlElement;
|
||||
float time = float.Parse(keyframeNode.GetAttribute("time"));
|
||||
|
||||
Vector3 vector3 = Vector3.zero;
|
||||
Quaternion q = Quaternion.identity;
|
||||
|
||||
foreach (XmlNode itemNodeTmp in keyframeNode.ChildNodes)
|
||||
{
|
||||
XmlElement itemNode = itemNodeTmp as XmlElement;
|
||||
switch (itemNode.Name)
|
||||
{
|
||||
case "translate":
|
||||
vector3 = itemNode.ReadVector3();
|
||||
|
||||
// 位置
|
||||
vector3 += boneData.Pos;
|
||||
posX.AddKey(time, vector3.x);
|
||||
posY.AddKey(time, vector3.y);
|
||||
posZ.AddKey(time, vector3.z);
|
||||
|
||||
break;
|
||||
case "rotate":
|
||||
// 保存的是弧度
|
||||
float angle = float.Parse(itemNode.GetAttribute("angle"));
|
||||
XmlElement axisNode = (XmlElement)itemNode.FirstChild;
|
||||
Vector3 axis = axisNode.ReadVector3();
|
||||
|
||||
float deg = Mathf.Rad2Deg * angle;
|
||||
q = Quaternion.AngleAxis(deg, axis).normalized;
|
||||
|
||||
// 旋转
|
||||
q *= boneData.Rot;
|
||||
rotX.AddKey(time, q.x);
|
||||
rotY.AddKey(time, q.y);
|
||||
rotZ.AddKey(time, q.z);
|
||||
rotW.AddKey(time, q.w);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<string> relativePathList = new List<string>();
|
||||
relativePathList.Add(boneName);
|
||||
FindParents(boneName, relativePathList);
|
||||
relativePathList.Add("skeleton");
|
||||
relativePathList.Reverse();
|
||||
string relativePath = Path.Combine(relativePathList.ToArray()).Replace("\\", "/");
|
||||
|
||||
animationClip.SetCurve(relativePath, typeof(Transform), "m_LocalPosition.x", posX);
|
||||
animationClip.SetCurve(relativePath, typeof(Transform), "m_LocalPosition.y", posY);
|
||||
animationClip.SetCurve(relativePath, typeof(Transform), "m_LocalPosition.z", posZ);
|
||||
|
||||
animationClip.SetCurve(relativePath, typeof(Transform), "m_LocalRotation.x", rotX);
|
||||
animationClip.SetCurve(relativePath, typeof(Transform), "m_LocalRotation.y", rotY);
|
||||
animationClip.SetCurve(relativePath, typeof(Transform), "m_LocalRotation.z", rotZ);
|
||||
animationClip.SetCurve(relativePath, typeof(Transform), "m_LocalRotation.w", rotW);
|
||||
|
||||
// animationClip.SetCurve(relativePath, typeof(Transform), "m_LocalEulerAngles.x", rotX);
|
||||
// animationClip.SetCurve(relativePath, typeof(Transform), "m_LocalEulerAngles.y", rotY);
|
||||
// animationClip.SetCurve(relativePath, typeof(Transform), "m_LocalEulerAngles.z", rotZ);
|
||||
|
||||
// animationClip.SetCurve(relativePath, typeof(Transform), "localEulerAnglesBaked.x", rotX);
|
||||
// animationClip.SetCurve(relativePath, typeof(Transform), "localEulerAnglesBaked.y", rotY);
|
||||
// animationClip.SetCurve(relativePath, typeof(Transform), "localEulerAnglesBaked.z", rotZ);
|
||||
}
|
||||
|
||||
animationClip.frameRate = 24f;
|
||||
Debug.Log($"读取动画: {animationClip.name} - {animationClip.length}");
|
||||
}
|
||||
}
|
||||
|
||||
// 找到骨骼的层级
|
||||
void FindParents(string boneName, List<string> result)
|
||||
{
|
||||
var cur = this.BoneHierarchies.FirstOrDefault(f => f.Bone == boneName);
|
||||
if (cur is null)
|
||||
return;
|
||||
|
||||
// 有父
|
||||
result.Add(cur.Parent);
|
||||
FindParents(cur.Parent, result);
|
||||
}
|
||||
|
||||
OgreSkeletonBone FindBone(string name)
|
||||
{
|
||||
return this.Bones.First(f => f.Name == name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public struct OgreSkeletonBone
|
||||
{
|
||||
public int Id;
|
||||
public string Name;
|
||||
public Vector3 Pos;
|
||||
public Quaternion Rot;
|
||||
public Vector3 Scale;
|
||||
}
|
||||
|
||||
public class OgreBoneHierarchy
|
||||
{
|
||||
public string Bone;
|
||||
public string Parent;
|
||||
}
|
||||
}
|
11
Assets/Scripts/JiuJie/OgreXmlData.cs.meta
generated
Normal file
11
Assets/Scripts/JiuJie/OgreXmlData.cs.meta
generated
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0577c6a9eb975ba4ebdd0369db0cb77c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
30
Assets/Scripts/JiuJie/XmlReaderEx.cs
Normal file
30
Assets/Scripts/JiuJie/XmlReaderEx.cs
Normal file
@ -0,0 +1,30 @@
|
||||
using System.Xml;
|
||||
using UnityEngine;
|
||||
|
||||
namespace DefaultNamespace
|
||||
{
|
||||
public static class XmlReaderEx
|
||||
{
|
||||
public static Vector3 ReadVector3(this XmlNode vNode)
|
||||
{
|
||||
float x = float.Parse(vNode.Attributes["x"].Value);
|
||||
float y = float.Parse(vNode.Attributes["y"].Value);
|
||||
float z = float.Parse(vNode.Attributes["z"].Value);
|
||||
return new Vector3(x, y, z);
|
||||
}
|
||||
|
||||
public static Vector3 ReadVector2(this XmlNode vNode)
|
||||
{
|
||||
float x = float.Parse(vNode.Attributes["x"].Value);
|
||||
float y = float.Parse(vNode.Attributes["y"].Value);
|
||||
return new Vector2(x, y);
|
||||
}
|
||||
|
||||
public static Vector3 ReadUV2(this XmlNode vNode)
|
||||
{
|
||||
float x = float.Parse(vNode.Attributes["u"].Value);
|
||||
float y = float.Parse(vNode.Attributes["v"].Value);
|
||||
return new Vector2(x, y);
|
||||
}
|
||||
}
|
||||
}
|
11
Assets/Scripts/JiuJie/XmlReaderEx.cs.meta
generated
Normal file
11
Assets/Scripts/JiuJie/XmlReaderEx.cs.meta
generated
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5a430aec26e01a14186aaf4205c23419
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Reference in New Issue
Block a user