private void DeoptimizeTransformHierarchy() { if (avatar == null) { throw new Exception("Transform hierarchy has been optimized, but can't find Avatar to deoptimize."); } // 1. Figure out the skeletonPaths from the unstripped avatar var skeletonPaths = new List <string>(); foreach (var id in avatar.m_Avatar.m_AvatarSkeleton.m_ID) { var path = avatar.FindBonePath(id); skeletonPaths.Add(path); } // 2. Restore the original transform hierarchy // Prerequisite: skeletonPaths follow pre-order traversal for (var i = 1; i < skeletonPaths.Count; i++) // start from 1, skip the root transform because it will always be there. { var path = skeletonPaths[i]; var strs = path.Split('/'); string transformName; ImportedFrame parentFrame; if (strs.Length == 1) { transformName = path; parentFrame = RootFrame; } else { transformName = strs.Last(); var parentFrameName = strs[strs.Length - 2]; parentFrame = RootFrame.FindChild(parentFrameName); //var parentFramePath = path.Substring(0, path.LastIndexOf('/')); //parentFrame = RootFrame.FindFrameByPath(parentFramePath); } var skeletonPose = avatar.m_Avatar.m_DefaultPose; var xform = skeletonPose.m_X[i]; var frame = RootFrame.FindChild(transformName); if (frame != null) { SetFrame(frame, xform.t, xform.q, xform.s); parentFrame.AddChild(frame); } else { frame = CreateFrame(transformName, xform.t, xform.q, xform.s); parentFrame.AddChild(frame); } } }
void SetupBoneMatrices(CustomMeshContainer meshContainer) { if (meshContainer.SkinInfo == null) { return; } meshContainer.BoneMatricesLookup = new CustomFrame[meshContainer.SkinInfo.BoneCount]; for (int i = 0; i < meshContainer.SkinInfo.BoneCount; i++) { CustomFrame frame = (CustomFrame)RootFrame.FindChild(meshContainer.SkinInfo.GetBoneName(i)); meshContainer.BoneMatricesLookup[i] = frame; } }
private void ConvertMeshRenderer(Renderer meshR) { var mesh = GetMesh(meshR); if (mesh == null) { return; } var iMesh = new ImportedMesh(); meshR.m_GameObject.TryGet(out var m_GameObject2); iMesh.Path = GetTransformPath(m_GameObject2.m_Transform); iMesh.SubmeshList = new List <ImportedSubmesh>(); var subHashSet = new HashSet <int>(); var combine = false; int firstSubMesh = 0; if (meshR.m_StaticBatchInfo?.subMeshCount > 0) { firstSubMesh = meshR.m_StaticBatchInfo.firstSubMesh; var finalSubMesh = meshR.m_StaticBatchInfo.firstSubMesh + meshR.m_StaticBatchInfo.subMeshCount; for (int i = meshR.m_StaticBatchInfo.firstSubMesh; i < finalSubMesh; i++) { subHashSet.Add(i); } combine = true; } else if (meshR.m_SubsetIndices?.Length > 0) { firstSubMesh = (int)meshR.m_SubsetIndices.Min(x => x); foreach (var index in meshR.m_SubsetIndices) { subHashSet.Add((int)index); } combine = true; } int firstFace = 0; for (int i = 0; i < mesh.m_SubMeshes.Length; i++) { int numFaces = (int)mesh.m_SubMeshes[i].indexCount / 3; if (subHashSet.Count > 0 && !subHashSet.Contains(i)) { firstFace += numFaces; continue; } var submesh = mesh.m_SubMeshes[i]; var iSubmesh = new ImportedSubmesh(); Material mat = null; if (i - firstSubMesh < meshR.m_Materials.Length) { if (meshR.m_Materials[i - firstSubMesh].TryGet(out var m_Material)) { mat = m_Material; } } ImportedMaterial iMat = ConvertMaterial(mat); iSubmesh.Material = iMat.Name; iSubmesh.VertexList = new List <ImportedVertex>((int)submesh.vertexCount); var vertexColours = mesh.m_Colors != null && (mesh.m_Colors.Length == mesh.m_VertexCount * 3 || mesh.m_Colors.Length == mesh.m_VertexCount * 4); for (var j = mesh.m_SubMeshes[i].firstVertex; j < mesh.m_SubMeshes[i].firstVertex + mesh.m_SubMeshes[i].vertexCount; j++) { var iVertex = vertexColours ? new ImportedVertexWithColour() : new ImportedVertex(); //Vertices int c = 3; if (mesh.m_Vertices.Length == mesh.m_VertexCount * 4) { c = 4; } iVertex.Position = new Vector3(-mesh.m_Vertices[j * c], mesh.m_Vertices[j * c + 1], mesh.m_Vertices[j * c + 2]); //Normals if (mesh.m_Normals?.Length > 0) { if (mesh.m_Normals.Length == mesh.m_VertexCount * 3) { c = 3; } else if (mesh.m_Normals.Length == mesh.m_VertexCount * 4) { c = 4; } iVertex.Normal = new Vector3(-mesh.m_Normals[j * c], mesh.m_Normals[j * c + 1], mesh.m_Normals[j * c + 2]); } //Colors if (vertexColours) { if (mesh.m_Colors.Length == mesh.m_VertexCount * 3) { ((ImportedVertexWithColour)iVertex).Colour = new Color(mesh.m_Colors[j * 3], mesh.m_Colors[j * 3 + 1], mesh.m_Colors[j * 3 + 2], 1.0f); } else { ((ImportedVertexWithColour)iVertex).Colour = new Color(mesh.m_Colors[j * 4], mesh.m_Colors[j * 4 + 1], mesh.m_Colors[j * 4 + 2], mesh.m_Colors[j * 4 + 3]); } } //UV if (mesh.m_UV0 != null && mesh.m_UV0.Length == mesh.m_VertexCount * 2) { iVertex.UV = new[] { mesh.m_UV0[j * 2], mesh.m_UV0[j * 2 + 1] }; } else if (mesh.m_UV1 != null && mesh.m_UV1.Length == mesh.m_VertexCount * 2) { iVertex.UV = new[] { mesh.m_UV1[j * 2], mesh.m_UV1[j * 2 + 1] }; } //Tangent if (mesh.m_Tangents != null && mesh.m_Tangents.Length == mesh.m_VertexCount * 4) { iVertex.Tangent = new Vector4(-mesh.m_Tangents[j * 4], mesh.m_Tangents[j * 4 + 1], mesh.m_Tangents[j * 4 + 2], -mesh.m_Tangents[j * 4 + 3]); } //BoneInfluence if (mesh.m_Skin?.Length > 0) { var inf = mesh.m_Skin[j]; iVertex.BoneIndices = new int[4]; iVertex.Weights = new float[4]; for (var k = 0; k < 4; k++) { iVertex.BoneIndices[k] = inf.boneIndex[k]; iVertex.Weights[k] = inf.weight[k]; } } iSubmesh.VertexList.Add(iVertex); } //Face iSubmesh.FaceList = new List <ImportedFace>(numFaces); var end = firstFace + numFaces; for (int f = firstFace; f < end; f++) { var face = new ImportedFace(); face.VertexIndices = new int[3]; face.VertexIndices[0] = (int)(mesh.m_Indices[f * 3 + 2] - submesh.firstVertex); face.VertexIndices[1] = (int)(mesh.m_Indices[f * 3 + 1] - submesh.firstVertex); face.VertexIndices[2] = (int)(mesh.m_Indices[f * 3] - submesh.firstVertex); iSubmesh.FaceList.Add(face); } firstFace = end; iMesh.SubmeshList.Add(iSubmesh); } if (meshR is SkinnedMeshRenderer sMesh) { //Bone if (sMesh.m_Bones.Length > 0) { var boneMax = Math.Min(sMesh.m_Bones.Length, mesh.m_BindPose.Length); iMesh.BoneList = new List <ImportedBone>(boneMax); for (int i = 0; i < boneMax; i++) { var bone = new ImportedBone(); if (sMesh.m_Bones[i].TryGet(out var m_Transform)) { bone.Path = GetTransformPath(m_Transform); } if (!string.IsNullOrEmpty(bone.Path)) { var convert = Matrix4x4.Scale(new Vector3(-1, 1, 1)); bone.Matrix = convert * mesh.m_BindPose[i] * convert; iMesh.BoneList.Add(bone); } } } if (iMesh.BoneList == null || iMesh.BoneList.Count == 0) { if (mesh.m_BindPose.Length > 0 && mesh.m_BoneNameHashes?.Length > 0) { var boneMax = Math.Min(mesh.m_BindPose.Length, mesh.m_BoneNameHashes.Length); iMesh.BoneList = new List <ImportedBone>(boneMax); for (int i = 0; i < boneMax; i++) { var bone = new ImportedBone(); var boneHash = mesh.m_BoneNameHashes[i]; var path = GetPathFromHash(boneHash); bone.Path = FixBonePath(path); if (!string.IsNullOrEmpty(bone.Path)) { var convert = Matrix4x4.Scale(new Vector3(-1, 1, 1)); bone.Matrix = convert * mesh.m_BindPose[i] * convert; iMesh.BoneList.Add(bone); } } } } //Morphs if (mesh.m_Shapes?.channels?.Length > 0) { var morph = new ImportedMorph(); MorphList.Add(morph); morph.Path = iMesh.Path; morph.Channels = new List <ImportedMorphChannel>(mesh.m_Shapes.channels.Length); for (int i = 0; i < mesh.m_Shapes.channels.Length; i++) { var channel = new ImportedMorphChannel(); morph.Channels.Add(channel); var shapeChannel = mesh.m_Shapes.channels[i]; channel.Name = shapeChannel.name; channel.KeyframeList = new List <ImportedMorphKeyframe>(shapeChannel.frameCount); var frameEnd = shapeChannel.frameIndex + shapeChannel.frameCount; for (int frameIdx = shapeChannel.frameIndex; frameIdx < frameEnd; frameIdx++) { var keyframe = new ImportedMorphKeyframe(); channel.KeyframeList.Add(keyframe); keyframe.Weight = mesh.m_Shapes.fullWeights[frameIdx]; var shape = mesh.m_Shapes.shapes[frameIdx]; keyframe.hasNormals = shape.hasNormals; keyframe.hasTangents = shape.hasTangents; keyframe.VertexList = new List <ImportedMorphVertex>((int)shape.vertexCount); var vertexEnd = shape.firstVertex + shape.vertexCount; for (uint j = shape.firstVertex; j < vertexEnd; j++) { var destVertex = new ImportedMorphVertex(); keyframe.VertexList.Add(destVertex); var morphVertex = mesh.m_Shapes.vertices[j]; destVertex.Index = morphVertex.index; var sourceVertex = GetSourceVertex(iMesh.SubmeshList, (int)morphVertex.index); destVertex.Vertex = new ImportedVertex(); var morphPos = morphVertex.vertex; destVertex.Vertex.Position = sourceVertex.Position + new Vector3(-morphPos.X, morphPos.Y, morphPos.Z); if (shape.hasNormals) { var morphNormal = morphVertex.normal; destVertex.Vertex.Normal = new Vector3(-morphNormal.X, morphNormal.Y, morphNormal.Z); } if (shape.hasTangents) { var morphTangent = morphVertex.tangent; destVertex.Vertex.Tangent = new Vector4(-morphTangent.X, morphTangent.Y, morphTangent.Z, 0); } } } } } } //TODO combine mesh if (combine) { meshR.m_GameObject.TryGet(out var m_GameObject); var frame = RootFrame.FindChild(m_GameObject.m_Name); if (frame != null) { frame.LocalPosition = RootFrame.LocalPosition; frame.LocalRotation = RootFrame.LocalRotation; while (frame.Parent != null) { frame = frame.Parent; frame.LocalPosition = RootFrame.LocalPosition; frame.LocalRotation = RootFrame.LocalRotation; } } } MeshList.Add(iMesh); }
private void ConvertMeshRenderer(Renderer meshR) { var mesh = GetMesh(meshR); if (mesh == null) { return; } var iMesh = new ImportedMesh(); meshR.m_GameObject.TryGet(out var m_GameObject2); iMesh.Path = GetTransformPath(m_GameObject2.m_Transform); iMesh.SubmeshList = new List <ImportedSubmesh>(); var subHashSet = new HashSet <int>(); var combine = false; int firstSubMesh = 0; if (meshR.m_StaticBatchInfo?.subMeshCount > 0) { firstSubMesh = meshR.m_StaticBatchInfo.firstSubMesh; var finalSubMesh = meshR.m_StaticBatchInfo.firstSubMesh + meshR.m_StaticBatchInfo.subMeshCount; for (int i = meshR.m_StaticBatchInfo.firstSubMesh; i < finalSubMesh; i++) { subHashSet.Add(i); } combine = true; } else if (meshR.m_SubsetIndices?.Length > 0) { firstSubMesh = (int)meshR.m_SubsetIndices.Min(x => x); foreach (var index in meshR.m_SubsetIndices) { subHashSet.Add((int)index); } combine = true; } iMesh.hasNormal = mesh.m_Normals?.Length > 0; iMesh.hasUV = new bool[8]; for (int uv = 0; uv < 8; uv++) { iMesh.hasUV[uv] = mesh.GetUV(uv)?.Length > 0; } iMesh.hasTangent = mesh.m_Tangents != null && mesh.m_Tangents.Length == mesh.m_VertexCount * 4; iMesh.hasColor = mesh.m_Colors?.Length > 0; int firstFace = 0; for (int i = 0; i < mesh.m_SubMeshes.Length; i++) { int numFaces = (int)mesh.m_SubMeshes[i].indexCount / 3; if (subHashSet.Count > 0 && !subHashSet.Contains(i)) { firstFace += numFaces; continue; } var submesh = mesh.m_SubMeshes[i]; var iSubmesh = new ImportedSubmesh(); Material mat = null; if (i - firstSubMesh < meshR.m_Materials.Length) { if (meshR.m_Materials[i - firstSubMesh].TryGet(out var m_Material)) { mat = m_Material; } } ImportedMaterial iMat = ConvertMaterial(mat); iSubmesh.Material = iMat.Name; iSubmesh.VertexList = new List <ImportedVertex>((int)submesh.vertexCount); for (var j = mesh.m_SubMeshes[i].firstVertex; j < mesh.m_SubMeshes[i].firstVertex + mesh.m_SubMeshes[i].vertexCount; j++) { var iVertex = new ImportedVertex(); //Vertices int c = 3; if (mesh.m_Vertices.Length == mesh.m_VertexCount * 4) { c = 4; } iVertex.Vertex = new Vector3(-mesh.m_Vertices[j * c], mesh.m_Vertices[j * c + 1], mesh.m_Vertices[j * c + 2]); //Normals if (iMesh.hasNormal) { if (mesh.m_Normals.Length == mesh.m_VertexCount * 3) { c = 3; } else if (mesh.m_Normals.Length == mesh.m_VertexCount * 4) { c = 4; } iVertex.Normal = new Vector3(-mesh.m_Normals[j * c], mesh.m_Normals[j * c + 1], mesh.m_Normals[j * c + 2]); } //UV iVertex.UV = new float[8][]; for (int uv = 0; uv < 8; uv++) { if (iMesh.hasUV[uv]) { var m_UV = mesh.GetUV(uv); if (m_UV.Length == mesh.m_VertexCount * 2) { c = 2; } else if (m_UV.Length == mesh.m_VertexCount * 3) { c = 3; } iVertex.UV[uv] = new[] { m_UV[j * c], m_UV[j * c + 1] }; } } //Tangent if (iMesh.hasTangent) { iVertex.Tangent = new Vector4(-mesh.m_Tangents[j * 4], mesh.m_Tangents[j * 4 + 1], mesh.m_Tangents[j * 4 + 2], mesh.m_Tangents[j * 4 + 3]); } //Colors if (iMesh.hasColor) { if (mesh.m_Colors.Length == mesh.m_VertexCount * 3) { iVertex.Color = new Color(mesh.m_Colors[j * 3], mesh.m_Colors[j * 3 + 1], mesh.m_Colors[j * 3 + 2], 1.0f); } else { iVertex.Color = new Color(mesh.m_Colors[j * 4], mesh.m_Colors[j * 4 + 1], mesh.m_Colors[j * 4 + 2], mesh.m_Colors[j * 4 + 3]); } } //BoneInfluence if (mesh.m_Skin?.Length > 0) { var inf = mesh.m_Skin[j]; iVertex.BoneIndices = new int[4]; iVertex.Weights = new float[4]; for (var k = 0; k < 4; k++) { iVertex.BoneIndices[k] = inf.boneIndex[k]; iVertex.Weights[k] = inf.weight[k]; } } iSubmesh.VertexList.Add(iVertex); } //Face iSubmesh.FaceList = new List <ImportedFace>(numFaces); var end = firstFace + numFaces; for (int f = firstFace; f < end; f++) { var face = new ImportedFace(); face.VertexIndices = new int[3]; face.VertexIndices[0] = (int)(mesh.m_Indices[f * 3 + 2] - submesh.firstVertex); face.VertexIndices[1] = (int)(mesh.m_Indices[f * 3 + 1] - submesh.firstVertex); face.VertexIndices[2] = (int)(mesh.m_Indices[f * 3] - submesh.firstVertex); iSubmesh.FaceList.Add(face); } firstFace = end; iMesh.SubmeshList.Add(iSubmesh); } if (meshR is SkinnedMeshRenderer sMesh) { //Bone /* * 0 - None * 1 - m_Bones * 2 - m_BoneNameHashes */ var boneType = 0; if (sMesh.m_Bones.Length > 0) { if (sMesh.m_Bones.Length == mesh.m_BindPose.Length) { var verifiedBoneCount = sMesh.m_Bones.Count(x => x.TryGet(out _)); if (verifiedBoneCount > 0) { boneType = 1; } if (verifiedBoneCount != sMesh.m_Bones.Length) { //尝试使用m_BoneNameHashes 4.3 and up if (mesh.m_BindPose.Length > 0 && (mesh.m_BindPose.Length == mesh.m_BoneNameHashes?.Length)) { //有效bone数量是否大于SkinnedMeshRenderer var verifiedBoneCount2 = mesh.m_BoneNameHashes.Count(x => FixBonePath(GetPathFromHash(x)) != null); if (verifiedBoneCount2 > verifiedBoneCount) { boneType = 2; } } } } else { //Logger.Error(""); } } else { //尝试使用m_BoneNameHashes 4.3 and up if (mesh.m_BindPose.Length > 0 && (mesh.m_BindPose.Length == mesh.m_BoneNameHashes?.Length)) { boneType = 2; } } if (boneType == 1) { var boneCount = sMesh.m_Bones.Length; iMesh.BoneList = new List <ImportedBone>(boneCount); for (int i = 0; i < boneCount; i++) { var bone = new ImportedBone(); if (sMesh.m_Bones[i].TryGet(out var m_Transform)) { bone.Path = GetTransformPath(m_Transform); } var convert = Matrix4x4.Scale(new Vector3(-1, 1, 1)); bone.Matrix = convert * mesh.m_BindPose[i] * convert; iMesh.BoneList.Add(bone); } } else if (boneType == 2) { var boneCount = mesh.m_BindPose.Length; iMesh.BoneList = new List <ImportedBone>(boneCount); for (int i = 0; i < boneCount; i++) { var bone = new ImportedBone(); var boneHash = mesh.m_BoneNameHashes[i]; var path = GetPathFromHash(boneHash); bone.Path = FixBonePath(path); var convert = Matrix4x4.Scale(new Vector3(-1, 1, 1)); bone.Matrix = convert * mesh.m_BindPose[i] * convert; iMesh.BoneList.Add(bone); } } //Morphs if (mesh.m_Shapes?.channels?.Length > 0) { var morph = new ImportedMorph(); MorphList.Add(morph); morph.Path = iMesh.Path; morph.Channels = new List <ImportedMorphChannel>(mesh.m_Shapes.channels.Length); for (int i = 0; i < mesh.m_Shapes.channels.Length; i++) { var channel = new ImportedMorphChannel(); morph.Channels.Add(channel); var shapeChannel = mesh.m_Shapes.channels[i]; var blendShapeName = "blendShape." + shapeChannel.name; var crc = new SevenZip.CRC(); var bytes = Encoding.UTF8.GetBytes(blendShapeName); crc.Update(bytes, 0, (uint)bytes.Length); morphChannelNames[crc.GetDigest()] = blendShapeName; channel.Name = shapeChannel.name; channel.KeyframeList = new List <ImportedMorphKeyframe>(shapeChannel.frameCount); var frameEnd = shapeChannel.frameIndex + shapeChannel.frameCount; for (int frameIdx = shapeChannel.frameIndex; frameIdx < frameEnd; frameIdx++) { var keyframe = new ImportedMorphKeyframe(); channel.KeyframeList.Add(keyframe); keyframe.Weight = mesh.m_Shapes.fullWeights[frameIdx]; var shape = mesh.m_Shapes.shapes[frameIdx]; keyframe.hasNormals = shape.hasNormals; keyframe.hasTangents = shape.hasTangents; keyframe.VertexList = new List <ImportedMorphVertex>((int)shape.vertexCount); var vertexEnd = shape.firstVertex + shape.vertexCount; for (uint j = shape.firstVertex; j < vertexEnd; j++) { var destVertex = new ImportedMorphVertex(); keyframe.VertexList.Add(destVertex); var morphVertex = mesh.m_Shapes.vertices[j]; destVertex.Index = morphVertex.index; var sourceVertex = GetSourceVertex(iMesh.SubmeshList, (int)morphVertex.index); destVertex.Vertex = new ImportedVertex(); var morphPos = morphVertex.vertex; destVertex.Vertex.Vertex = sourceVertex.Vertex + new Vector3(-morphPos.X, morphPos.Y, morphPos.Z); if (shape.hasNormals) { var morphNormal = morphVertex.normal; destVertex.Vertex.Normal = new Vector3(-morphNormal.X, morphNormal.Y, morphNormal.Z); } if (shape.hasTangents) { var morphTangent = morphVertex.tangent; destVertex.Vertex.Tangent = new Vector4(-morphTangent.X, morphTangent.Y, morphTangent.Z, 0); } } } } } } //TODO combine mesh if (combine) { meshR.m_GameObject.TryGet(out var m_GameObject); var frame = RootFrame.FindChild(m_GameObject.m_Name); if (frame != null) { frame.LocalPosition = RootFrame.LocalPosition; frame.LocalRotation = RootFrame.LocalRotation; while (frame.Parent != null) { frame = frame.Parent; frame.LocalPosition = RootFrame.LocalPosition; frame.LocalRotation = RootFrame.LocalRotation; } } } MeshList.Add(iMesh); }
private void ConvertMeshRenderer(Renderer meshR) { var mesh = GetMesh(meshR); if (mesh == null) { return; } var iMesh = new ImportedMesh(); meshR.m_GameObject.TryGet(out var m_GameObject2); iMesh.Path = GetTransformPath(m_GameObject2.m_Transform); iMesh.SubmeshList = new List <ImportedSubmesh>(); var subHashSet = new HashSet <int>(); var combine = false; int firstSubMesh = 0; if (meshR.m_StaticBatchInfo?.subMeshCount > 0) { firstSubMesh = meshR.m_StaticBatchInfo.firstSubMesh; var finalSubMesh = meshR.m_StaticBatchInfo.firstSubMesh + meshR.m_StaticBatchInfo.subMeshCount; for (int i = meshR.m_StaticBatchInfo.firstSubMesh; i < finalSubMesh; i++) { subHashSet.Add(i); } combine = true; } else if (meshR.m_SubsetIndices?.Length > 0) { firstSubMesh = (int)meshR.m_SubsetIndices.Min(x => x); foreach (var index in meshR.m_SubsetIndices) { subHashSet.Add((int)index); } combine = true; } int firstFace = 0; for (int i = 0; i < mesh.m_SubMeshes.Length; i++) { int numFaces = (int)mesh.m_SubMeshes[i].indexCount / 3; if (subHashSet.Count > 0 && !subHashSet.Contains(i)) { firstFace += numFaces; continue; } var submesh = mesh.m_SubMeshes[i]; var iSubmesh = new ImportedSubmesh(); Material mat = null; if (i - firstSubMesh < meshR.m_Materials.Length) { if (meshR.m_Materials[i - firstSubMesh].TryGet(out var m_Material)) { mat = m_Material; } } ImportedMaterial iMat = ConvertMaterial(mat); iSubmesh.Material = iMat.Name; iSubmesh.VertexList = new List <ImportedVertex>((int)submesh.vertexCount); var vertexColours = mesh.m_Colors != null && (mesh.m_Colors.Length == mesh.m_VertexCount * 3 || mesh.m_Colors.Length == mesh.m_VertexCount * 4); for (var j = mesh.m_SubMeshes[i].firstVertex; j < mesh.m_SubMeshes[i].firstVertex + mesh.m_SubMeshes[i].vertexCount; j++) { var iVertex = vertexColours ? new ImportedVertexWithColour() : new ImportedVertex(); //Vertices int c = 3; if (mesh.m_Vertices.Length == mesh.m_VertexCount * 4) { c = 4; } iVertex.Position = new Vector3(-mesh.m_Vertices[j * c], mesh.m_Vertices[j * c + 1], mesh.m_Vertices[j * c + 2]); //Normals if (mesh.m_Normals?.Length > 0) { if (mesh.m_Normals.Length == mesh.m_VertexCount * 3) { c = 3; } else if (mesh.m_Normals.Length == mesh.m_VertexCount * 4) { c = 4; } iVertex.Normal = new Vector3(-mesh.m_Normals[j * c], mesh.m_Normals[j * c + 1], mesh.m_Normals[j * c + 2]); } //Colors if (vertexColours) { if (mesh.m_Colors.Length == mesh.m_VertexCount * 3) { ((ImportedVertexWithColour)iVertex).Colour = new Color4(mesh.m_Colors[j * 3], mesh.m_Colors[j * 3 + 1], mesh.m_Colors[j * 3 + 2], 1.0f); } else { ((ImportedVertexWithColour)iVertex).Colour = new Color4(mesh.m_Colors[j * 4], mesh.m_Colors[j * 4 + 1], mesh.m_Colors[j * 4 + 2], mesh.m_Colors[j * 4 + 3]); } } //UV if (mesh.m_UV0 != null && mesh.m_UV0.Length == mesh.m_VertexCount * 2) { iVertex.UV = new[] { mesh.m_UV0[j * 2], mesh.m_UV0[j * 2 + 1] }; } else if (mesh.m_UV1 != null && mesh.m_UV1.Length == mesh.m_VertexCount * 2) { iVertex.UV = new[] { mesh.m_UV1[j * 2], mesh.m_UV1[j * 2 + 1] }; } //Tangent if (mesh.m_Tangents != null && mesh.m_Tangents.Length == mesh.m_VertexCount * 4) { iVertex.Tangent = new Vector4(-mesh.m_Tangents[j * 4], mesh.m_Tangents[j * 4 + 1], mesh.m_Tangents[j * 4 + 2], -mesh.m_Tangents[j * 4 + 3]); } //BoneInfluence if (mesh.m_Skin?.Length > 0) { var inf = mesh.m_Skin[j]; iVertex.BoneIndices = new int[4]; iVertex.Weights = new float[4]; for (var k = 0; k < 4; k++) { iVertex.BoneIndices[k] = inf.boneIndex[k]; iVertex.Weights[k] = inf.weight[k]; } } iSubmesh.VertexList.Add(iVertex); } //Face iSubmesh.FaceList = new List <ImportedFace>(numFaces); var end = firstFace + numFaces; for (int f = firstFace; f < end; f++) { var face = new ImportedFace(); face.VertexIndices = new int[3]; face.VertexIndices[0] = (int)(mesh.m_Indices[f * 3 + 2] - submesh.firstVertex); face.VertexIndices[1] = (int)(mesh.m_Indices[f * 3 + 1] - submesh.firstVertex); face.VertexIndices[2] = (int)(mesh.m_Indices[f * 3] - submesh.firstVertex); iSubmesh.FaceList.Add(face); } firstFace = end; iMesh.SubmeshList.Add(iSubmesh); } if (meshR is SkinnedMeshRenderer sMesh) { //Bone if (sMesh.m_Bones.Length > 0) { iMesh.BoneList = new List <ImportedBone>(sMesh.m_Bones.Length); for (int i = 0; i < sMesh.m_Bones.Length; i++) { var bone = new ImportedBone(); if (sMesh.m_Bones[i].TryGet(out var m_Transform)) { bone.Path = GetTransformPath(m_Transform); } if (!string.IsNullOrEmpty(bone.Path)) { var convert = Matrix.Scaling(new Vector3(-1, 1, 1)); bone.Matrix = convert * Matrix.Transpose(mesh.m_BindPose[i]) * convert; iMesh.BoneList.Add(bone); } } } else if (mesh.m_BindPose.Length > 0 && mesh.m_BoneNameHashes?.Length > 0 && mesh.m_BindPose.Length == mesh.m_BoneNameHashes.Length) { iMesh.BoneList = new List <ImportedBone>(mesh.m_BoneNameHashes.Length); for (int i = 0; i < mesh.m_BoneNameHashes.Length; i++) { var bone = new ImportedBone(); var boneHash = mesh.m_BoneNameHashes[i]; var path = GetPathFromHash(boneHash); bone.Path = FixBonePath(path); if (!string.IsNullOrEmpty(bone.Path)) { var convert = Matrix.Scaling(new Vector3(-1, 1, 1)); bone.Matrix = convert * Matrix.Transpose(mesh.m_BindPose[i]) * convert; iMesh.BoneList.Add(bone); } } } //Morphs if (mesh.m_Shapes?.shapes != null) { if (mesh.m_Shapes.shapes.Length > 0) { ImportedMorph morph = null; string lastGroup = ""; for (int i = 0; i < mesh.m_Shapes.channels.Length; i++) { string group = BlendShapeNameGroup(mesh, i); if (group != lastGroup) { morph = new ImportedMorph(); MorphList.Add(morph); morph.Path = iMesh.Path; morph.ClipName = group; morph.Channels = new List <Tuple <float, int, int> >(mesh.m_Shapes.channels.Length); morph.KeyframeList = new List <ImportedMorphKeyframe>(mesh.m_Shapes.shapes.Length); lastGroup = group; } morph.Channels.Add(new Tuple <float, int, int>(i < sMesh.m_BlendShapeWeights.Length ? sMesh.m_BlendShapeWeights[i] : 0f, morph.KeyframeList.Count, mesh.m_Shapes.channels[i].frameCount)); for (int frameIdx = 0; frameIdx < mesh.m_Shapes.channels[i].frameCount; frameIdx++) { ImportedMorphKeyframe keyframe = new ImportedMorphKeyframe(); keyframe.Name = BlendShapeNameExtension(mesh, i) + "_" + frameIdx; int shapeIdx = mesh.m_Shapes.channels[i].frameIndex + frameIdx; keyframe.VertexList = new List <ImportedVertex>((int)mesh.m_Shapes.shapes[shapeIdx].vertexCount); keyframe.MorphedVertexIndices = new List <ushort>((int)mesh.m_Shapes.shapes[shapeIdx].vertexCount); keyframe.Weight = shapeIdx < mesh.m_Shapes.fullWeights.Length ? mesh.m_Shapes.fullWeights[shapeIdx] : 100f; int lastVertIndex = (int)(mesh.m_Shapes.shapes[shapeIdx].firstVertex + mesh.m_Shapes.shapes[shapeIdx].vertexCount); for (int j = (int)mesh.m_Shapes.shapes[shapeIdx].firstVertex; j < lastVertIndex; j++) { var morphVert = mesh.m_Shapes.vertices[j]; ImportedVertex vert = GetSourceVertex(iMesh.SubmeshList, (int)morphVert.index); ImportedVertex destVert = new ImportedVertex(); Vector3 morphPos = morphVert.vertex; morphPos.X *= -1; destVert.Position = vert.Position + morphPos; Vector3 morphNormal = morphVert.normal; morphNormal.X *= -1; destVert.Normal = morphNormal; Vector4 morphTangent = new Vector4(morphVert.tangent, 0); morphTangent.X *= -1; destVert.Tangent = morphTangent; keyframe.VertexList.Add(destVert); keyframe.MorphedVertexIndices.Add((ushort)morphVert.index); } morph.KeyframeList.Add(keyframe); } } } } } //TODO combine mesh if (combine) { meshR.m_GameObject.TryGet(out var m_GameObject); var frame = RootFrame.FindChild(m_GameObject.m_Name); frame.LocalPosition = RootFrame.LocalPosition; frame.LocalRotation = RootFrame.LocalRotation; while (frame.Parent != null) { frame = frame.Parent; frame.LocalPosition = RootFrame.LocalPosition; frame.LocalRotation = RootFrame.LocalRotation; } } MeshList.Add(iMesh); }