mirror of
https://github.com/aelurum/AssetStudio.git
synced 2025-05-27 22:00:23 -04:00
compressed AnimationClip supported
This commit is contained in:
parent
afae830ece
commit
c9a98d7163
@ -71,7 +71,7 @@ namespace AssetStudio
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class PackedBitVector
|
public class PackedFloatVector
|
||||||
{
|
{
|
||||||
public uint m_NumItems { get; set; }
|
public uint m_NumItems { get; set; }
|
||||||
public float m_Range { get; set; }
|
public float m_Range { get; set; }
|
||||||
@ -79,7 +79,7 @@ namespace AssetStudio
|
|||||||
public byte[] m_Data { get; set; }
|
public byte[] m_Data { get; set; }
|
||||||
public byte m_BitSize { get; set; }
|
public byte m_BitSize { get; set; }
|
||||||
|
|
||||||
public PackedBitVector(EndianBinaryReader reader)
|
public PackedFloatVector(EndianBinaryReader reader)
|
||||||
{
|
{
|
||||||
m_NumItems = reader.ReadUInt32();
|
m_NumItems = reader.ReadUInt32();
|
||||||
m_Range = reader.ReadSingle();
|
m_Range = reader.ReadSingle();
|
||||||
@ -92,15 +92,53 @@ namespace AssetStudio
|
|||||||
m_BitSize = reader.ReadByte();
|
m_BitSize = reader.ReadByte();
|
||||||
reader.AlignStream(4);
|
reader.AlignStream(4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public float[] UnpackFloats(int itemCountInChunk, int chunkStride, int start = 0, int numChunks = -1)
|
||||||
|
{
|
||||||
|
int bitPos = m_BitSize * start;
|
||||||
|
int indexPos = bitPos / 8;
|
||||||
|
bitPos %= 8;
|
||||||
|
|
||||||
|
float scale = 1.0f / m_Range;
|
||||||
|
if (numChunks == -1)
|
||||||
|
numChunks = (int)m_NumItems / itemCountInChunk;
|
||||||
|
var end = chunkStride * numChunks / 4;
|
||||||
|
var data = new float[end];
|
||||||
|
for (var index = 0; index != end; index += chunkStride / 4)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < itemCountInChunk; ++i)
|
||||||
|
{
|
||||||
|
uint x = 0;
|
||||||
|
|
||||||
|
int bits = 0;
|
||||||
|
while (bits < m_BitSize)
|
||||||
|
{
|
||||||
|
x |= (uint)((m_Data[indexPos] >> bitPos) << bits);
|
||||||
|
int num = Math.Min(m_BitSize - bits, 8 - bitPos);
|
||||||
|
bitPos += num;
|
||||||
|
bits += num;
|
||||||
|
if (bitPos == 8)
|
||||||
|
{
|
||||||
|
indexPos++;
|
||||||
|
bitPos = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
x &= (uint)(1 << m_BitSize) - 1u;
|
||||||
|
data[index + i] = x / (scale * ((1 << m_BitSize) - 1)) + m_Start;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class PackedBitVector2
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class PackedIntVector
|
||||||
{
|
{
|
||||||
public uint m_NumItems { get; set; }
|
public uint m_NumItems { get; set; }
|
||||||
public byte[] m_Data { get; set; }
|
public byte[] m_Data { get; set; }
|
||||||
public byte m_BitSize { get; set; }
|
public byte m_BitSize { get; set; }
|
||||||
|
|
||||||
public PackedBitVector2(EndianBinaryReader reader)
|
public PackedIntVector(EndianBinaryReader reader)
|
||||||
{
|
{
|
||||||
m_NumItems = reader.ReadUInt32();
|
m_NumItems = reader.ReadUInt32();
|
||||||
|
|
||||||
@ -111,14 +149,40 @@ namespace AssetStudio
|
|||||||
m_BitSize = reader.ReadByte();
|
m_BitSize = reader.ReadByte();
|
||||||
reader.AlignStream(4);
|
reader.AlignStream(4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int[] UnpackInts()
|
||||||
|
{
|
||||||
|
var data = new int[m_NumItems];
|
||||||
|
int indexPos = 0;
|
||||||
|
int bitPos = 0;
|
||||||
|
for (int i = 0; i < m_NumItems; i++)
|
||||||
|
{
|
||||||
|
int bits = 0;
|
||||||
|
data[i] = 0;
|
||||||
|
while (bits < m_BitSize)
|
||||||
|
{
|
||||||
|
data[i] |= (m_Data[indexPos] >> bitPos) << bits;
|
||||||
|
int num = Math.Min(m_BitSize - bits, 8 - bitPos);
|
||||||
|
bitPos += num;
|
||||||
|
bits += num;
|
||||||
|
if (bitPos == 8)
|
||||||
|
{
|
||||||
|
indexPos++;
|
||||||
|
bitPos = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
data[i] &= (1 << m_BitSize) - 1;
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class PackedBitVector3
|
public class PackedQuatVector
|
||||||
{
|
{
|
||||||
public uint m_NumItems { get; set; }
|
public uint m_NumItems { get; set; }
|
||||||
public byte[] m_Data { get; set; }
|
public byte[] m_Data { get; set; }
|
||||||
|
|
||||||
public PackedBitVector3(EndianBinaryReader reader)
|
public PackedQuatVector(EndianBinaryReader reader)
|
||||||
{
|
{
|
||||||
m_NumItems = reader.ReadUInt32();
|
m_NumItems = reader.ReadUInt32();
|
||||||
|
|
||||||
@ -127,23 +191,87 @@ namespace AssetStudio
|
|||||||
|
|
||||||
reader.AlignStream(4);
|
reader.AlignStream(4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Quaternion[] UnpackQuats()
|
||||||
|
{
|
||||||
|
var data = new Quaternion[m_NumItems];
|
||||||
|
int indexPos = 0;
|
||||||
|
int bitPos = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < m_NumItems; i++)
|
||||||
|
{
|
||||||
|
uint flags = 0;
|
||||||
|
|
||||||
|
int bits = 0;
|
||||||
|
while (bits < 3)
|
||||||
|
{
|
||||||
|
flags |= (uint)((m_Data[indexPos] >> bitPos) << bits);
|
||||||
|
int num = Math.Min(3 - bits, 8 - bitPos);
|
||||||
|
bitPos += num;
|
||||||
|
bits += num;
|
||||||
|
if (bitPos == 8)
|
||||||
|
{
|
||||||
|
indexPos++;
|
||||||
|
bitPos = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
flags &= 7;
|
||||||
|
|
||||||
|
|
||||||
|
var q = new Quaternion();
|
||||||
|
float sum = 0;
|
||||||
|
for (int j = 0; j < 4; j++)
|
||||||
|
{
|
||||||
|
if ((flags & 3) != j)
|
||||||
|
{
|
||||||
|
int bitSize = ((flags & 3) + 1) % 4 == j ? 9 : 10;
|
||||||
|
uint x = 0;
|
||||||
|
|
||||||
|
bits = 0;
|
||||||
|
while (bits < bitSize)
|
||||||
|
{
|
||||||
|
x |= (uint)((m_Data[indexPos] >> bitPos) << bits);
|
||||||
|
int num = Math.Min(bitSize - bits, 8 - bitPos);
|
||||||
|
bitPos += num;
|
||||||
|
bits += num;
|
||||||
|
if (bitPos == 8)
|
||||||
|
{
|
||||||
|
indexPos++;
|
||||||
|
bitPos = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
x &= (uint)((1 << bitSize) - 1);
|
||||||
|
q[j] = x / (0.5f * ((1 << bitSize) - 1)) - 1;
|
||||||
|
sum += q[j] * q[j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int lastComponent = (int)(flags & 3);
|
||||||
|
q[lastComponent] = (float)Math.Sqrt(1 - sum);
|
||||||
|
if ((flags & 4) != 0u)
|
||||||
|
q[lastComponent] = -q[lastComponent];
|
||||||
|
data[i] = q;
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class CompressedAnimationCurve
|
public class CompressedAnimationCurve
|
||||||
{
|
{
|
||||||
public string m_Path { get; set; }
|
public string m_Path { get; set; }
|
||||||
public PackedBitVector2 m_Times { get; set; }
|
public PackedIntVector m_Times { get; set; }
|
||||||
public PackedBitVector3 m_Values { get; set; }
|
public PackedQuatVector m_Values { get; set; }
|
||||||
public PackedBitVector m_Slopes { get; set; }
|
public PackedFloatVector m_Slopes { get; set; }
|
||||||
public int m_PreInfinity { get; set; }
|
public int m_PreInfinity { get; set; }
|
||||||
public int m_PostInfinity { get; set; }
|
public int m_PostInfinity { get; set; }
|
||||||
|
|
||||||
public CompressedAnimationCurve(EndianBinaryReader reader)
|
public CompressedAnimationCurve(EndianBinaryReader reader)
|
||||||
{
|
{
|
||||||
m_Path = reader.ReadAlignedString();
|
m_Path = reader.ReadAlignedString();
|
||||||
m_Times = new PackedBitVector2(reader);
|
m_Times = new PackedIntVector(reader);
|
||||||
m_Values = new PackedBitVector3(reader);
|
m_Values = new PackedQuatVector(reader);
|
||||||
m_Slopes = new PackedBitVector(reader);
|
m_Slopes = new PackedFloatVector(reader);
|
||||||
m_PreInfinity = reader.ReadInt32();
|
m_PreInfinity = reader.ReadInt32();
|
||||||
m_PostInfinity = reader.ReadInt32();
|
m_PostInfinity = reader.ReadInt32();
|
||||||
}
|
}
|
||||||
|
@ -658,17 +658,35 @@ namespace AssetStudio
|
|||||||
iAnim.TrackList = new List<ImportedAnimationKeyframedTrack>();
|
iAnim.TrackList = new List<ImportedAnimationKeyframedTrack>();
|
||||||
if (animationClip.m_Legacy)
|
if (animationClip.m_Legacy)
|
||||||
{
|
{
|
||||||
|
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 numKeys = m_CompressedRotationCurve.m_Times.m_NumItems;
|
||||||
|
var data = m_CompressedRotationCurve.m_Times.UnpackInts();
|
||||||
|
var times = new float[numKeys];
|
||||||
|
int t = 0;
|
||||||
|
for (int i = 0; i < numKeys; i++)
|
||||||
|
{
|
||||||
|
t += data[i];
|
||||||
|
times[i] = t * 0.01f;
|
||||||
|
}
|
||||||
|
var quats = m_CompressedRotationCurve.m_Values.UnpackQuats();
|
||||||
|
|
||||||
|
for (int i = 0; i < numKeys; i++)
|
||||||
|
{
|
||||||
|
var quat = quats[i];
|
||||||
|
var value = Fbx.QuaternionToEuler(new Quaternion(quat.X, -quat.Y, -quat.Z, quat.W));
|
||||||
|
track.Rotations.Add(new ImportedKeyframe<Vector3>(times[i], value));
|
||||||
|
}
|
||||||
|
}
|
||||||
foreach (var m_RotationCurve in animationClip.m_RotationCurves)
|
foreach (var m_RotationCurve in animationClip.m_RotationCurves)
|
||||||
{
|
{
|
||||||
var path = m_RotationCurve.path;
|
var path = m_RotationCurve.path;
|
||||||
var boneName = path.Substring(path.LastIndexOf('/') + 1);
|
var boneName = path.Substring(path.LastIndexOf('/') + 1);
|
||||||
var track = iAnim.FindTrack(boneName);
|
var track = iAnim.FindTrack(boneName);
|
||||||
if (track == null)
|
|
||||||
{
|
|
||||||
track = new ImportedAnimationKeyframedTrack();
|
|
||||||
track.Name = boneName;
|
|
||||||
iAnim.TrackList.Add(track);
|
|
||||||
}
|
|
||||||
foreach (var m_Curve in m_RotationCurve.curve.m_Curve)
|
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));
|
var value = Fbx.QuaternionToEuler(new Quaternion(m_Curve.value.X, -m_Curve.value.Y, -m_Curve.value.Z, m_Curve.value.W));
|
||||||
@ -680,12 +698,6 @@ namespace AssetStudio
|
|||||||
var path = m_PositionCurve.path;
|
var path = m_PositionCurve.path;
|
||||||
var boneName = path.Substring(path.LastIndexOf('/') + 1);
|
var boneName = path.Substring(path.LastIndexOf('/') + 1);
|
||||||
var track = iAnim.FindTrack(boneName);
|
var track = iAnim.FindTrack(boneName);
|
||||||
if (track == null)
|
|
||||||
{
|
|
||||||
track = new ImportedAnimationKeyframedTrack();
|
|
||||||
track.Name = boneName;
|
|
||||||
iAnim.TrackList.Add(track);
|
|
||||||
}
|
|
||||||
foreach (var m_Curve in m_PositionCurve.curve.m_Curve)
|
foreach (var m_Curve in m_PositionCurve.curve.m_Curve)
|
||||||
{
|
{
|
||||||
track.Translations.Add(new ImportedKeyframe<Vector3>(m_Curve.time, new Vector3(-m_Curve.value.X, m_Curve.value.Y, m_Curve.value.Z)));
|
track.Translations.Add(new ImportedKeyframe<Vector3>(m_Curve.time, new Vector3(-m_Curve.value.X, m_Curve.value.Y, m_Curve.value.Z)));
|
||||||
@ -696,17 +708,34 @@ namespace AssetStudio
|
|||||||
var path = m_ScaleCurve.path;
|
var path = m_ScaleCurve.path;
|
||||||
var boneName = path.Substring(path.LastIndexOf('/') + 1);
|
var boneName = path.Substring(path.LastIndexOf('/') + 1);
|
||||||
var track = iAnim.FindTrack(boneName);
|
var track = iAnim.FindTrack(boneName);
|
||||||
if (track == null)
|
|
||||||
{
|
|
||||||
track = new ImportedAnimationKeyframedTrack();
|
|
||||||
track.Name = boneName;
|
|
||||||
iAnim.TrackList.Add(track);
|
|
||||||
}
|
|
||||||
foreach (var m_Curve in m_ScaleCurve.curve.m_Curve)
|
foreach (var m_Curve in m_ScaleCurve.curve.m_Curve)
|
||||||
{
|
{
|
||||||
track.Scalings.Add(new ImportedKeyframe<Vector3>(m_Curve.time, new Vector3(m_Curve.value.X, m_Curve.value.Y, m_Curve.value.Z)));
|
track.Scalings.Add(new ImportedKeyframe<Vector3>(m_Curve.time, new Vector3(m_Curve.value.X, m_Curve.value.Y, m_Curve.value.Z)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (animationClip.m_EulerCurves != null)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
foreach (var m_Curve in m_EulerCurve.curve.m_Curve)
|
||||||
|
{
|
||||||
|
track.Rotations.Add(new ImportedKeyframe<Vector3>(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)
|
||||||
|
{
|
||||||
|
var path = m_FloatCurve.path;
|
||||||
|
var boneName = path.Substring(path.LastIndexOf('/') + 1);
|
||||||
|
var track = iAnim.FindTrack(boneName);
|
||||||
|
foreach (var m_Curve in m_FloatCurve.curve.m_Curve)
|
||||||
|
{
|
||||||
|
track.Curve.Add(new ImportedKeyframe<float>(m_Curve.time, m_Curve.value));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -775,11 +804,6 @@ namespace AssetStudio
|
|||||||
}
|
}
|
||||||
var boneName = GetNameFromHashes(binding.path, binding.attribute);
|
var boneName = GetNameFromHashes(binding.path, binding.attribute);
|
||||||
var track = iAnim.FindTrack(boneName);
|
var track = iAnim.FindTrack(boneName);
|
||||||
if (track == null)
|
|
||||||
{
|
|
||||||
track = new ImportedAnimationKeyframedTrack { Name = boneName };
|
|
||||||
iAnim.TrackList.Add(track);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (binding.attribute)
|
switch (binding.attribute)
|
||||||
{
|
{
|
||||||
|
@ -148,7 +148,14 @@ namespace AssetStudio
|
|||||||
|
|
||||||
public ImportedAnimationKeyframedTrack FindTrack(string name)
|
public ImportedAnimationKeyframedTrack FindTrack(string name)
|
||||||
{
|
{
|
||||||
return TrackList.Find(track => track.Name == name);
|
var track = TrackList.Find(x => x.Name == name);
|
||||||
|
if (track == null)
|
||||||
|
{
|
||||||
|
track = new ImportedAnimationKeyframedTrack { Name = name };
|
||||||
|
TrackList.Add(track);
|
||||||
|
}
|
||||||
|
|
||||||
|
return track;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user