|
|
@@ -2004,7 +2004,7 @@ namespace bs
|
|
|
|
|
|
template<class T, int C>
|
|
|
TAnimationCurve<T> FBXImporter::importCurve(FbxAnimCurve*(&fbxCurve)[C], float (&defaultValues)[C],
|
|
|
- FBXImportOptions& importOptions, float start, float end)
|
|
|
+ FBXImportOptions& importOptions, float clipStart, float clipEnd)
|
|
|
{
|
|
|
int keyCounts[C];
|
|
|
for (int i = 0; i < C; i++)
|
|
|
@@ -2027,12 +2027,58 @@ namespace bs
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ // Determine curve length
|
|
|
+ float curveStart = std::numeric_limits<float>::infinity();
|
|
|
+ float curveEnd = -std::numeric_limits<float>::infinity();
|
|
|
+
|
|
|
+ for (INT32 i = 0; i < C; i++)
|
|
|
+ {
|
|
|
+ if(fbxCurve[i] == nullptr)
|
|
|
+ {
|
|
|
+ curveStart = std::min(0.0f, curveStart);
|
|
|
+ curveEnd = std::max(0.0f, curveEnd);
|
|
|
+
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ int keyCount = keyCounts[i];
|
|
|
+ for (INT32 j = 0; j < keyCount; j++)
|
|
|
+ {
|
|
|
+ FbxTime fbxTime = fbxCurve[i]->KeyGetTime(j);
|
|
|
+ float time = (float)fbxTime.GetSecondDouble();
|
|
|
+
|
|
|
+ curveStart = std::min(time, curveStart);
|
|
|
+ curveEnd = std::max(time, curveEnd);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
// Read keys directly
|
|
|
if(!importOptions.animResample && !forceResample)
|
|
|
{
|
|
|
bool foundMismatch = false;
|
|
|
int keyCount = keyCounts[0];
|
|
|
Vector<TKeyframe<T>> keyframes;
|
|
|
+
|
|
|
+ // All curves must match the length of the clip, so add a keyframe if first keyframe doesn't match the start time
|
|
|
+ if(curveStart > clipStart)
|
|
|
+ {
|
|
|
+ keyframes.push_back(TKeyframe<T>());
|
|
|
+ TKeyframe<T>& keyFrame = keyframes.back();
|
|
|
+
|
|
|
+ keyFrame.time = clipStart;
|
|
|
+
|
|
|
+ FbxTime fbxSampleTime;
|
|
|
+ fbxSampleTime.SetSecondDouble(clipStart);
|
|
|
+
|
|
|
+ for (int j = 0; j < C; j++)
|
|
|
+ {
|
|
|
+ setKeyframeValues(keyFrame, j,
|
|
|
+ fbxCurve[j]->Evaluate(fbxSampleTime),
|
|
|
+ fbxCurve[j]->EvaluateLeftDerivative(fbxSampleTime),
|
|
|
+ fbxCurve[j]->EvaluateRightDerivative(fbxSampleTime));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
for (int i = 0; i < keyCount; i++)
|
|
|
{
|
|
|
FbxTime fbxTime = fbxCurve[0]->KeyGetTime(i);
|
|
|
@@ -2054,7 +2100,7 @@ namespace bs
|
|
|
if(foundMismatch)
|
|
|
break;
|
|
|
|
|
|
- if (time < start || time > end)
|
|
|
+ if (time < clipStart || time > clipEnd)
|
|
|
continue;
|
|
|
|
|
|
keyframes.push_back(TKeyframe<T>());
|
|
|
@@ -2071,50 +2117,47 @@ namespace bs
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ // All curves must match the length of the clip, so add a keyframe if last keyframe doesn't match the end time
|
|
|
+ if(curveEnd < clipEnd)
|
|
|
+ {
|
|
|
+ keyframes.push_back(TKeyframe<T>());
|
|
|
+ TKeyframe<T>& keyFrame = keyframes.back();
|
|
|
+
|
|
|
+ keyFrame.time = clipEnd;
|
|
|
+
|
|
|
+ FbxTime fbxSampleTime;
|
|
|
+ fbxSampleTime.SetSecondDouble(clipEnd);
|
|
|
+
|
|
|
+ for (int j = 0; j < C; j++)
|
|
|
+ {
|
|
|
+ setKeyframeValues(keyFrame, j,
|
|
|
+ fbxCurve[j]->Evaluate(fbxSampleTime),
|
|
|
+ fbxCurve[j]->EvaluateLeftDerivative(fbxSampleTime),
|
|
|
+ fbxCurve[j]->EvaluateRightDerivative(fbxSampleTime));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
if (!foundMismatch)
|
|
|
return TAnimationCurve<T>(keyframes);
|
|
|
else
|
|
|
forceResample = true;
|
|
|
}
|
|
|
|
|
|
+ // Resample keys
|
|
|
if (!importOptions.animResample && forceResample)
|
|
|
LOGWRN("Animation has different keyframes for different curve components, forcing resampling.");
|
|
|
|
|
|
- // Resample keys
|
|
|
- float curveStart = std::numeric_limits<float>::infinity();
|
|
|
- float curveEnd = -std::numeric_limits<float>::infinity();
|
|
|
-
|
|
|
- for (INT32 i = 0; i < C; i++)
|
|
|
- {
|
|
|
- if(fbxCurve[i] == nullptr)
|
|
|
- {
|
|
|
- curveStart = std::min(0.0f, curveStart);
|
|
|
- curveEnd = std::max(0.0f, curveEnd);
|
|
|
-
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
- int keyCount = keyCounts[i];
|
|
|
- for (INT32 j = 0; j < keyCount; j++)
|
|
|
- {
|
|
|
- FbxTime fbxTime = fbxCurve[i]->KeyGetTime(j);
|
|
|
- float time = (float)fbxTime.GetSecondDouble();
|
|
|
-
|
|
|
- curveStart = std::min(time, curveStart);
|
|
|
- curveEnd = std::max(time, curveEnd);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- curveStart = Math::clamp(curveStart, start, end);
|
|
|
- curveEnd = Math::clamp(curveEnd, start, end);
|
|
|
+ // Make sure to resample along the length of the entire clip
|
|
|
+ curveStart = std::min(curveStart, clipStart);
|
|
|
+ curveEnd = std::max(curveEnd, clipEnd);
|
|
|
|
|
|
float curveLength = curveEnd - curveStart;
|
|
|
- INT32 numSamples = Math::ceilToInt(curveLength / importOptions.animSampleRate);
|
|
|
+ INT32 numSamples = Math::ceilToInt(curveLength / importOptions.animSampleRate) + 1;
|
|
|
|
|
|
// We don't use the exact provided sample rate but instead modify it slightly so it
|
|
|
// completely covers the curve range including start/end points while maintaining
|
|
|
// constant time step between keyframes.
|
|
|
- float dt = curveLength / (float)numSamples;
|
|
|
+ float dt = curveLength / (float)(numSamples - 1);
|
|
|
|
|
|
INT32 lastKeyframe[] = { 0, 0, 0 };
|
|
|
INT32 lastLeftTangent[] = { 0, 0, 0 };
|