KopMap/Assets/Scripts/JiuJie/JiuJIeTest.cs
2025-04-03 02:30:16 +08:00

423 lines
17 KiB
C#

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);
}
}
}
}
}