mirror of
https://github.com/aelurum/AssetStudio.git
synced 2025-05-25 05:40:21 -04:00
support optimized transform hierarchy
This commit is contained in:
parent
18af0a8856
commit
2d0278db87
@ -362,5 +362,10 @@ namespace AssetStudio
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public string FindBonePath(uint hash)
|
||||
{
|
||||
return m_TOS.Find(pair => pair.Key == hash).Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using SharpDX;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
@ -7,12 +8,19 @@ namespace AssetStudio
|
||||
{
|
||||
public class Transform
|
||||
{
|
||||
public PPtr m_GameObject = new PPtr();
|
||||
public PPtr m_GameObject;
|
||||
public float[] m_LocalRotation;
|
||||
public float[] m_LocalPosition;
|
||||
public float[] m_LocalScale;
|
||||
public List<PPtr> m_Children = new List<PPtr>();
|
||||
public PPtr m_Father = new PPtr();//can be transform or type 224 (as seen in Minions)
|
||||
public List<PPtr> m_Children;
|
||||
public PPtr m_Father;
|
||||
|
||||
public Transform(Vector3 t, Quaternion q, Vector3 s)
|
||||
{
|
||||
m_LocalPosition = new[] { t.X, t.Y, t.Z };
|
||||
m_LocalRotation = new[] { q.X, q.Y, q.Z, q.W };
|
||||
m_LocalScale = new[] { s.X, s.Y, s.Z };
|
||||
}
|
||||
|
||||
public Transform(AssetPreloadData preloadData)
|
||||
{
|
||||
@ -24,6 +32,7 @@ namespace AssetStudio
|
||||
m_LocalPosition = new[] { reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle() };
|
||||
m_LocalScale = new[] { reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle() };
|
||||
int m_ChildrenCount = reader.ReadInt32();
|
||||
m_Children = new List<PPtr>(m_ChildrenCount);
|
||||
for (int j = 0; j < m_ChildrenCount; j++)
|
||||
{
|
||||
m_Children.Add(sourceFile.ReadPPtr());
|
||||
|
@ -22,6 +22,7 @@ namespace AssetStudio
|
||||
private Dictionary<uint, string> morphChannelInfo = new Dictionary<uint, string>();
|
||||
private HashSet<AssetPreloadData> animationClipHashSet = new HashSet<AssetPreloadData>();
|
||||
private Dictionary<uint, string> bonePathHash = new Dictionary<uint, string>();
|
||||
private bool deoptimize;
|
||||
|
||||
public ModelConverter(GameObject m_GameObject)
|
||||
{
|
||||
@ -198,6 +199,18 @@ namespace AssetStudio
|
||||
return frame;
|
||||
}
|
||||
|
||||
private ImportedFrame ConvertFrame(Transform trans, string name)
|
||||
{
|
||||
var frame = new ImportedFrame();
|
||||
frame.Name = name;
|
||||
frame.InitChildren(0);
|
||||
var m_EulerRotation = QuatToEuler(new[] { trans.m_LocalRotation[0], -trans.m_LocalRotation[1], -trans.m_LocalRotation[2], trans.m_LocalRotation[3] });
|
||||
frame.LocalRotation = new[] { m_EulerRotation[0], m_EulerRotation[1], m_EulerRotation[2] };
|
||||
frame.LocalScale = new[] { trans.m_LocalScale[0], trans.m_LocalScale[1], trans.m_LocalScale[2] };
|
||||
frame.LocalPosition = new[] { -trans.m_LocalPosition[0], trans.m_LocalPosition[1], trans.m_LocalPosition[2] };
|
||||
return frame;
|
||||
}
|
||||
|
||||
private void ConvertFrames(Transform trans, ImportedFrame parent)
|
||||
{
|
||||
var frame = ConvertFrames(trans);
|
||||
@ -354,10 +367,6 @@ namespace AssetStudio
|
||||
{
|
||||
//Bone
|
||||
iMesh.BoneList = new List<ImportedBone>(sMesh.m_Bones.Length);
|
||||
/*if (sMesh.m_Bones.Length >= 256)
|
||||
{
|
||||
throw new Exception("Too many bones (" + mesh.m_BindPose.Length + ")");
|
||||
}*/
|
||||
for (int i = 0; i < sMesh.m_Bones.Length; i++)
|
||||
{
|
||||
var bone = new ImportedBone();
|
||||
@ -405,6 +414,52 @@ namespace AssetStudio
|
||||
iMesh.BoneList.Add(bone);
|
||||
}
|
||||
|
||||
if (sMesh.m_Bones.Length == 0 && mesh.m_BindPose?.Length > 0 && mesh.m_BoneNameHashes?.Length > 0)
|
||||
{
|
||||
//TODO move to Init method use Animator.m_HasTransformHierarchy to judge
|
||||
if (!deoptimize)
|
||||
{
|
||||
DeoptimizeTransformHierarchy();
|
||||
deoptimize = true;
|
||||
}
|
||||
//TODO Repeat code with above
|
||||
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 om = new float[4, 4];
|
||||
var m = mesh.m_BindPose[i];
|
||||
om[0, 0] = m[0, 0];
|
||||
om[0, 1] = -m[1, 0];
|
||||
om[0, 2] = -m[2, 0];
|
||||
om[0, 3] = m[3, 0];
|
||||
om[1, 0] = -m[0, 1];
|
||||
om[1, 1] = m[1, 1];
|
||||
om[1, 2] = m[2, 1];
|
||||
om[1, 3] = m[3, 1];
|
||||
om[2, 0] = -m[0, 2];
|
||||
om[2, 1] = m[1, 2];
|
||||
om[2, 2] = m[2, 2];
|
||||
om[2, 3] = m[3, 2];
|
||||
om[3, 0] = -m[0, 3];
|
||||
om[3, 1] = m[1, 3];
|
||||
om[3, 2] = m[2, 3];
|
||||
om[3, 3] = m[3, 3];
|
||||
bone.Matrix = om;
|
||||
iMesh.BoneList.Add(bone);
|
||||
}
|
||||
}
|
||||
|
||||
//Morphs
|
||||
if (mesh.m_Shapes != null)
|
||||
{
|
||||
@ -537,7 +592,7 @@ namespace AssetStudio
|
||||
return GetTransformPath(Father) + "/" + m_GameObject.m_Name;
|
||||
}
|
||||
|
||||
return String.Empty + m_GameObject.m_Name;
|
||||
return m_GameObject.m_Name;
|
||||
}
|
||||
|
||||
private ImportedMaterial ConvertMaterial(Material mat)
|
||||
@ -968,5 +1023,56 @@ namespace AssetStudio
|
||||
double newValue = count * 360.0 + cur;
|
||||
return (float)newValue;
|
||||
}
|
||||
|
||||
private void DeoptimizeTransformHierarchy()
|
||||
{
|
||||
if (avatar == null)
|
||||
return;
|
||||
// 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
|
||||
var rootFrame = FrameList[0];
|
||||
rootFrame.ClearChild();
|
||||
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 = ImportedHelpers.FindFrame(parentFrameName, rootFrame);
|
||||
}
|
||||
|
||||
var skeletonPose = avatar.m_Avatar.m_DefaultPose;
|
||||
var xform = skeletonPose.m_X[i];
|
||||
if (!(xform.t is Vector3 t))
|
||||
{
|
||||
var v4 = (Vector4)xform.t;
|
||||
t = (Vector3)v4;
|
||||
}
|
||||
if (!(xform.s is Vector3 s))
|
||||
{
|
||||
var v4 = (Vector4)xform.s;
|
||||
s = (Vector3)v4;
|
||||
}
|
||||
var curTransform = new Transform(t, xform.q, s);
|
||||
var frame = ConvertFrame(curTransform, transformName);
|
||||
parentFrame.AddChild(frame);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -64,6 +64,11 @@ namespace AssetStudio
|
||||
return children.IndexOf(obj);
|
||||
}
|
||||
|
||||
public void ClearChild()
|
||||
{
|
||||
children.Clear();
|
||||
}
|
||||
|
||||
public IEnumerator<ImportedFrame> GetEnumerator()
|
||||
{
|
||||
return children.GetEnumerator();
|
||||
@ -199,7 +204,7 @@ namespace AssetStudio
|
||||
|
||||
public static class ImportedHelpers
|
||||
{
|
||||
public static ImportedFrame FindFrame(String name, ImportedFrame root)
|
||||
public static ImportedFrame FindFrame(string name, ImportedFrame root)
|
||||
{
|
||||
ImportedFrame frame = root;
|
||||
if ((frame != null) && (frame.Name == name))
|
||||
@ -218,7 +223,7 @@ namespace AssetStudio
|
||||
return null;
|
||||
}
|
||||
|
||||
public static ImportedMesh FindMesh(String frameName, List<ImportedMesh> importedMeshList)
|
||||
public static ImportedMesh FindMesh(string frameName, List<ImportedMesh> importedMeshList)
|
||||
{
|
||||
foreach (ImportedMesh mesh in importedMeshList)
|
||||
{
|
||||
@ -252,7 +257,7 @@ namespace AssetStudio
|
||||
return null;
|
||||
}
|
||||
|
||||
public static ImportedMaterial FindMaterial(String name, List<ImportedMaterial> importedMats)
|
||||
public static ImportedMaterial FindMaterial(string name, List<ImportedMaterial> importedMats)
|
||||
{
|
||||
foreach (ImportedMaterial mat in importedMats)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user