mirror of
https://github.com/aelurum/AssetStudio.git
synced 2025-06-03 00:58:13 -04:00
improved AnimationClip export
This commit is contained in:
parent
ec8c3e71d6
commit
afae830ece
@ -15,7 +15,7 @@ namespace AssetStudio
|
|||||||
public List<ImportedMesh> MeshList { get; protected set; } = new List<ImportedMesh>();
|
public List<ImportedMesh> MeshList { get; protected set; } = new List<ImportedMesh>();
|
||||||
public List<ImportedMaterial> MaterialList { get; protected set; } = new List<ImportedMaterial>();
|
public List<ImportedMaterial> MaterialList { get; protected set; } = new List<ImportedMaterial>();
|
||||||
public List<ImportedTexture> TextureList { get; protected set; } = new List<ImportedTexture>();
|
public List<ImportedTexture> TextureList { get; protected set; } = new List<ImportedTexture>();
|
||||||
public List<ImportedAnimation> AnimationList { get; protected set; } = new List<ImportedAnimation>();
|
public List<ImportedKeyframedAnimation> AnimationList { get; protected set; } = new List<ImportedKeyframedAnimation>();
|
||||||
public List<ImportedMorph> MorphList { get; protected set; } = new List<ImportedMorph>();
|
public List<ImportedMorph> MorphList { get; protected set; } = new List<ImportedMorph>();
|
||||||
|
|
||||||
private Avatar avatar;
|
private Avatar avatar;
|
||||||
@ -651,14 +651,14 @@ namespace AssetStudio
|
|||||||
{
|
{
|
||||||
foreach (var assetPreloadData in animationClipHashSet)
|
foreach (var assetPreloadData in animationClipHashSet)
|
||||||
{
|
{
|
||||||
var clip = new AnimationClip(assetPreloadData);
|
var animationClip = new AnimationClip(assetPreloadData);
|
||||||
if (clip.m_Legacy)
|
var iAnim = new ImportedKeyframedAnimation();
|
||||||
|
AnimationList.Add(iAnim);
|
||||||
|
iAnim.Name = animationClip.m_Name;
|
||||||
|
iAnim.TrackList = new List<ImportedAnimationKeyframedTrack>();
|
||||||
|
if (animationClip.m_Legacy)
|
||||||
{
|
{
|
||||||
var iAnim = new ImportedKeyframedAnimation();
|
foreach (var m_RotationCurve in animationClip.m_RotationCurves)
|
||||||
iAnim.Name = clip.m_Name;
|
|
||||||
AnimationList.Add(iAnim);
|
|
||||||
iAnim.TrackList = new List<ImportedAnimationKeyframedTrack>();
|
|
||||||
foreach (var m_RotationCurve in clip.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);
|
||||||
@ -675,7 +675,7 @@ namespace AssetStudio
|
|||||||
track.Rotations.Add(new ImportedKeyframe<Vector3>(m_Curve.time, value));
|
track.Rotations.Add(new ImportedKeyframe<Vector3>(m_Curve.time, value));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
foreach (var m_PositionCurve in clip.m_PositionCurves)
|
foreach (var m_PositionCurve in animationClip.m_PositionCurves)
|
||||||
{
|
{
|
||||||
var path = m_PositionCurve.path;
|
var path = m_PositionCurve.path;
|
||||||
var boneName = path.Substring(path.LastIndexOf('/') + 1);
|
var boneName = path.Substring(path.LastIndexOf('/') + 1);
|
||||||
@ -691,7 +691,7 @@ namespace AssetStudio
|
|||||||
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)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
foreach (var m_ScaleCurve in clip.m_ScaleCurves)
|
foreach (var m_ScaleCurve in animationClip.m_ScaleCurves)
|
||||||
{
|
{
|
||||||
var path = m_ScaleCurve.path;
|
var path = m_ScaleCurve.path;
|
||||||
var boneName = path.Substring(path.LastIndexOf('/') + 1);
|
var boneName = path.Substring(path.LastIndexOf('/') + 1);
|
||||||
@ -707,184 +707,122 @@ namespace AssetStudio
|
|||||||
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 ((bool)Properties.Settings.Default["FixRotation"])
|
|
||||||
{
|
|
||||||
foreach (var track in iAnim.TrackList)
|
|
||||||
{
|
|
||||||
var prevKey = new Vector3();
|
|
||||||
foreach (var rotation in track.Rotations)
|
|
||||||
{
|
|
||||||
var value = rotation.value;
|
|
||||||
ReplaceOutOfBound(ref prevKey, ref value);
|
|
||||||
prevKey = value;
|
|
||||||
rotation.value = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var iAnim = new ImportedSampledAnimation();
|
var m_Clip = animationClip.m_MuscleClip.m_Clip;
|
||||||
iAnim.Name = clip.m_Name;
|
var streamedFrames = m_Clip.m_StreamedClip.ReadData();
|
||||||
iAnim.SampleRate = clip.m_SampleRate;
|
var m_ClipBindingConstant = animationClip.m_ClipBindingConstant;
|
||||||
AnimationList.Add(iAnim);
|
for (int frameIndex = 1; frameIndex < streamedFrames.Count - 1; frameIndex++)
|
||||||
int numTracks = (clip.m_MuscleClip.m_Clip.m_ConstantClip.data.Length + (int)clip.m_MuscleClip.m_Clip.m_DenseClip.m_CurveCount + (int)clip.m_MuscleClip.m_Clip.m_StreamedClip.curveCount + 9) / 10;
|
|
||||||
iAnim.TrackList = new List<ImportedAnimationSampledTrack>(numTracks);
|
|
||||||
var streamedFrames = clip.m_MuscleClip.m_Clip.m_StreamedClip.ReadData();
|
|
||||||
float[] streamedValues = new float[clip.m_MuscleClip.m_Clip.m_StreamedClip.curveCount];
|
|
||||||
int numFrames = Math.Max(clip.m_MuscleClip.m_Clip.m_DenseClip.m_FrameCount, streamedFrames.Count - 2);
|
|
||||||
for (int frameIdx = 0; frameIdx < numFrames; frameIdx++)
|
|
||||||
{
|
{
|
||||||
if (1 + frameIdx < streamedFrames.Count)
|
var frame = streamedFrames[frameIndex];
|
||||||
|
var streamedValues = frame.keyList.Select(x => x.value).ToArray();
|
||||||
|
for (int curveIndex = 0; curveIndex < frame.keyList.Count;)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < streamedFrames[1 + frameIdx].keyList.Count; i++)
|
ReadCurveData(iAnim, m_ClipBindingConstant, frame.keyList[curveIndex].index, frame.time, streamedValues, 0, ref curveIndex);
|
||||||
{
|
|
||||||
streamedValues[i] = streamedFrames[1 + frameIdx].keyList[i].value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int numStreamedCurves = 1 + frameIdx < streamedFrames.Count ? streamedFrames[1 + frameIdx].keyList.Count : 0;
|
|
||||||
int numCurves = numStreamedCurves + (int)clip.m_MuscleClip.m_Clip.m_DenseClip.m_CurveCount + clip.m_MuscleClip.m_Clip.m_ConstantClip.data.Length;
|
|
||||||
int streamOffset = numStreamedCurves - (int)clip.m_MuscleClip.m_Clip.m_StreamedClip.curveCount;
|
|
||||||
for (int curveIdx = 0; curveIdx < numCurves;)
|
|
||||||
{
|
|
||||||
GenericBinding binding;
|
|
||||||
float[] data;
|
|
||||||
int dataOffset;
|
|
||||||
if (1 + frameIdx < streamedFrames.Count && curveIdx < streamedFrames[1 + frameIdx].keyList.Count)
|
|
||||||
{
|
|
||||||
binding = clip.m_ClipBindingConstant.FindBinding(streamedFrames[1 + frameIdx].keyList[curveIdx].index);
|
|
||||||
data = streamedValues;
|
|
||||||
dataOffset = 0;
|
|
||||||
}
|
|
||||||
else if (curveIdx < numStreamedCurves + clip.m_MuscleClip.m_Clip.m_DenseClip.m_CurveCount)
|
|
||||||
{
|
|
||||||
binding = clip.m_ClipBindingConstant.FindBinding(curveIdx - streamOffset);
|
|
||||||
data = clip.m_MuscleClip.m_Clip.m_DenseClip.m_SampleArray;
|
|
||||||
dataOffset = numStreamedCurves - frameIdx * (int)clip.m_MuscleClip.m_Clip.m_DenseClip.m_CurveCount;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
binding = clip.m_ClipBindingConstant.FindBinding(curveIdx - streamOffset);
|
|
||||||
data = clip.m_MuscleClip.m_Clip.m_ConstantClip.data;
|
|
||||||
dataOffset = numStreamedCurves + (int)clip.m_MuscleClip.m_Clip.m_DenseClip.m_CurveCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (binding.path == 0)
|
|
||||||
{
|
|
||||||
curveIdx++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
string boneName = GetNameFromHashes(binding.path, binding.attribute);
|
|
||||||
ImportedAnimationSampledTrack track = iAnim.FindTrack(boneName);
|
|
||||||
if (track == null)
|
|
||||||
{
|
|
||||||
track = new ImportedAnimationSampledTrack();
|
|
||||||
track.Name = boneName;
|
|
||||||
iAnim.TrackList.Add(track);
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
switch (binding.attribute)
|
|
||||||
{
|
|
||||||
case 1:
|
|
||||||
if (track.Translations == null)
|
|
||||||
{
|
|
||||||
track.Translations = new Vector3?[numFrames];
|
|
||||||
}
|
|
||||||
|
|
||||||
track.Translations[frameIdx] = new Vector3
|
|
||||||
(
|
|
||||||
-data[curveIdx++ - dataOffset],
|
|
||||||
data[curveIdx++ - dataOffset],
|
|
||||||
data[curveIdx++ - dataOffset]
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
if (track.Rotations == null)
|
|
||||||
{
|
|
||||||
track.Rotations = new Vector3?[numFrames];
|
|
||||||
}
|
|
||||||
|
|
||||||
track.Rotations[frameIdx] = Fbx.QuaternionToEuler(new Quaternion
|
|
||||||
(
|
|
||||||
data[curveIdx++ - dataOffset],
|
|
||||||
-data[curveIdx++ - dataOffset],
|
|
||||||
-data[curveIdx++ - dataOffset],
|
|
||||||
data[curveIdx++ - dataOffset]
|
|
||||||
));
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
if (track.Scalings == null)
|
|
||||||
{
|
|
||||||
track.Scalings = new Vector3?[numFrames];
|
|
||||||
}
|
|
||||||
|
|
||||||
track.Scalings[frameIdx] = new Vector3
|
|
||||||
(
|
|
||||||
data[curveIdx++ - dataOffset],
|
|
||||||
data[curveIdx++ - dataOffset],
|
|
||||||
data[curveIdx++ - dataOffset]
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
if (track.Rotations == null)
|
|
||||||
{
|
|
||||||
track.Rotations = new Vector3?[numFrames];
|
|
||||||
}
|
|
||||||
|
|
||||||
track.Rotations[frameIdx] = new Vector3
|
|
||||||
(
|
|
||||||
data[curveIdx++ - dataOffset],
|
|
||||||
-data[curveIdx++ - dataOffset],
|
|
||||||
-data[curveIdx++ - dataOffset]
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
if (track.Curve == null)
|
|
||||||
{
|
|
||||||
track.Curve = new float?[numFrames];
|
|
||||||
}
|
|
||||||
|
|
||||||
track.Curve[frameIdx] = data[curveIdx++ - dataOffset];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
//errors.Append(" ").Append(boneName).Append(" a=").Append(binding.attribute).Append(" ci=").Append(curveIdx).Append("/#=").Append(numCurves).Append(" of=").Append(dataOffset).Append(" f=").Append(frameIdx).Append("/#=").Append(numFrames).Append("\n");
|
|
||||||
//TODO Display error
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
var m_DenseClip = m_Clip.m_DenseClip;
|
||||||
if ((bool)Properties.Settings.Default["FixRotation"])
|
var streamCount = m_Clip.m_StreamedClip.curveCount;
|
||||||
|
for (int frameIndex = 0; frameIndex < m_DenseClip.m_FrameCount; frameIndex++)
|
||||||
{
|
{
|
||||||
foreach (var track in iAnim.TrackList)
|
var time = frameIndex / m_DenseClip.m_SampleRate;
|
||||||
|
var frameOffset = frameIndex * m_DenseClip.m_CurveCount;
|
||||||
|
for (int curveIndex = 0; curveIndex < m_DenseClip.m_CurveCount;)
|
||||||
{
|
{
|
||||||
if (track.Rotations == null)
|
var index = streamCount + curveIndex;
|
||||||
continue;
|
ReadCurveData(iAnim, m_ClipBindingConstant, (int)index, time, m_DenseClip.m_SampleArray, (int)frameOffset, ref curveIndex);
|
||||||
var prevKey = new Vector3();
|
}
|
||||||
for (var i = 0; i < track.Rotations.Length; i++)
|
}
|
||||||
{
|
var m_ConstantClip = m_Clip.m_ConstantClip;
|
||||||
var rotation = track.Rotations[i];
|
var denseCount = m_Clip.m_DenseClip.m_CurveCount;
|
||||||
if (rotation == null)
|
var time2 = 0.0f;
|
||||||
continue;
|
for (int i = 0; i < 2; i++)
|
||||||
var value = new Vector3(rotation.Value.X, rotation.Value.Y, rotation.Value.Z);
|
{
|
||||||
ReplaceOutOfBound(ref prevKey, ref value);
|
for (int curveIndex = 0; curveIndex < m_ConstantClip.data.Length;)
|
||||||
prevKey = value;
|
{
|
||||||
track.Rotations[i] = value;
|
var index = streamCount + denseCount + curveIndex;
|
||||||
}
|
ReadCurveData(iAnim, m_ClipBindingConstant, (int)index, time2, m_ConstantClip.data, 0, ref curveIndex);
|
||||||
|
}
|
||||||
|
time2 = animationClip.m_MuscleClip.m_StopTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((bool)Properties.Settings.Default["FixRotation"])
|
||||||
|
{
|
||||||
|
foreach (var track in iAnim.TrackList)
|
||||||
|
{
|
||||||
|
var prevKey = new Vector3();
|
||||||
|
foreach (var rotation in track.Rotations)
|
||||||
|
{
|
||||||
|
var value = rotation.value;
|
||||||
|
ReplaceOutOfBound(ref prevKey, ref value);
|
||||||
|
prevKey = value;
|
||||||
|
rotation.value = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void ReadCurveData(ImportedKeyframedAnimation iAnim, AnimationClipBindingConstant m_ClipBindingConstant, int index, float time, float[] data, int offset, ref int curveIndex)
|
||||||
|
{
|
||||||
|
var binding = m_ClipBindingConstant.FindBinding(index);
|
||||||
|
if (binding.path == 0)
|
||||||
|
{
|
||||||
|
curveIndex++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
track.Translations.Add(new ImportedKeyframe<Vector3>(time, new Vector3
|
||||||
|
(
|
||||||
|
-data[curveIndex++ + offset],
|
||||||
|
data[curveIndex++ + offset],
|
||||||
|
data[curveIndex++ + offset]
|
||||||
|
)));
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
var value = Fbx.QuaternionToEuler(new Quaternion
|
||||||
|
(
|
||||||
|
data[curveIndex++ + offset],
|
||||||
|
-data[curveIndex++ + offset],
|
||||||
|
-data[curveIndex++ + offset],
|
||||||
|
data[curveIndex++ + offset]
|
||||||
|
));
|
||||||
|
track.Rotations.Add(new ImportedKeyframe<Vector3>(time, value));
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
track.Scalings.Add(new ImportedKeyframe<Vector3>(time, new Vector3
|
||||||
|
(
|
||||||
|
data[curveIndex++ + offset],
|
||||||
|
data[curveIndex++ + offset],
|
||||||
|
data[curveIndex++ + offset]
|
||||||
|
)));
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
track.Rotations.Add(new ImportedKeyframe<Vector3>(time, new Vector3
|
||||||
|
(
|
||||||
|
data[curveIndex++ + offset],
|
||||||
|
-data[curveIndex++ + offset],
|
||||||
|
-data[curveIndex++ + offset]
|
||||||
|
)));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
track.Curve.Add(new ImportedKeyframe<float>(time, data[curveIndex++]));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private string GetNameFromHashes(uint path, uint attribute)
|
private string GetNameFromHashes(uint path, uint attribute)
|
||||||
{
|
{
|
||||||
var boneName = GetNameFromBonePathHashes(path);
|
var boneName = GetNameFromBonePathHashes(path);
|
||||||
|
@ -66,8 +66,7 @@ namespace AssetStudio {
|
|||||||
void ExportMesh(FbxNode* pFrameNode, ImportedMesh^ meshList, bool normals);
|
void ExportMesh(FbxNode* pFrameNode, ImportedMesh^ meshList, bool normals);
|
||||||
FbxFileTexture* ExportTexture(ImportedTexture^ matTex, FbxMesh* pMesh);
|
FbxFileTexture* ExportTexture(ImportedTexture^ matTex, FbxMesh* pMesh);
|
||||||
void ExportAnimations(bool EulerFilter, float filterValue, bool flatInbetween);
|
void ExportAnimations(bool EulerFilter, float filterValue, bool flatInbetween);
|
||||||
void ExportKeyframedAnimation(ImportedKeyframedAnimation^ parser, FbxString& kTakeName, FbxAnimCurveFilterUnroll* EulerFilter, float filterPrecision, List<String^>^ pNotFound);
|
void ExportKeyframedAnimation(ImportedKeyframedAnimation^ parser, FbxString& kTakeName, FbxAnimCurveFilterUnroll* EulerFilter, float filterPrecision, bool flatInbetween);
|
||||||
void ExportSampledAnimation(ImportedSampledAnimation^ parser, FbxString& kTakeName, FbxAnimCurveFilterUnroll* EulerFilter, float filterPrecision, bool flatInbetween, List<String^>^ pNotFound);
|
|
||||||
void ExportMorphs(IImported^ imported, bool morphMask, bool flatInbetween);
|
void ExportMorphs(IImported^ imported, bool morphMask, bool flatInbetween);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -713,14 +713,12 @@ namespace AssetStudio
|
|||||||
|
|
||||||
void Fbx::Exporter::ExportAnimations(bool EulerFilter, float filterPrecision, bool flatInbetween)
|
void Fbx::Exporter::ExportAnimations(bool EulerFilter, float filterPrecision, bool flatInbetween)
|
||||||
{
|
{
|
||||||
List<ImportedAnimation^>^ importedAnimationList = imported->AnimationList;
|
auto importedAnimationList = imported->AnimationList;
|
||||||
if (importedAnimationList == nullptr)
|
if (importedAnimationList == nullptr)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<String^>^ pNotFound = gcnew List<String^>();
|
|
||||||
|
|
||||||
FbxAnimCurveFilterUnroll* lFilter = EulerFilter ? new FbxAnimCurveFilterUnroll() : NULL;
|
FbxAnimCurveFilterUnroll* lFilter = EulerFilter ? new FbxAnimCurveFilterUnroll() : NULL;
|
||||||
|
|
||||||
for (int i = 0; i < importedAnimationList->Count; i++)
|
for (int i = 0; i < importedAnimationList->Count; i++)
|
||||||
@ -740,37 +738,16 @@ namespace AssetStudio
|
|||||||
{
|
{
|
||||||
kTakeName = FbxString("Take") + FbxString(i);
|
kTakeName = FbxString("Take") + FbxString(i);
|
||||||
}
|
}
|
||||||
bool keyframed = dynamic_cast<ImportedKeyframedAnimation^>(importedAnimation) != nullptr;
|
ExportKeyframedAnimation(importedAnimation, kTakeName, lFilter, filterPrecision, flatInbetween);
|
||||||
if (keyframed)
|
|
||||||
{
|
|
||||||
ImportedKeyframedAnimation^ parser = (ImportedKeyframedAnimation^)importedAnimation;
|
|
||||||
ExportKeyframedAnimation(parser, kTakeName, lFilter, filterPrecision, pNotFound);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ImportedSampledAnimation^ parser = (ImportedSampledAnimation^)importedAnimation;
|
|
||||||
ExportSampledAnimation(parser, kTakeName, lFilter, filterPrecision, flatInbetween, pNotFound);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*if (pNotFound->Count > 0)
|
|
||||||
{
|
|
||||||
String^ pNotFoundString = gcnew String("Warning: Animations weren't exported for the following missing frames or morphs: ");
|
|
||||||
for (int i = 0; i < pNotFound->Count; i++)
|
|
||||||
{
|
|
||||||
pNotFoundString += pNotFound[i] + ", ";
|
|
||||||
}
|
|
||||||
Report::ReportLog(pNotFoundString->Substring(0, pNotFoundString->Length - 2));
|
|
||||||
}*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Fbx::Exporter::ExportKeyframedAnimation(ImportedKeyframedAnimation^ parser, FbxString& kTakeName, FbxAnimCurveFilterUnroll* EulerFilter, float filterPrecision, List<String^>^ pNotFound)
|
void Fbx::Exporter::ExportKeyframedAnimation(ImportedKeyframedAnimation^ parser, FbxString& kTakeName, FbxAnimCurveFilterUnroll* EulerFilter, float filterPrecision, bool flatInbetween)
|
||||||
{
|
{
|
||||||
List<ImportedAnimationKeyframedTrack^>^ pAnimationList = parser->TrackList;
|
List<ImportedAnimationKeyframedTrack^>^ pAnimationList = parser->TrackList;
|
||||||
|
|
||||||
char* lTakeName = kTakeName.Buffer();
|
char* lTakeName = kTakeName.Buffer();
|
||||||
|
|
||||||
FbxTime lTime;
|
|
||||||
FbxAnimStack* lAnimStack = FbxAnimStack::Create(pScene, lTakeName);
|
FbxAnimStack* lAnimStack = FbxAnimStack::Create(pScene, lTakeName);
|
||||||
FbxAnimLayer* lAnimLayer = FbxAnimLayer::Create(pScene, "Base Layer");
|
FbxAnimLayer* lAnimLayer = FbxAnimLayer::Create(pScene, "Base Layer");
|
||||||
lAnimStack->AddMember(lAnimLayer);
|
lAnimStack->AddMember(lAnimLayer);
|
||||||
@ -796,14 +773,7 @@ namespace AssetStudio
|
|||||||
Marshal::FreeHGlobal((IntPtr)pName);
|
Marshal::FreeHGlobal((IntPtr)pName);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pNode == NULL)
|
if (pNode != NULL)
|
||||||
{
|
|
||||||
if (!pNotFound->Contains(name))
|
|
||||||
{
|
|
||||||
pNotFound->Add(name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
FbxAnimCurve* lCurveSX = pNode->LclScaling.GetCurve(lAnimLayer, FBXSDK_CURVENODE_COMPONENT_X, true);
|
FbxAnimCurve* lCurveSX = pNode->LclScaling.GetCurve(lAnimLayer, FBXSDK_CURVENODE_COMPONENT_X, true);
|
||||||
FbxAnimCurve* lCurveSY = pNode->LclScaling.GetCurve(lAnimLayer, FBXSDK_CURVENODE_COMPONENT_Y, true);
|
FbxAnimCurve* lCurveSY = pNode->LclScaling.GetCurve(lAnimLayer, FBXSDK_CURVENODE_COMPONENT_Y, true);
|
||||||
@ -825,6 +795,8 @@ namespace AssetStudio
|
|||||||
lCurveTY->KeyModifyBegin();
|
lCurveTY->KeyModifyBegin();
|
||||||
lCurveTZ->KeyModifyBegin();
|
lCurveTZ->KeyModifyBegin();
|
||||||
|
|
||||||
|
FbxTime lTime;
|
||||||
|
|
||||||
for each (auto Scaling in keyframeList->Scalings)
|
for each (auto Scaling in keyframeList->Scalings)
|
||||||
{
|
{
|
||||||
lTime.SetSecondDouble(Scaling->time);
|
lTime.SetSecondDouble(Scaling->time);
|
||||||
@ -871,163 +843,14 @@ namespace AssetStudio
|
|||||||
EulerFilter->SetQualityTolerance(filterPrecision);
|
EulerFilter->SetQualityTolerance(filterPrecision);
|
||||||
EulerFilter->Apply(lCurve, 3);
|
EulerFilter->Apply(lCurve, 3);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Fbx::Exporter::ExportSampledAnimation(ImportedSampledAnimation^ parser, FbxString& kTakeName, FbxAnimCurveFilterUnroll* EulerFilter, float filterPrecision, bool flatInbetween, List<String^>^ pNotFound)
|
if (keyframeList->Curve->Count > 0)
|
||||||
{
|
|
||||||
List<ImportedAnimationSampledTrack^>^ pAnimationList = parser->TrackList;
|
|
||||||
|
|
||||||
char* lTakeName = kTakeName.Buffer();
|
|
||||||
|
|
||||||
FbxTime lTime;
|
|
||||||
FbxAnimStack* lAnimStack = FbxAnimStack::Create(pScene, lTakeName);
|
|
||||||
FbxAnimLayer* lAnimLayer = FbxAnimLayer::Create(pScene, "Base Layer");
|
|
||||||
lAnimStack->AddMember(lAnimLayer);
|
|
||||||
|
|
||||||
const double fps = 1.0 / parser->SampleRate;
|
|
||||||
|
|
||||||
for (int j = 0; j < pAnimationList->Count; j++)
|
|
||||||
{
|
|
||||||
ImportedAnimationSampledTrack^ sampleList = pAnimationList[j];
|
|
||||||
|
|
||||||
int endAt;
|
|
||||||
if (sampleList->Scalings && sampleList->Scalings->Length > 0)
|
|
||||||
{
|
|
||||||
endAt = sampleList->Scalings->Length;
|
|
||||||
}
|
|
||||||
else if (sampleList->Rotations && sampleList->Rotations->Length > 0)
|
|
||||||
{
|
|
||||||
endAt = sampleList->Rotations->Length;
|
|
||||||
}
|
|
||||||
else if (sampleList->Translations && sampleList->Translations->Length > 0)
|
|
||||||
{
|
|
||||||
endAt = sampleList->Translations->Length;
|
|
||||||
}
|
|
||||||
else if (sampleList->Curve && sampleList->Curve->Length > 0)
|
|
||||||
{
|
|
||||||
endAt = sampleList->Curve->Length;
|
|
||||||
}
|
|
||||||
|
|
||||||
String^ name = sampleList->Name;
|
|
||||||
int dotPos = name->IndexOf('.');
|
|
||||||
if (dotPos >= 0 && !ImportedHelpers::FindFrame(name, imported->FrameList[0]))
|
|
||||||
{
|
|
||||||
name = name->Substring(0, dotPos);
|
|
||||||
}
|
|
||||||
FbxNode* pNode = NULL;
|
|
||||||
char* pName = NULL;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
pName = Fbx::StringToCharArray(name);
|
|
||||||
pNode = pScene->GetRootNode()->FindChild(pName);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
Marshal::FreeHGlobal((IntPtr)pName);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pNode == NULL)
|
|
||||||
{
|
|
||||||
if (!pNotFound->Contains(name))
|
|
||||||
{
|
|
||||||
pNotFound->Add(name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (sampleList->Scalings)
|
|
||||||
{
|
|
||||||
FbxAnimCurve* lCurveSX = pNode->LclScaling.GetCurve(lAnimLayer, FBXSDK_CURVENODE_COMPONENT_X, true);
|
|
||||||
FbxAnimCurve* lCurveSY = pNode->LclScaling.GetCurve(lAnimLayer, FBXSDK_CURVENODE_COMPONENT_Y, true);
|
|
||||||
FbxAnimCurve* lCurveSZ = pNode->LclScaling.GetCurve(lAnimLayer, FBXSDK_CURVENODE_COMPONENT_Z, true);
|
|
||||||
lCurveSX->KeyModifyBegin();
|
|
||||||
lCurveSY->KeyModifyBegin();
|
|
||||||
lCurveSZ->KeyModifyBegin();
|
|
||||||
for (int k = 0; k < endAt; k++)
|
|
||||||
{
|
|
||||||
if (!sampleList->Scalings[k].HasValue)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
lTime.SetSecondDouble(fps * k);
|
|
||||||
|
|
||||||
lCurveSX->KeySet(lCurveSX->KeyAdd(lTime), lTime, sampleList->Scalings[k].Value.X);
|
|
||||||
lCurveSY->KeySet(lCurveSY->KeyAdd(lTime), lTime, sampleList->Scalings[k].Value.Y);
|
|
||||||
lCurveSZ->KeySet(lCurveSZ->KeyAdd(lTime), lTime, sampleList->Scalings[k].Value.Z);
|
|
||||||
}
|
|
||||||
lCurveSX->KeyModifyEnd();
|
|
||||||
lCurveSY->KeyModifyEnd();
|
|
||||||
lCurveSZ->KeyModifyEnd();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sampleList->Rotations)
|
|
||||||
{
|
|
||||||
FbxAnimCurve* lCurveRX = pNode->LclRotation.GetCurve(lAnimLayer, FBXSDK_CURVENODE_COMPONENT_X, true);
|
|
||||||
FbxAnimCurve* lCurveRY = pNode->LclRotation.GetCurve(lAnimLayer, FBXSDK_CURVENODE_COMPONENT_Y, true);
|
|
||||||
FbxAnimCurve* lCurveRZ = pNode->LclRotation.GetCurve(lAnimLayer, FBXSDK_CURVENODE_COMPONENT_Z, true);
|
|
||||||
lCurveRX->KeyModifyBegin();
|
|
||||||
lCurveRY->KeyModifyBegin();
|
|
||||||
lCurveRZ->KeyModifyBegin();
|
|
||||||
for (int k = 0; k < endAt; k++)
|
|
||||||
{
|
|
||||||
if (!sampleList->Rotations[k].HasValue)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
lTime.SetSecondDouble(fps * k);
|
|
||||||
|
|
||||||
lCurveRX->KeySet(lCurveRX->KeyAdd(lTime), lTime, sampleList->Rotations[k].Value.X);
|
|
||||||
lCurveRY->KeySet(lCurveRY->KeyAdd(lTime), lTime, sampleList->Rotations[k].Value.Y);
|
|
||||||
lCurveRZ->KeySet(lCurveRZ->KeyAdd(lTime), lTime, sampleList->Rotations[k].Value.Z);
|
|
||||||
}
|
|
||||||
lCurveRX->KeyModifyEnd();
|
|
||||||
lCurveRY->KeyModifyEnd();
|
|
||||||
lCurveRZ->KeyModifyEnd();
|
|
||||||
|
|
||||||
if (EulerFilter)
|
|
||||||
{
|
|
||||||
FbxAnimCurve* lCurve[3];
|
|
||||||
lCurve[0] = lCurveRX;
|
|
||||||
lCurve[1] = lCurveRY;
|
|
||||||
lCurve[2] = lCurveRZ;
|
|
||||||
EulerFilter->Reset();
|
|
||||||
EulerFilter->SetTestForPath(true);
|
|
||||||
EulerFilter->SetQualityTolerance(filterPrecision);
|
|
||||||
EulerFilter->Apply(lCurve, 3);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sampleList->Translations)
|
|
||||||
{
|
|
||||||
FbxAnimCurve* lCurveTX = pNode->LclTranslation.GetCurve(lAnimLayer, FBXSDK_CURVENODE_COMPONENT_X, true);
|
|
||||||
FbxAnimCurve* lCurveTY = pNode->LclTranslation.GetCurve(lAnimLayer, FBXSDK_CURVENODE_COMPONENT_Y, true);
|
|
||||||
FbxAnimCurve* lCurveTZ = pNode->LclTranslation.GetCurve(lAnimLayer, FBXSDK_CURVENODE_COMPONENT_Z, true);
|
|
||||||
lCurveTX->KeyModifyBegin();
|
|
||||||
lCurveTY->KeyModifyBegin();
|
|
||||||
lCurveTZ->KeyModifyBegin();
|
|
||||||
for (int k = 0; k < endAt; k++)
|
|
||||||
{
|
|
||||||
if (!sampleList->Translations[k].HasValue)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
lTime.SetSecondDouble(fps * k);
|
|
||||||
|
|
||||||
lCurveTX->KeySet(lCurveTX->KeyAdd(lTime), lTime, sampleList->Translations[k].Value.X);
|
|
||||||
lCurveTY->KeySet(lCurveTY->KeyAdd(lTime), lTime, sampleList->Translations[k].Value.Y);
|
|
||||||
lCurveTZ->KeySet(lCurveTZ->KeyAdd(lTime), lTime, sampleList->Translations[k].Value.Z);
|
|
||||||
}
|
|
||||||
lCurveTX->KeyModifyEnd();
|
|
||||||
lCurveTY->KeyModifyEnd();
|
|
||||||
lCurveTZ->KeyModifyEnd();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sampleList->Curve)
|
|
||||||
{
|
{
|
||||||
FbxNode* pMeshNode = pNode->GetChild(0);
|
FbxNode* pMeshNode = pNode->GetChild(0);
|
||||||
FbxMesh* pMesh = pMeshNode ? pMeshNode->GetMesh() : NULL;
|
FbxMesh* pMesh = pMeshNode ? pMeshNode->GetMesh() : NULL;
|
||||||
if (pMesh)
|
if (pMesh)
|
||||||
{
|
{
|
||||||
name = sampleList->Name->Substring(dotPos + 1);
|
name = keyframeList->Name->Substring(dotPos + 1);
|
||||||
int numBlendShapes = pMesh->GetDeformerCount(FbxDeformer::eBlendShape);
|
int numBlendShapes = pMesh->GetDeformerCount(FbxDeformer::eBlendShape);
|
||||||
for (int bsIdx = 0; bsIdx < numBlendShapes; bsIdx++)
|
for (int bsIdx = 0; bsIdx < numBlendShapes; bsIdx++)
|
||||||
{
|
{
|
||||||
@ -1067,28 +890,22 @@ namespace AssetStudio
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
flatMaxStrength = 100;
|
flatMaxStrength = 100;
|
||||||
//Report::ReportLog("Error! Weight for flat Blend-Shape " + shapeName + " not found! Using a value of " + flatMaxStrength);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
lCurve->KeyModifyBegin();
|
lCurve->KeyModifyBegin();
|
||||||
for (int k = 0; k < endAt; k++)
|
for each (auto Curve in keyframeList->Curve)
|
||||||
{
|
{
|
||||||
if (!sampleList->Curve[k].HasValue)
|
lTime.SetSecondDouble(Curve->time);
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
lTime.SetSecondDouble(fps * k);
|
|
||||||
|
|
||||||
auto keySetIndex = lCurve->KeyAdd(lTime);
|
auto keySetIndex = lCurve->KeyAdd(lTime);
|
||||||
|
|
||||||
if (!flatInbetween)
|
if (!flatInbetween)
|
||||||
{
|
{
|
||||||
lCurve->KeySet(keySetIndex, lTime, sampleList->Curve[k].Value);
|
lCurve->KeySet(keySetIndex, lTime, Curve->value);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
float val = sampleList->Curve[k].Value;
|
float val = Curve->value;
|
||||||
if (val >= flatMinStrength && val <= flatMaxStrength)
|
if (val >= flatMinStrength && val <= flatMaxStrength)
|
||||||
{
|
{
|
||||||
val = (val - flatMinStrength) * 100 / (flatMaxStrength - flatMinStrength);
|
val = (val - flatMinStrength) * 100 / (flatMaxStrength - flatMinStrength);
|
||||||
@ -1118,14 +935,6 @@ namespace AssetStudio
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
name = sampleList->Name;
|
|
||||||
if (!pNotFound->Contains(name))
|
|
||||||
{
|
|
||||||
pNotFound->Add(name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@ namespace AssetStudio
|
|||||||
List<ImportedMesh> MeshList { get; }
|
List<ImportedMesh> MeshList { get; }
|
||||||
List<ImportedMaterial> MaterialList { get; }
|
List<ImportedMaterial> MaterialList { get; }
|
||||||
List<ImportedTexture> TextureList { get; }
|
List<ImportedTexture> TextureList { get; }
|
||||||
List<ImportedAnimation> AnimationList { get; }
|
List<ImportedKeyframedAnimation> AnimationList { get; }
|
||||||
List<ImportedMorph> MorphList { get; }
|
List<ImportedMorph> MorphList { get; }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,34 +140,25 @@ namespace AssetStudio
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract class ImportedAnimation
|
public class ImportedKeyframedAnimation
|
||||||
{
|
{
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
}
|
|
||||||
|
|
||||||
public abstract class ImportedAnimationTrackContainer<TrackType> : ImportedAnimation where TrackType : ImportedAnimationTrack
|
public List<ImportedAnimationKeyframedTrack> TrackList { get; set; }
|
||||||
{
|
|
||||||
public List<TrackType> TrackList { get; set; }
|
|
||||||
|
|
||||||
public TrackType FindTrack(string name)
|
public ImportedAnimationKeyframedTrack FindTrack(string name)
|
||||||
{
|
{
|
||||||
return TrackList.Find(track => track.Name == name);
|
return TrackList.Find(track => track.Name == name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ImportedKeyframedAnimation : ImportedAnimationTrackContainer<ImportedAnimationKeyframedTrack>
|
public class ImportedAnimationKeyframedTrack
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public class ImportedSampledAnimation : ImportedAnimationTrackContainer<ImportedAnimationSampledTrack>
|
|
||||||
{
|
|
||||||
public float SampleRate { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract class ImportedAnimationTrack
|
|
||||||
{
|
{
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
|
public List<ImportedKeyframe<Vector3>> Scalings = new List<ImportedKeyframe<Vector3>>();
|
||||||
|
public List<ImportedKeyframe<Vector3>> Rotations = new List<ImportedKeyframe<Vector3>>();
|
||||||
|
public List<ImportedKeyframe<Vector3>> Translations = new List<ImportedKeyframe<Vector3>>();
|
||||||
|
public List<ImportedKeyframe<float>> Curve = new List<ImportedKeyframe<float>>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ImportedKeyframe<T>
|
public class ImportedKeyframe<T>
|
||||||
@ -182,21 +173,6 @@ namespace AssetStudio
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ImportedAnimationKeyframedTrack : ImportedAnimationTrack
|
|
||||||
{
|
|
||||||
public List<ImportedKeyframe<Vector3>> Scalings = new List<ImportedKeyframe<Vector3>>();
|
|
||||||
public List<ImportedKeyframe<Vector3>> Rotations = new List<ImportedKeyframe<Vector3>>();
|
|
||||||
public List<ImportedKeyframe<Vector3>> Translations = new List<ImportedKeyframe<Vector3>>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public class ImportedAnimationSampledTrack : ImportedAnimationTrack
|
|
||||||
{
|
|
||||||
public Vector3?[] Scalings;
|
|
||||||
public Vector3?[] Rotations;
|
|
||||||
public Vector3?[] Translations;
|
|
||||||
public float?[] Curve;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class ImportedMorph
|
public class ImportedMorph
|
||||||
{
|
{
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
|
Loading…
x
Reference in New Issue
Block a user