compressed AnimationClip supported

This commit is contained in:
Perfare 2018-09-08 10:01:44 +08:00
parent afae830ece
commit c9a98d7163
3 changed files with 195 additions and 36 deletions

View File

@ -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();
}

View File

@ -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)
{

View File

@ -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;
}
}