423 lines
17 KiB
C#
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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} |