mirror of
https://github.com/aelurum/AssetStudio.git
synced 2025-05-27 22:00:23 -04:00
support optimized transform hierarchy
This commit is contained in:
parent
18af0a8856
commit
2d0278db87
@ -362,5 +362,10 @@ namespace AssetStudio
|
|||||||
}
|
}
|
||||||
return null;
|
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.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
@ -7,12 +8,19 @@ namespace AssetStudio
|
|||||||
{
|
{
|
||||||
public class Transform
|
public class Transform
|
||||||
{
|
{
|
||||||
public PPtr m_GameObject = new PPtr();
|
public PPtr m_GameObject;
|
||||||
public float[] m_LocalRotation;
|
public float[] m_LocalRotation;
|
||||||
public float[] m_LocalPosition;
|
public float[] m_LocalPosition;
|
||||||
public float[] m_LocalScale;
|
public float[] m_LocalScale;
|
||||||
public List<PPtr> m_Children = new List<PPtr>();
|
public List<PPtr> m_Children;
|
||||||
public PPtr m_Father = new PPtr();//can be transform or type 224 (as seen in Minions)
|
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)
|
public Transform(AssetPreloadData preloadData)
|
||||||
{
|
{
|
||||||
@ -24,6 +32,7 @@ namespace AssetStudio
|
|||||||
m_LocalPosition = new[] { reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle() };
|
m_LocalPosition = new[] { reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle() };
|
||||||
m_LocalScale = new[] { reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle() };
|
m_LocalScale = new[] { reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle() };
|
||||||
int m_ChildrenCount = reader.ReadInt32();
|
int m_ChildrenCount = reader.ReadInt32();
|
||||||
|
m_Children = new List<PPtr>(m_ChildrenCount);
|
||||||
for (int j = 0; j < m_ChildrenCount; j++)
|
for (int j = 0; j < m_ChildrenCount; j++)
|
||||||
{
|
{
|
||||||
m_Children.Add(sourceFile.ReadPPtr());
|
m_Children.Add(sourceFile.ReadPPtr());
|
||||||
|
@ -22,6 +22,7 @@ namespace AssetStudio
|
|||||||
private Dictionary<uint, string> morphChannelInfo = new Dictionary<uint, string>();
|
private Dictionary<uint, string> morphChannelInfo = new Dictionary<uint, string>();
|
||||||
private HashSet<AssetPreloadData> animationClipHashSet = new HashSet<AssetPreloadData>();
|
private HashSet<AssetPreloadData> animationClipHashSet = new HashSet<AssetPreloadData>();
|
||||||
private Dictionary<uint, string> bonePathHash = new Dictionary<uint, string>();
|
private Dictionary<uint, string> bonePathHash = new Dictionary<uint, string>();
|
||||||
|
private bool deoptimize;
|
||||||
|
|
||||||
public ModelConverter(GameObject m_GameObject)
|
public ModelConverter(GameObject m_GameObject)
|
||||||
{
|
{
|
||||||
@ -198,6 +199,18 @@ namespace AssetStudio
|
|||||||
return frame;
|
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)
|
private void ConvertFrames(Transform trans, ImportedFrame parent)
|
||||||
{
|
{
|
||||||
var frame = ConvertFrames(trans);
|
var frame = ConvertFrames(trans);
|
||||||
@ -354,10 +367,6 @@ namespace AssetStudio
|
|||||||
{
|
{
|
||||||
//Bone
|
//Bone
|
||||||
iMesh.BoneList = new List<ImportedBone>(sMesh.m_Bones.Length);
|
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++)
|
for (int i = 0; i < sMesh.m_Bones.Length; i++)
|
||||||
{
|
{
|
||||||
var bone = new ImportedBone();
|
var bone = new ImportedBone();
|
||||||
@ -405,6 +414,52 @@ namespace AssetStudio
|
|||||||
iMesh.BoneList.Add(bone);
|
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
|
//Morphs
|
||||||
if (mesh.m_Shapes != null)
|
if (mesh.m_Shapes != null)
|
||||||
{
|
{
|
||||||
@ -537,7 +592,7 @@ namespace AssetStudio
|
|||||||
return GetTransformPath(Father) + "/" + m_GameObject.m_Name;
|
return GetTransformPath(Father) + "/" + m_GameObject.m_Name;
|
||||||
}
|
}
|
||||||
|
|
||||||
return String.Empty + m_GameObject.m_Name;
|
return m_GameObject.m_Name;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ImportedMaterial ConvertMaterial(Material mat)
|
private ImportedMaterial ConvertMaterial(Material mat)
|
||||||
@ -968,5 +1023,56 @@ namespace AssetStudio
|
|||||||
double newValue = count * 360.0 + cur;
|
double newValue = count * 360.0 + cur;
|
||||||
return (float)newValue;
|
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);
|
return children.IndexOf(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void ClearChild()
|
||||||
|
{
|
||||||
|
children.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
public IEnumerator<ImportedFrame> GetEnumerator()
|
public IEnumerator<ImportedFrame> GetEnumerator()
|
||||||
{
|
{
|
||||||
return children.GetEnumerator();
|
return children.GetEnumerator();
|
||||||
@ -199,7 +204,7 @@ namespace AssetStudio
|
|||||||
|
|
||||||
public static class ImportedHelpers
|
public static class ImportedHelpers
|
||||||
{
|
{
|
||||||
public static ImportedFrame FindFrame(String name, ImportedFrame root)
|
public static ImportedFrame FindFrame(string name, ImportedFrame root)
|
||||||
{
|
{
|
||||||
ImportedFrame frame = root;
|
ImportedFrame frame = root;
|
||||||
if ((frame != null) && (frame.Name == name))
|
if ((frame != null) && (frame.Name == name))
|
||||||
@ -218,7 +223,7 @@ namespace AssetStudio
|
|||||||
return null;
|
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)
|
foreach (ImportedMesh mesh in importedMeshList)
|
||||||
{
|
{
|
||||||
@ -252,7 +257,7 @@ namespace AssetStudio
|
|||||||
return null;
|
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)
|
foreach (ImportedMaterial mat in importedMats)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user