This commit is contained in:
2025-04-03 02:30:16 +08:00
parent 142adb61c6
commit bee7af1732
14907 changed files with 1009130 additions and 13 deletions

3
Assets/Scripts/Editor.meta generated Normal file
View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 585609d41aa64f5286a356a19c8a1869
timeCreated: 1727962761

View File

@ -0,0 +1,59 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using UnityEditor;
using UnityEngine;
public static class Tool
{
[MenuItem("KopTools/MakeTexture")]
public static void MakeTextureArray()
{
MakeTexture();
}
private static void MakeTexture()
{
TextAsset textAsset = Resources.Load<TextAsset>("TerrainInfo");
string[] terrainInfos = textAsset.text.Split("\n");
Texture2D texture2D = new Texture2D(2048, 2048);
for (int i = 0; i < 2048; i++)
{
for (int j = 0; j < 2048; j++)
{
texture2D.SetPixel(i, j, Color.black);
}
}
for (int i = 0; i < terrainInfos.Length; i++)
{
string infoItem = terrainInfos[i];
if (string.IsNullOrEmpty(infoItem))
continue;
string[] infos = infoItem.Split("\t", StringSplitOptions.RemoveEmptyEntries);
if (infos is { Length: < 2 })
continue;
string texName = Path.GetFileNameWithoutExtension(infos[1]);
string texFilePath = $"Textures/{texName}";
int startX = i * 256 % 2048;
int startY = (63 - i) / 8 * 256;
Texture2D texture = Resources.Load<Texture2D>(texFilePath);
if (texture)
{
var pixels = texture.GetPixels();
texture2D.SetPixels(startX, startY, texture.width, texture.height, pixels);
}
Debug.Log($"i:{i} | startX:{startX} | startY:{startY} | {texFilePath}");
}
// save
File.WriteAllBytes($"Assets/TerrainTex.png", texture2D.EncodeToPNG());
}
}

11
Assets/Scripts/Editor/Tool.cs.meta generated Normal file
View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b37341f8e6fccdb49b7c3e9644055e0e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

8
Assets/Scripts/JiuJie.meta generated Normal file
View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 1f51d9a8b8c7a134498f4c4abcb37688
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View 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
View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8b3c1bd47b6760f4e991d38836ab7ca2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

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

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0577c6a9eb975ba4ebdd0369db0cb77c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

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

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5a430aec26e01a14186aaf4205c23419
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,65 @@
using System.Collections;
using System.IO;
using MindPowerSdk;
using UnityEditor;
using UnityEngine;
namespace Assets.Sandbox.Scripts
{
public class MonoKopSceneObjTest : MonoBehaviour
{
public string obj_file = @"D:\项目\海盗王\138原版一键端\海盗王Online\map\hell5.obj";
public MonoKopTest monoKopTest;
void Start()
{
CSceneObjSet sceneObjSet = new CSceneObjSet();
sceneObjSet.LoadBin("Assets/Resources/sceneobjinfo.bin");
SceneObjFile sceneObjFile = new SceneObjFile();
sceneObjFile.Load(obj_file);
for (int y = 0; y < sceneObjFile.FileHeader.SectionCntY; y++)
{
for (int x = 0; x < sceneObjFile.FileHeader.SectionCntX; x++)
{
var list = sceneObjFile.objInfos[x, y];
if (list is null) continue;
foreach (var sceneObjInfo in list)
{
if (sceneObjInfo.GetTypeId() == 1)
continue;
int id = sceneObjInfo.GetID();
CSceneObjInfo modeInfo = sceneObjSet.Get(id);
Vector3 pos = new Vector3(sceneObjInfo.X / 100f, sceneObjInfo.HeightOff / 100f, sceneObjInfo.Y / 100f * -1f);
float mapHeight = monoKopTest.map.GetHeight(pos.x, (sceneObjInfo.Y / 100f));
pos.y += mapHeight;
//Quaternion rot = Quaternion.AngleAxis(sceneObjInfo.YawAngle, Vector3.up);
string modePath = "Assets/Resources/Model/Scene/" + Path.GetFileNameWithoutExtension(modeInfo.szDataName) + ".lmo.obj";
Object mode = AssetDatabase.LoadAssetAtPath<Object>(modePath);
if (mode)
{
GameObject goModel = (GameObject)GameObject.Instantiate(mode);
goModel.transform.position = pos;
goModel.transform.localScale = new Vector3(1, 1, -1);
Vector3 e = goModel.transform.eulerAngles;
goModel.transform.rotation = Quaternion.Euler(e.x, sceneObjInfo.YawAngle, e.z);
goModel.name = $"[{id}]{mode.name}";
// Debug.Log(goModel);
}
else
{
Debug.LogError($"mode not found: {modePath}");
}
}
}
}
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: bdfe66723728e50479ef3c6bf778c779
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,77 @@
using System.IO;
using UnityEngine;
namespace MindPowerSdk
{
public class MonoKopTest : MonoBehaviour
{
public string mapPath = "";
public string mapName = "";
public short chunkSize = 64;
public MPMap map = null;
public Material terrainMaterial;
public Material terrainMaterial2;
void Start()
{
using FileStream fs = File.OpenRead(Path.Combine(mapPath, mapName));
BinaryReader reader = new BinaryReader(fs);
map = new MPMap();
map.Load(reader);
Debug.Log($"map size:({map.Width},{map.Height}) | section size:({map.SectionWidth},{map.SectionHeight})");
// GenTerrainMesh();
// TerrainGenerator.GenTerrain(map, chunkSize, terrainMaterial2, transform);
}
public void GenTerrainMesh()
{
// 自定义分块生成
int xCnt = Mathf.CeilToInt((float)map.Width / chunkSize);
int yCnt = Mathf.CeilToInt((float)map.Height / chunkSize);
for (short i = 0; i < yCnt; i++)
{
for (short j = 0; j < xCnt; j++)
{
short x = (short)(j * chunkSize);
short y = (short)(i * chunkSize);
Mesh mesh = map.GenMesh(x, y, chunkSize);
(Texture2D texNo, Texture2D maskNo) = map.GenTxtNoTexture(x, y, chunkSize);
GameObject go = new GameObject("m_" + i);
// go.isStatic = true;
go.transform.parent = transform;
// Vector3 pos = Vector3.forward * map.Height;
// go.transform.position = pos;
// 设置材质
MeshRenderer meshRenderer = go.AddComponent<MeshRenderer>();
var mat = meshRenderer.material = new Material(terrainMaterial);
mat.SetTexture("_TexNo", texNo);
mat.SetTexture("_MaskNo", maskNo);
MeshFilter meshFilter = go.AddComponent<MeshFilter>();
meshFilter.mesh = mesh;
#if UNITY_EDITOR
//AssetDatabase.CreateAsset(mesh, "Assets/Sandbox/map.mesh");
//(Texture2D t1, Texture2D t2) = map.GenTxtNoTexture(x, y, chunkSize);
//byte[] png = t1.EncodeToPNG();
//File.WriteAllBytes($"Assets/Sandbox/map_tex_no.png", png);
//png = t2.EncodeToPNG();
//File.WriteAllBytes($"Assets/Sandbox/map_alph_no.png", png);
#endif
}
}
}
}
}

11
Assets/Scripts/MonoKopTest.cs.meta generated Normal file
View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d1eaa80f641d7ec458654343727a7fea
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: