mirror of
https://github.com/aelurum/AssetStudio.git
synced 2025-05-25 05:40:21 -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 float m_Range { get; set; }
|
||||
@ -79,7 +79,7 @@ namespace AssetStudio
|
||||
public byte[] m_Data { get; set; }
|
||||
public byte m_BitSize { get; set; }
|
||||
|
||||
public PackedBitVector(EndianBinaryReader reader)
|
||||
public PackedFloatVector(EndianBinaryReader reader)
|
||||
{
|
||||
m_NumItems = reader.ReadUInt32();
|
||||
m_Range = reader.ReadSingle();
|
||||
@ -92,15 +92,53 @@ namespace AssetStudio
|
||||
m_BitSize = reader.ReadByte();
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
public class PackedBitVector2
|
||||
public class PackedIntVector
|
||||
{
|
||||
public uint m_NumItems { get; set; }
|
||||
public byte[] m_Data { get; set; }
|
||||
public byte m_BitSize { get; set; }
|
||||
|
||||
public PackedBitVector2(EndianBinaryReader reader)
|
||||
public PackedIntVector(EndianBinaryReader reader)
|
||||
{
|
||||
m_NumItems = reader.ReadUInt32();
|
||||
|
||||
@ -111,14 +149,40 @@ namespace AssetStudio
|
||||
m_BitSize = reader.ReadByte();
|
||||
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 byte[] m_Data { get; set; }
|
||||
|
||||
public PackedBitVector3(EndianBinaryReader reader)
|
||||
public PackedQuatVector(EndianBinaryReader reader)
|
||||
{
|
||||
m_NumItems = reader.ReadUInt32();
|
||||
|
||||
@ -127,23 +191,87 @@ namespace AssetStudio
|
||||
|
||||
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 string m_Path { get; set; }
|
||||
public PackedBitVector2 m_Times { get; set; }
|
||||
public PackedBitVector3 m_Values { get; set; }
|
||||
public PackedBitVector m_Slopes { get; set; }
|
||||
public PackedIntVector m_Times { get; set; }
|
||||
public PackedQuatVector m_Values { get; set; }
|
||||
public PackedFloatVector m_Slopes { get; set; }
|
||||
public int m_PreInfinity { get; set; }
|
||||
public int m_PostInfinity { get; set; }
|
||||
|
||||
public CompressedAnimationCurve(EndianBinaryReader reader)
|
||||
{
|
||||
m_Path = reader.ReadAlignedString();
|
||||
m_Times = new PackedBitVector2(reader);
|
||||
m_Values = new PackedBitVector3(reader);
|
||||
m_Slopes = new PackedBitVector(reader);
|
||||
m_Times = new PackedIntVector(reader);
|
||||
m_Values = new PackedQuatVector(reader);
|
||||
m_Slopes = new PackedFloatVector(reader);
|
||||
m_PreInfinity = reader.ReadInt32();
|
||||
m_PostInfinity = reader.ReadInt32();
|
||||
}
|
||||
|
@ -658,17 +658,35 @@ namespace AssetStudio
|
||||
iAnim.TrackList = new List<ImportedAnimationKeyframedTrack>();
|
||||
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)
|
||||
{
|
||||
var path = m_RotationCurve.path;
|
||||
var boneName = path.Substring(path.LastIndexOf('/') + 1);
|
||||
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)
|
||||
{
|
||||
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 boneName = path.Substring(path.LastIndexOf('/') + 1);
|
||||
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)
|
||||
{
|
||||
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 boneName = path.Substring(path.LastIndexOf('/') + 1);
|
||||
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)
|
||||
{
|
||||
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
|
||||
{
|
||||
@ -775,11 +804,6 @@ namespace AssetStudio
|
||||
}
|
||||
var boneName = GetNameFromHashes(binding.path, binding.attribute);
|
||||
var track = iAnim.FindTrack(boneName);
|
||||
if (track == null)
|
||||
{
|
||||
track = new ImportedAnimationKeyframedTrack { Name = boneName };
|
||||
iAnim.TrackList.Add(track);
|
||||
}
|
||||
|
||||
switch (binding.attribute)
|
||||
{
|
||||
|
@ -148,7 +148,14 @@ namespace AssetStudio
|
||||
|
||||
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