From 54d78d55a0b973c379b3bd70f1b7ea5705d5a604 Mon Sep 17 00:00:00 2001 From: Perfare Date: Mon, 24 Dec 2018 04:25:55 +0800 Subject: [PATCH] Fixed #326 --- AssetStudio/Classes/Animator.cs | 2 +- AssetStudio/Classes/Avatar.cs | 12 - AssetStudio/IImported.cs | 127 +++++---- AssetStudioFBX/AssetStudioFBX.h | 1 + AssetStudioFBX/AssetStudioFBXExporter.cpp | 310 ++++++++-------------- AssetStudioUtility/ModelConverter.cs | 173 ++++++------ 6 files changed, 266 insertions(+), 359 deletions(-) diff --git a/AssetStudio/Classes/Animator.cs b/AssetStudio/Classes/Animator.cs index 5e9b59e..8bee51d 100644 --- a/AssetStudio/Classes/Animator.cs +++ b/AssetStudio/Classes/Animator.cs @@ -9,7 +9,7 @@ namespace AssetStudio { public PPtr m_Avatar; public PPtr m_Controller; - public bool m_HasTransformHierarchy; + public bool m_HasTransformHierarchy = true; public Animator(ObjectReader reader) : base(reader) { diff --git a/AssetStudio/Classes/Avatar.cs b/AssetStudio/Classes/Avatar.cs index f2ec658..074cce3 100644 --- a/AssetStudio/Classes/Avatar.cs +++ b/AssetStudio/Classes/Avatar.cs @@ -303,18 +303,6 @@ namespace AssetStudio } } - public string FindBoneName(uint hash) - { - foreach (var pair in m_TOS) - { - if (pair.Key == hash) - { - return pair.Value.Substring(pair.Value.LastIndexOf('/') + 1); - } - } - return null; - } - public string FindBonePath(uint hash) { return m_TOS.FirstOrDefault(pair => pair.Key == hash).Value; diff --git a/AssetStudio/IImported.cs b/AssetStudio/IImported.cs index d124c1e..e489c63 100644 --- a/AssetStudio/IImported.cs +++ b/AssetStudio/IImported.cs @@ -16,7 +16,7 @@ namespace AssetStudio List MorphList { get; } } - public class ImportedFrame : IEnumerable + public class ImportedFrame { public string Name { get; set; } public Vector3 LocalRotation { get; set; } @@ -47,20 +47,82 @@ namespace AssetStudio children.Remove(frame); } - public IEnumerator GetEnumerator() + public ImportedFrame FindFrameByPath(string path) { - return children.GetEnumerator(); + var splitPath = path.Split('/'); + if (Name != splitPath[0]) + throw new Exception($"Couldn't find path {path}"); + var curFrame = this; + for (int i = 1; i < splitPath.Length; i++) + { + curFrame = curFrame.FindChild(splitPath[i], false); + if (curFrame == null) + { + throw new Exception($"Couldn't find path {path}"); + } + } + return curFrame; } - IEnumerator IEnumerable.GetEnumerator() + public ImportedFrame FindFrame(string name) { - return GetEnumerator(); + if (Name == name) + { + return this; + } + foreach (var child in children) + { + var frame = child.FindFrame(name); + if (frame != null) + { + return frame; + } + } + return null; + } + + public ImportedFrame FindChild(string name, bool recursive = true) + { + foreach (var child in children) + { + if (recursive) + { + var frame = child.FindFrame(name); + if (frame != null) + { + return frame; + } + } + else + { + if (child.Name == name) + { + return child; + } + } + } + return null; + } + + public IEnumerable FindChilds(string name) + { + if (Name == name) + { + yield return this; + } + foreach (var child in children) + { + foreach (var item in child.FindChilds(name)) + { + yield return item; + } + } } } public class ImportedMesh { - public string Name { get; set; } + public string Path { get; set; } public List SubmeshList { get; set; } public List BoneList { get; set; } } @@ -94,7 +156,7 @@ namespace AssetStudio public class ImportedBone { - public string Name { get; set; } + public string Path { get; set; } public Matrix Matrix { get; set; } } @@ -129,12 +191,12 @@ namespace AssetStudio public List TrackList { get; set; } - public ImportedAnimationKeyframedTrack FindTrack(string name) + public ImportedAnimationKeyframedTrack FindTrack(string path) { - var track = TrackList.Find(x => x.Name == name); + var track = TrackList.Find(x => x.Path == path); if (track == null) { - track = new ImportedAnimationKeyframedTrack { Name = name }; + track = new ImportedAnimationKeyframedTrack { Path = path }; TrackList.Add(track); } @@ -144,11 +206,10 @@ namespace AssetStudio public class ImportedAnimationKeyframedTrack { - public string Name { get; set; } + public string Path { get; set; } public List> Scalings = new List>(); public List> Rotations = new List>(); public List> Translations = new List>(); - public List> Curve = new List>(); } public class ImportedKeyframe @@ -167,7 +228,7 @@ namespace AssetStudio public class ImportedMorph { - public string Name { get; set; } + public string Path { get; set; } public string ClipName { get; set; } public List> Channels { get; set; } public List KeyframeList { get; set; } @@ -184,45 +245,11 @@ namespace AssetStudio public static class ImportedHelpers { - public static ImportedFrame FindFrame(string name, ImportedFrame root) - { - if (root.Name == name) - { - return root; - } - foreach (var child in root) - { - var frame = FindFrame(name, child); - if (frame != null) - { - return frame; - } - } - return null; - } - - public static ImportedFrame FindChildOrRoot(string name, ImportedFrame root) - { - foreach (var child in root) - { - var frame = FindFrame(name, child); - if (frame != null) - { - return frame; - } - } - if (root.Name == name) - { - return root; - } - return null; - } - - public static ImportedMesh FindMesh(string frameName, List importedMeshList) + public static ImportedMesh FindMesh(string path, List importedMeshList) { foreach (var mesh in importedMeshList) { - if (mesh.Name == frameName) + if (mesh.Path == path) { return mesh; } @@ -243,7 +270,7 @@ namespace AssetStudio foreach (var mesh in importedMeshList) { - if (mesh.Name == framePath) + if (mesh.Path == framePath) { return mesh; } diff --git a/AssetStudioFBX/AssetStudioFBX.h b/AssetStudioFBX/AssetStudioFBX.h index 160b61c..be9b2b7 100644 --- a/AssetStudioFBX/AssetStudioFBX.h +++ b/AssetStudioFBX/AssetStudioFBX.h @@ -76,6 +76,7 @@ namespace AssetStudio { void SetJointsFromImportedMeshes(bool allBones); void ExportFrame(FbxNode* pParentNode, ImportedFrame^ frame); void ExportMesh(FbxNode* pFrameNode, ImportedMesh^ meshList, bool normals); + FbxNode* FindNodeByPath(String ^ path, bool recursive); FbxFileTexture* ExportTexture(ImportedTexture^ matTex, FbxMesh* pMesh); void ExportAnimations(bool eulerFilter, float filterValue, bool flatInbetween); void ExportKeyframedAnimation(ImportedKeyframedAnimation^ parser, FbxString& kTakeName, FbxAnimCurveFilterUnroll* eulerFilter, float filterPrecision, bool flatInbetween); diff --git a/AssetStudioFBX/AssetStudioFBXExporter.cpp b/AssetStudioFBX/AssetStudioFBXExporter.cpp index bc0931d..a824a4e 100644 --- a/AssetStudioFBX/AssetStudioFBXExporter.cpp +++ b/AssetStudioFBX/AssetStudioFBXExporter.cpp @@ -228,9 +228,10 @@ namespace AssetStudio { for (int i = 0; i < boneList->Count; i++) { - if (!exportFrames->Contains(boneList[i]->Name)) + String^ boneName = boneList[i]->Path->Substring(boneList[i]->Path->LastIndexOf('/') + 1); + if (!exportFrames->Contains(boneName)) { - ImportedFrame^ boneParent = ImportedHelpers::FindChildOrRoot(boneList[i]->Name, imported->RootFrame); + ImportedFrame^ boneParent = imported->RootFrame->FindFrameByPath(boneList[i]->Path); while (boneParent != nullptr) { exportFrames->Add(boneParent->Name); @@ -263,7 +264,7 @@ namespace AssetStudio for (int j = 0; j < boneList->Count; j++) { ImportedBone^ bone = boneList[j]; - boneNames->Add(bone->Name); + boneNames->Add(bone->Path); } } } @@ -307,8 +308,8 @@ namespace AssetStudio void Fbx::Exporter::ExportMesh(FbxNode* pFrameNode, ImportedMesh^ meshList, bool normals) { - int lastSlash = meshList->Name->LastIndexOf('/'); - String^ frameName = lastSlash < 0 ? meshList->Name : meshList->Name->Substring(lastSlash + 1); + int lastSlash = meshList->Path->LastIndexOf('/'); + String^ frameName = lastSlash < 0 ? meshList->Path : meshList->Path->Substring(lastSlash + 1); List^ boneList = meshList->BoneList; bool hasBones; if (exportSkins && boneList != nullptr) @@ -330,22 +331,8 @@ namespace AssetStudio for (int i = 0; i < boneList->Count; i++) { ImportedBone^ bone = boneList[i]; - String^ boneName = bone->Name; - char* pBoneName = NULL; - try - { - pBoneName = StringToCharArray(boneName); - FbxNode* foundNode = pScene->GetRootNode()->FindChild(pBoneName); - if (foundNode == NULL) - { - throw gcnew Exception(gcnew String("Couldn't find frame ") + boneName + gcnew String(" used by the bone")); - } - pBoneNodeList->Add(foundNode); - } - finally - { - Marshal::FreeHGlobal((IntPtr)pBoneName); - } + FbxNode* lFrame = FindNodeByPath(bone->Path, false); + pBoneNodeList->Add(lFrame); } } @@ -628,6 +615,41 @@ namespace AssetStudio } } + FbxNode* Fbx::Exporter::FindNodeByPath(String ^ path, bool recursive) + { + array^ splitPath = path->Split('/'); + FbxNode* lNode = pScene->GetRootNode(); + for (int i = 0; i < splitPath->Length; i++) + { + String^ frameName = splitPath[i]; + char* pNodeName = NULL; + try + { + pNodeName = StringToCharArray(frameName); + FbxNode* foundNode; + if (recursive && i == 0) + { + foundNode = lNode->FindChild(pNodeName); + } + else + { + foundNode = lNode->FindChild(pNodeName, false); + } + if (foundNode == NULL) + { + //throw gcnew Exception(gcnew String("Couldn't find path ") + path); + return NULL; + } + lNode = foundNode; + } + finally + { + Marshal::FreeHGlobal((IntPtr)pNodeName); + } + } + return lNode; + } + FbxFileTexture* Fbx::Exporter::ExportTexture(ImportedTexture^ matTex, FbxMesh* pMesh) { FbxFileTexture* pTex = NULL; @@ -749,187 +771,77 @@ namespace AssetStudio for (int j = 0; j < pAnimationList->Count; j++) { ImportedAnimationKeyframedTrack^ keyframeList = pAnimationList[j]; - String^ name = keyframeList->Name; - int dotPos = name->IndexOf('.'); - if (dotPos >= 0 && !ImportedHelpers::FindChildOrRoot(name, imported->RootFrame)) + FbxNode* pNode = FindNodeByPath(keyframeList->Path, true); + if (pNode != nullptr) { - name = name->Substring(0, dotPos); - } - FbxNode* pNode = NULL; - char* pName = NULL; - try - { - pName = StringToCharArray(name); - pNode = pScene->GetRootNode()->FindChild(pName); - } - finally - { - Marshal::FreeHGlobal((IntPtr)pName); - } + FbxAnimCurve* lCurveSX = pNode->LclScaling.GetCurve(lAnimLayer, FBXSDK_CURVENODE_COMPONENT_X, true); + FbxAnimCurve* lCurveSY = pNode->LclScaling.GetCurve(lAnimLayer, FBXSDK_CURVENODE_COMPONENT_Y, true); + FbxAnimCurve* lCurveSZ = pNode->LclScaling.GetCurve(lAnimLayer, FBXSDK_CURVENODE_COMPONENT_Z, true); + FbxAnimCurve* lCurveRX = pNode->LclRotation.GetCurve(lAnimLayer, FBXSDK_CURVENODE_COMPONENT_X, true); + FbxAnimCurve* lCurveRY = pNode->LclRotation.GetCurve(lAnimLayer, FBXSDK_CURVENODE_COMPONENT_Y, true); + FbxAnimCurve* lCurveRZ = pNode->LclRotation.GetCurve(lAnimLayer, FBXSDK_CURVENODE_COMPONENT_Z, true); + FbxAnimCurve* lCurveTX = pNode->LclTranslation.GetCurve(lAnimLayer, FBXSDK_CURVENODE_COMPONENT_X, true); + FbxAnimCurve* lCurveTY = pNode->LclTranslation.GetCurve(lAnimLayer, FBXSDK_CURVENODE_COMPONENT_Y, true); + FbxAnimCurve* lCurveTZ = pNode->LclTranslation.GetCurve(lAnimLayer, FBXSDK_CURVENODE_COMPONENT_Z, true); - if (pNode != NULL) + lCurveSX->KeyModifyBegin(); + lCurveSY->KeyModifyBegin(); + lCurveSZ->KeyModifyBegin(); + lCurveRX->KeyModifyBegin(); + lCurveRY->KeyModifyBegin(); + lCurveRZ->KeyModifyBegin(); + lCurveTX->KeyModifyBegin(); + lCurveTY->KeyModifyBegin(); + lCurveTZ->KeyModifyBegin(); + + FbxTime lTime; + + for each (auto Scaling in keyframeList->Scalings) { - FbxAnimCurve* lCurveSX = pNode->LclScaling.GetCurve(lAnimLayer, FBXSDK_CURVENODE_COMPONENT_X, true); - FbxAnimCurve* lCurveSY = pNode->LclScaling.GetCurve(lAnimLayer, FBXSDK_CURVENODE_COMPONENT_Y, true); - FbxAnimCurve* lCurveSZ = pNode->LclScaling.GetCurve(lAnimLayer, FBXSDK_CURVENODE_COMPONENT_Z, true); - FbxAnimCurve* lCurveRX = pNode->LclRotation.GetCurve(lAnimLayer, FBXSDK_CURVENODE_COMPONENT_X, true); - FbxAnimCurve* lCurveRY = pNode->LclRotation.GetCurve(lAnimLayer, FBXSDK_CURVENODE_COMPONENT_Y, true); - FbxAnimCurve* lCurveRZ = pNode->LclRotation.GetCurve(lAnimLayer, FBXSDK_CURVENODE_COMPONENT_Z, true); - FbxAnimCurve* lCurveTX = pNode->LclTranslation.GetCurve(lAnimLayer, FBXSDK_CURVENODE_COMPONENT_X, true); - FbxAnimCurve* lCurveTY = pNode->LclTranslation.GetCurve(lAnimLayer, FBXSDK_CURVENODE_COMPONENT_Y, true); - FbxAnimCurve* lCurveTZ = pNode->LclTranslation.GetCurve(lAnimLayer, FBXSDK_CURVENODE_COMPONENT_Z, true); + lTime.SetSecondDouble(Scaling->time); - lCurveSX->KeyModifyBegin(); - lCurveSY->KeyModifyBegin(); - lCurveSZ->KeyModifyBegin(); - lCurveRX->KeyModifyBegin(); - lCurveRY->KeyModifyBegin(); - lCurveRZ->KeyModifyBegin(); - lCurveTX->KeyModifyBegin(); - lCurveTY->KeyModifyBegin(); - lCurveTZ->KeyModifyBegin(); - - FbxTime lTime; - - for each (auto Scaling in keyframeList->Scalings) - { - lTime.SetSecondDouble(Scaling->time); - - lCurveSX->KeySet(lCurveSX->KeyAdd(lTime), lTime, Scaling->value.X); - lCurveSY->KeySet(lCurveSY->KeyAdd(lTime), lTime, Scaling->value.Y); - lCurveSZ->KeySet(lCurveSZ->KeyAdd(lTime), lTime, Scaling->value.Z); - } - for each (auto Rotation in keyframeList->Rotations) - { - lTime.SetSecondDouble(Rotation->time); - - lCurveRX->KeySet(lCurveRX->KeyAdd(lTime), lTime, Rotation->value.X); - lCurveRY->KeySet(lCurveRY->KeyAdd(lTime), lTime, Rotation->value.Y); - lCurveRZ->KeySet(lCurveRZ->KeyAdd(lTime), lTime, Rotation->value.Z); - } - for each (auto Translation in keyframeList->Translations) - { - lTime.SetSecondDouble(Translation->time); - - lCurveTX->KeySet(lCurveTX->KeyAdd(lTime), lTime, Translation->value.X); - lCurveTY->KeySet(lCurveTY->KeyAdd(lTime), lTime, Translation->value.Y); - lCurveTZ->KeySet(lCurveTZ->KeyAdd(lTime), lTime, Translation->value.Z); - } - - lCurveSX->KeyModifyEnd(); - lCurveSY->KeyModifyEnd(); - lCurveSZ->KeyModifyEnd(); - lCurveRX->KeyModifyEnd(); - lCurveRY->KeyModifyEnd(); - lCurveRZ->KeyModifyEnd(); - lCurveTX->KeyModifyEnd(); - lCurveTY->KeyModifyEnd(); - lCurveTZ->KeyModifyEnd(); - - if (eulerFilter) - { - FbxAnimCurve* lCurve[3]; - lCurve[0] = lCurveRX; - lCurve[1] = lCurveRY; - lCurve[2] = lCurveRZ; - eulerFilter->Reset(); - eulerFilter->SetQualityTolerance(filterPrecision); - eulerFilter->Apply(lCurve, 3); - } - - if (keyframeList->Curve->Count > 0) - { - FbxNode* pMeshNode = pNode->GetChild(0); - FbxMesh* pMesh = pMeshNode ? pMeshNode->GetMesh() : NULL; - if (pMesh) - { - name = keyframeList->Name->Substring(dotPos + 1); - int numBlendShapes = pMesh->GetDeformerCount(FbxDeformer::eBlendShape); - for (int bsIdx = 0; bsIdx < numBlendShapes; bsIdx++) - { - FbxBlendShape* lBlendShape = (FbxBlendShape*)pMesh->GetDeformer(bsIdx, FbxDeformer::eBlendShape); - int numChannels = lBlendShape->GetBlendShapeChannelCount(); - float flatMinStrength = 0, flatMaxStrength; - String^ shapeName = nullptr; - for (int chnIdx = 0; chnIdx < numChannels; chnIdx++) - { - FbxBlendShapeChannel* lChannel = lBlendShape->GetBlendShapeChannel(chnIdx); - String^ keyframeName; - if (!flatInbetween) - { - keyframeName = gcnew String(lChannel->GetName()); - } - else - { - shapeName = gcnew String(lChannel->GetTargetShape(0)->GetName()); - keyframeName = shapeName->Substring(0, shapeName->LastIndexOf("_")); - } - if (keyframeName == name) - { - FbxAnimCurve* lCurve = lChannel->DeformPercent.GetCurve(lAnimLayer, true); - if (flatInbetween) - { - FbxProperty weightProp; - WITH_MARSHALLED_STRING - ( - weightName, - shapeName + ".Weight", - weightProp = pMesh->FindProperty(weightName); - ); - if (weightProp.IsValid()) - { - flatMaxStrength = (float)weightProp.Get(); - } - else - { - flatMaxStrength = 100; - } - } - lCurve->KeyModifyBegin(); - for each (auto Curve in keyframeList->Curve) - { - lTime.SetSecondDouble(Curve->time); - - auto keySetIndex = lCurve->KeyAdd(lTime); - - if (!flatInbetween) - { - lCurve->KeySet(keySetIndex, lTime, Curve->value); - } - else - { - float val = Curve->value; - if (val >= flatMinStrength && val <= flatMaxStrength) - { - val = (val - flatMinStrength) * 100 / (flatMaxStrength - flatMinStrength); - } - else if (val < flatMinStrength) - { - val = 0; - } - else if (val > flatMaxStrength) - { - val = 100; - } - lCurve->KeySet(keySetIndex, lTime, val); - } - } - lCurve->KeyModifyEnd(); - if (!flatInbetween) - { - bsIdx = numBlendShapes; - break; - } - else - { - flatMinStrength = flatMaxStrength; - } - } - } - } - } - } + lCurveSX->KeySet(lCurveSX->KeyAdd(lTime), lTime, Scaling->value.X); + lCurveSY->KeySet(lCurveSY->KeyAdd(lTime), lTime, Scaling->value.Y); + lCurveSZ->KeySet(lCurveSZ->KeyAdd(lTime), lTime, Scaling->value.Z); } + for each (auto Rotation in keyframeList->Rotations) + { + lTime.SetSecondDouble(Rotation->time); + + lCurveRX->KeySet(lCurveRX->KeyAdd(lTime), lTime, Rotation->value.X); + lCurveRY->KeySet(lCurveRY->KeyAdd(lTime), lTime, Rotation->value.Y); + lCurveRZ->KeySet(lCurveRZ->KeyAdd(lTime), lTime, Rotation->value.Z); + } + for each (auto Translation in keyframeList->Translations) + { + lTime.SetSecondDouble(Translation->time); + + lCurveTX->KeySet(lCurveTX->KeyAdd(lTime), lTime, Translation->value.X); + lCurveTY->KeySet(lCurveTY->KeyAdd(lTime), lTime, Translation->value.Y); + lCurveTZ->KeySet(lCurveTZ->KeyAdd(lTime), lTime, Translation->value.Z); + } + + lCurveSX->KeyModifyEnd(); + lCurveSY->KeyModifyEnd(); + lCurveSZ->KeyModifyEnd(); + lCurveRX->KeyModifyEnd(); + lCurveRY->KeyModifyEnd(); + lCurveRZ->KeyModifyEnd(); + lCurveTX->KeyModifyEnd(); + lCurveTY->KeyModifyEnd(); + lCurveTZ->KeyModifyEnd(); + + if (eulerFilter) + { + FbxAnimCurve* lCurve[3]; + lCurve[0] = lCurveRX; + lCurve[1] = lCurveRY; + lCurve[2] = lCurveRZ; + eulerFilter->Reset(); + eulerFilter->SetQualityTolerance(filterPrecision); + eulerFilter->Apply(lCurve, 3); + } + } } } @@ -953,7 +865,7 @@ namespace AssetStudio { framePath = gcnew String(rootNode->GetName()) + "/" + framePath; } - if (framePath == meshList->Name) + if (framePath == meshList->Path) { pBaseNode = pMeshNode; break; @@ -966,7 +878,7 @@ namespace AssetStudio for each (ImportedMorph^ morph in imported->MorphList) { - if (morph->Name != meshList->Name) + if (morph->Path != meshList->Path) { continue; } diff --git a/AssetStudioUtility/ModelConverter.cs b/AssetStudioUtility/ModelConverter.cs index 5312511..3f4e111 100644 --- a/AssetStudioUtility/ModelConverter.cs +++ b/AssetStudioUtility/ModelConverter.cs @@ -18,10 +18,10 @@ namespace AssetStudio public List MorphList { get; protected set; } = new List(); private Avatar avatar; - private Dictionary morphChannelInfo = new Dictionary(); private HashSet animationClipHashSet = new HashSet(); private Dictionary bonePathHash = new Dictionary(); private Dictionary textureNameDictionary = new Dictionary(); + private Dictionary transformDictionary = new Dictionary(); public ModelConverter(GameObject m_GameObject) { @@ -183,9 +183,10 @@ namespace AssetStudio } } - private static ImportedFrame ConvertTransform(Transform trans) + private ImportedFrame ConvertTransform(Transform trans) { var frame = new ImportedFrame(trans.m_Children.Length); + transformDictionary.Add(trans, frame); trans.m_GameObject.TryGet(out var m_GameObject); frame.Name = m_GameObject.m_Name; SetFrame(frame, trans.m_LocalPosition, trans.m_LocalRotation, trans.m_LocalScale); @@ -232,7 +233,7 @@ namespace AssetStudio return; var iMesh = new ImportedMesh(); meshR.m_GameObject.TryGet(out var m_GameObject2); - iMesh.Name = GetMeshPath(m_GameObject2.m_Transform); + iMesh.Path = GetTransformPath(m_GameObject2.m_Transform); iMesh.SubmeshList = new List(); var subHashSet = new HashSet(); var combine = false; @@ -358,46 +359,37 @@ namespace AssetStudio iMesh.SubmeshList.Add(iSubmesh); } - //Bone - iMesh.BoneList = new List(); - if (mesh.m_BindPose?.Length > 0 && mesh.m_BoneNameHashes?.Length > 0 && mesh.m_BindPose.Length == mesh.m_BoneNameHashes.Length) - { - for (int i = 0; i < mesh.m_BindPose.Length; i++) - { - var bone = new ImportedBone(); - var boneHash = mesh.m_BoneNameHashes[i]; - bone.Name = GetNameFromBonePathHashes(boneHash); - if (string.IsNullOrEmpty(bone.Name)) - { - bone.Name = avatar?.FindBoneName(boneHash); - } - if (string.IsNullOrEmpty(bone.Name)) - { - //throw new Exception("A Bone could neither be found by hash in Avatar nor by index in SkinnedMeshRenderer."); - continue; - } - var convert = Matrix.Scaling(new Vector3(-1, 1, 1)); - bone.Matrix = convert * Matrix.Transpose(mesh.m_BindPose[i]) * convert; - iMesh.BoneList.Add(bone); - } - } - if (meshR is SkinnedMeshRenderer sMesh) { - //Bone for 4.3 down and other - if (iMesh.BoneList.Count == 0) + //Bone + if (sMesh.m_Bones.Length > 0) { + iMesh.BoneList = new List(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)) { - if (m_Transform.m_GameObject.TryGet(out var m_GameObject)) - { - bone.Name = m_GameObject.m_Name; - } + bone.Path = GetTransformPath(m_Transform); } - if (!string.IsNullOrEmpty(bone.Name)) + 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(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; @@ -407,12 +399,8 @@ namespace AssetStudio } //Morphs - if (mesh.m_Shapes?.channels != null) + if (mesh.m_Shapes?.shapes != null) { - foreach (var channel in mesh.m_Shapes.channels) - { - morphChannelInfo[channel.nameHash] = channel.name; - } if (mesh.m_Shapes.shapes.Length > 0) { ImportedMorph morph = null; @@ -424,7 +412,7 @@ namespace AssetStudio { morph = new ImportedMorph(); MorphList.Add(morph); - morph.Name = iMesh.Name; + morph.Path = iMesh.Path; morph.ClipName = group; morph.Channels = new List>(mesh.m_Shapes.channels.Length); morph.KeyframeList = new List(mesh.m_Shapes.shapes.Length); @@ -470,7 +458,7 @@ namespace AssetStudio if (combine) { meshR.m_GameObject.TryGet(out var m_GameObject); - var frame = ImportedHelpers.FindChildOrRoot(m_GameObject.m_Name, RootFrame); + var frame = RootFrame.FindChild(m_GameObject.m_Name); frame.LocalPosition = RootFrame.LocalPosition; frame.LocalRotation = RootFrame.LocalRotation; while (frame.Parent != null) @@ -508,26 +496,43 @@ namespace AssetStudio return null; } - private string GetMeshPath(Transform meshTransform) + private string GetTransformPath(Transform transform) { - meshTransform.m_GameObject.TryGet(out var m_GameObject); - var curFrame = ImportedHelpers.FindChildOrRoot(m_GameObject.m_Name, RootFrame); - var path = curFrame.Name; - while (curFrame.Parent != null) - { - curFrame = curFrame.Parent; - path = curFrame.Name + "/" + path; - } + var frame = transformDictionary[transform]; + return GetFramePath(frame); + } + private static string GetFramePath(ImportedFrame frame) + { + var path = frame.Name; + while (frame.Parent != null) + { + frame = frame.Parent; + path = frame.Name + "/" + path; + } return path; } - private static string GetTransformPath(Transform transform) + private string FixBonePath(string path) + { + var name = path.Substring(path.LastIndexOf('/') + 1); + foreach (var frame in RootFrame.FindChilds(name)) + { + var fullPath = GetFramePath(frame); + if (fullPath.EndsWith(path)) + { + return fullPath; + } + } + return null; + } + + private static string GetTransformPathByFather(Transform transform) { transform.m_GameObject.TryGet(out var m_GameObject); if (transform.m_Father.TryGet(out var father)) { - return GetTransformPath(father) + "/" + m_GameObject.m_Name; + return GetTransformPathByFather(father) + "/" + m_GameObject.m_Name; } return m_GameObject.m_Name; @@ -680,9 +685,7 @@ namespace AssetStudio { foreach (var m_CompressedRotationCurve in animationClip.m_CompressedRotationCurves) { - var path = m_CompressedRotationCurve.m_Path; - var boneName = path.Substring(path.LastIndexOf('/') + 1); - var track = iAnim.FindTrack(boneName); + var track = iAnim.FindTrack(m_CompressedRotationCurve.m_Path); var numKeys = m_CompressedRotationCurve.m_Times.m_NumItems; var data = m_CompressedRotationCurve.m_Times.UnpackInts(); @@ -704,9 +707,7 @@ namespace AssetStudio } foreach (var m_RotationCurve in animationClip.m_RotationCurves) { - var path = m_RotationCurve.path; - var boneName = path.Substring(path.LastIndexOf('/') + 1); - var track = iAnim.FindTrack(boneName); + var track = iAnim.FindTrack(m_RotationCurve.path); foreach (var m_Curve in m_RotationCurve.curve.m_Curve) { var value = Fbx.QuaternionToEuler(new Quaternion(m_Curve.value.X, -m_Curve.value.Y, -m_Curve.value.Z, m_Curve.value.W)); @@ -715,9 +716,7 @@ namespace AssetStudio } foreach (var m_PositionCurve in animationClip.m_PositionCurves) { - var path = m_PositionCurve.path; - var boneName = path.Substring(path.LastIndexOf('/') + 1); - var track = iAnim.FindTrack(boneName); + var track = iAnim.FindTrack(m_PositionCurve.path); foreach (var m_Curve in m_PositionCurve.curve.m_Curve) { track.Translations.Add(new ImportedKeyframe(m_Curve.time, new Vector3(-m_Curve.value.X, m_Curve.value.Y, m_Curve.value.Z))); @@ -725,9 +724,7 @@ namespace AssetStudio } foreach (var m_ScaleCurve in animationClip.m_ScaleCurves) { - var path = m_ScaleCurve.path; - var boneName = path.Substring(path.LastIndexOf('/') + 1); - var track = iAnim.FindTrack(boneName); + var track = iAnim.FindTrack(m_ScaleCurve.path); foreach (var m_Curve in m_ScaleCurve.curve.m_Curve) { track.Scalings.Add(new ImportedKeyframe(m_Curve.time, new Vector3(m_Curve.value.X, m_Curve.value.Y, m_Curve.value.Z))); @@ -737,25 +734,21 @@ namespace AssetStudio { foreach (var m_EulerCurve in animationClip.m_EulerCurves) { - var path = m_EulerCurve.path; - var boneName = path.Substring(path.LastIndexOf('/') + 1); - var track = iAnim.FindTrack(boneName); + var track = iAnim.FindTrack(m_EulerCurve.path); foreach (var m_Curve in m_EulerCurve.curve.m_Curve) { track.Rotations.Add(new ImportedKeyframe(m_Curve.time, new Vector3(m_Curve.value.X, -m_Curve.value.Y, -m_Curve.value.Z))); } } } - foreach (var m_FloatCurve in animationClip.m_FloatCurves) + /*foreach (var m_FloatCurve in animationClip.m_FloatCurves) { - var path = m_FloatCurve.path; - var boneName = path.Substring(path.LastIndexOf('/') + 1); - var track = iAnim.FindTrack(boneName); + var track = iAnim.FindTrack(m_FloatCurve.path); foreach (var m_Curve in m_FloatCurve.curve.m_Curve) { track.Curve.Add(new ImportedKeyframe(m_Curve.time, m_Curve.value)); } - } + }*/ } else { @@ -810,8 +803,8 @@ namespace AssetStudio curveIndex++; return; } - var boneName = GetNameFromHashes(binding.path, binding.attribute); - var track = iAnim.FindTrack(boneName); + + var track = iAnim.FindTrack(GetPathFromHash(binding.path)); switch (binding.attribute) { @@ -850,37 +843,23 @@ namespace AssetStudio ))); break; default: - track.Curve.Add(new ImportedKeyframe(time, data[curveIndex++])); + //track.Curve.Add(new ImportedKeyframe(time, data[curveIndex++])); + curveIndex++; break; } } - private string GetNameFromHashes(uint path, uint attribute) + private string GetPathFromHash(uint hash) { - var boneName = GetNameFromBonePathHashes(path); + bonePathHash.TryGetValue(hash, out var boneName); if (string.IsNullOrEmpty(boneName)) { - boneName = avatar?.FindBoneName(path); + boneName = avatar?.FindBonePath(hash); } if (string.IsNullOrEmpty(boneName)) { - boneName = "unknown " + path; + boneName = "unknown " + hash; } - if (attribute > 4) - { - if (morphChannelInfo.TryGetValue(attribute, out var morphChannel)) - { - return boneName + "." + morphChannel; - } - return boneName + ".unknown_morphChannel " + attribute; - } - return boneName; - } - - private string GetNameFromBonePathHashes(uint path) - { - if (bonePathHash.TryGetValue(path, out var boneName)) - boneName = boneName.Substring(boneName.LastIndexOf('/') + 1); return boneName; } @@ -922,7 +901,7 @@ namespace AssetStudio private void CreateBonePathHash(Transform m_Transform) { - var name = GetTransformPath(m_Transform); + var name = GetTransformPathByFather(m_Transform); var crc = new SevenZip.CRC(); var bytes = Encoding.UTF8.GetBytes(name); crc.Update(bytes, 0, (uint)bytes.Length); @@ -971,13 +950,13 @@ namespace AssetStudio { transformName = strs.Last(); var parentFrameName = strs[strs.Length - 2]; - parentFrame = ImportedHelpers.FindChildOrRoot(parentFrameName, RootFrame); + parentFrame = RootFrame.FindChild(parentFrameName); } var skeletonPose = avatar.m_Avatar.m_DefaultPose; var xform = skeletonPose.m_X[i]; - var frame = ImportedHelpers.FindChildOrRoot(transformName, RootFrame); + var frame = RootFrame.FindChild(transformName); if (frame != null) { SetFrame(frame, xform.t, xform.q, xform.s);