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(); 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(); 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[] weights = new List[len]; // 每个顶点的骨骼数量 NativeArray bonesPerVertex = new NativeArray(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 boneWeights = new NativeArray(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 triangles = new NativeArray(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 bonesPerVertex = new NativeArray(verticesCount, Allocator.Temp); NativeArray boneWeights = new NativeArray(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(); smr.sharedMesh = mesh; smr.sharedMaterial = defaultMaterial; smr.bones = bones; smr.rootBone = dic[skeletonData.BoneHierarchies[0].Parent]; #endif Animation ani = gameObject.GetComponent(); 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(); List bones = new List(); 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.bones = bones.ToArray(); skinnedMeshRenderer.sharedMesh = mesh; // skinnedMeshRenderer.sharedMaterial = skinnedMeshRenderer.bounds = mesh.bounds; skinnedMeshRenderer.rootBone = dic[ogreSkeletonData.BoneHierarchies[0].Parent]; Animation animation = gameObject.GetComponent(); 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(); foreach (AnimationState state in animation) { if (GUILayout.Button(state.name)) { state.clip.wrapMode = isPlayLoop ? WrapMode.Loop : WrapMode.Default; animation.Play(state.name); } } } } }