diff --git a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpAnimationImporter.cpp b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpAnimationImporter.cpp index 9522512619..e456f2dbab 100644 --- a/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpAnimationImporter.cpp +++ b/Code/Tools/SceneAPI/FbxSceneBuilder/Importers/AssImpAnimationImporter.cpp @@ -51,6 +51,7 @@ namespace AZ AZ_Warning("AnimationImporter", false, "Animation ticks per second should not be zero, defaulting to %d keyframes for animation.", keysSize); return keysSize; } + const double totalTicks = duration / ticksPerSecond; AZ::u32 numKeys = keysSize; // +1 because the animation is from [0, duration] - we have a keyframe at the end of the duration which needs to be included @@ -422,10 +423,12 @@ namespace AZ // If there is no bone animation on the current node, then generate one here. AZStd::shared_ptr createdAnimationData = AZStd::make_shared(); - createdAnimationData->ReserveKeyFrames( - animation->mDuration + - 1); // +1 because we start at 0 and the last keyframe is at mDuration instead of mDuration-1 - createdAnimationData->SetTimeStepBetweenFrames(1.0 / animation->mTicksPerSecond); + + const size_t numKeyframes = animation->mDuration + 1; // +1 because we start at 0 and the last keyframe is at mDuration instead of mDuration-1 + createdAnimationData->ReserveKeyFrames(numKeyframes); + + const double timeStepBetweenFrames = 1.0 / animation->mTicksPerSecond; + createdAnimationData->SetTimeStepBetweenFrames(timeStepBetweenFrames); // Set every frame of the animation to the start location of the node. aiMatrix4x4 combinedTransform = GetConcatenatedLocalTransform(currentNode); @@ -527,7 +530,7 @@ namespace AZ // are less predictable than just using a fixed time step. // AssImp documentation claims animation->mDuration is the duration of the animation in ticks, but // not all animations we've tested follow that pattern. Sometimes duration is in seconds. - const AZ::u32 numKeyFrames = GetNumKeyFrames( + const size_t numKeyFrames = GetNumKeyFrames( AZStd::max(AZStd::max(anim->mNumScalingKeys, anim->mNumPositionKeys), anim->mNumRotationKeys), animation->mDuration, animation->mTicksPerSecond); @@ -543,8 +546,10 @@ namespace AZ for (AZ::u32 frame = 0; frame < numKeyFrames; ++frame) { const double time = GetTimeForFrame(frame, animation->mTicksPerSecond); - aiVector3D scale = aiVector3D(1.f, 1.f, 1.f), position = aiVector3D(0.f, 0.f, 0.f); - aiQuaternion rotation(1.f, 0.f, 0.f, 0.f); + + aiVector3D scale(1.0f, 1.0f, 1.0f); + aiVector3D position(0.0f, 0.0f, 0.0f); + aiQuaternion rotation(1.0f, 0.0f, 0.0f, 0.0f); if (!SampleKeyFrame(scale, anim->mScalingKeys, anim->mNumScalingKeys, time, lastScaleIndex) || !SampleKeyFrame(position, anim->mPositionKeys, anim->mNumPositionKeys, time, lastPositionIndex) || !SampleKeyFrame(rotation, anim->mRotationKeys, anim->mNumRotationKeys, time, lastRotationIndex)) @@ -553,7 +558,6 @@ namespace AZ } aiMatrix4x4 transform(scale, rotation, position); - DataTypes::MatrixType animTransform = AssImpSDKWrapper::AssImpTypeConverter::ToTransform(transform); context.m_sourceSceneSystem.SwapTransformForUpAxis(animTransform); @@ -618,7 +622,7 @@ namespace AZ AZStd::shared_ptr morphAnimNode = AZStd::make_shared(); - const AZ::u32 numKeyFrames = GetNumKeyFrames(keys.size(), animation->mDuration, animation->mTicksPerSecond); + const size_t numKeyFrames = GetNumKeyFrames(keys.size(), animation->mDuration, animation->mTicksPerSecond); morphAnimNode->ReserveKeyFrames(numKeyFrames); morphAnimNode->SetTimeStepBetweenFrames(s_defaultTimeStepBetweenFrames); @@ -627,7 +631,7 @@ namespace AZ const AZ::u32 maxKeys = keys.size(); AZ::u32 keyIdx = 0; - for (AZ::u32 frame = 0; frame <= numKeyFrames; ++frame) + for (AZ::u32 frame = 0; frame < numKeyFrames; ++frame) { const double time = GetTimeForFrame(frame, animation->mTicksPerSecond); @@ -640,7 +644,6 @@ namespace AZ morphAnimNode->AddKeyFrame(weight); } - const size_t dotIndex = nodeName.find_last_of('.'); nodeName = nodeName.substr(dotIndex + 1); diff --git a/Gems/EMotionFX/Code/EMotionFX/Source/MotionData/NonUniformMotionData.cpp b/Gems/EMotionFX/Code/EMotionFX/Source/MotionData/NonUniformMotionData.cpp index fbe8a78cba..8a58300b88 100644 --- a/Gems/EMotionFX/Code/EMotionFX/Source/MotionData/NonUniformMotionData.cpp +++ b/Gems/EMotionFX/Code/EMotionFX/Source/MotionData/NonUniformMotionData.cpp @@ -258,8 +258,16 @@ namespace EMotionFX } else if (!timeValues.empty()) { - if (!AZ::IsClose(timeValues.front(), startTime, AZ::Constants::FloatEpsilon) || !AZ::IsClose(timeValues.back(), endTime, AZ::Constants::FloatEpsilon)) + if (!AZ::IsClose(timeValues.front(), startTime, AZ::Constants::FloatEpsilon)) { + AZ_Error("EMotionFX", false, "No keyframe present at the start of the animation (%f). The first keyframe is at %f.", + startTime, timeValues.front()); + return false; + } + if (!AZ::IsClose(timeValues.back(), endTime, AZ::Constants::FloatEpsilon)) + { + AZ_Error("EMotionFX", false, "No keyframe present at the end of the animation (%f). The last keyframe is at %f.", + endTime, timeValues.back()); return false; } } @@ -271,14 +279,25 @@ namespace EMotionFX { for (const JointData& jointData : m_jointData) { - if ((jointData.m_positionTrack.m_times.size() != jointData.m_positionTrack.m_values.size()) || (jointData.m_rotationTrack.m_times.size() != jointData.m_rotationTrack.m_values.size())) + if (jointData.m_positionTrack.m_times.size() != jointData.m_positionTrack.m_values.size()) { + AZ_Error("EMotionFX", false, "Number of position keyframe times (%d) does not match the number of keyframe values (%d).", + jointData.m_positionTrack.m_times.size(), jointData.m_positionTrack.m_values.size()); + return false; + } + + if (jointData.m_rotationTrack.m_times.size() != jointData.m_rotationTrack.m_values.size()) + { + AZ_Error("EMotionFX", false, "Number of rotation keyframe times (%d) does not match the number of keyframe values (%d).", + jointData.m_rotationTrack.m_times.size(), jointData.m_rotationTrack.m_values.size()); return false; } #ifndef EMFX_SCALE_DISABLED if (jointData.m_scaleTrack.m_times.size() != jointData.m_scaleTrack.m_values.size()) { + AZ_Error("EMotionFX", false, "Number of scale keyframe times (%d) does not match the number of keyframe values (%d).", + jointData.m_scaleTrack.m_times.size(), jointData.m_scaleTrack.m_values.size()); return false; } @@ -288,7 +307,8 @@ namespace EMotionFX } #endif - if (!VerifyKeyTrackTimeIntegrity(jointData.m_positionTrack.m_times) || !VerifyKeyTrackTimeIntegrity(jointData.m_rotationTrack.m_times)) + if (!VerifyKeyTrackTimeIntegrity(jointData.m_positionTrack.m_times) || + !VerifyKeyTrackTimeIntegrity(jointData.m_rotationTrack.m_times)) { return false; } @@ -300,7 +320,8 @@ namespace EMotionFX bool firstCheck = true; for (const JointData& jointData : m_jointData) { - if (!VerifyStartEndTimeIntegrity(jointData.m_positionTrack.m_times, firstCheck, startTime, endTime) || !VerifyStartEndTimeIntegrity(jointData.m_rotationTrack.m_times, firstCheck, startTime, endTime)) + if (!VerifyStartEndTimeIntegrity(jointData.m_positionTrack.m_times, firstCheck, startTime, endTime) || + !VerifyStartEndTimeIntegrity(jointData.m_rotationTrack.m_times, firstCheck, startTime, endTime)) { return false; } @@ -317,6 +338,8 @@ namespace EMotionFX { if (morphData.m_track.m_times.size() != morphData.m_track.m_values.size()) { + AZ_Error("EMotionFX", false, "Number of morph keyframe times (%d) does not match the number of keyframe values (%d).", + morphData.m_track.m_times.size(), morphData.m_track.m_values.size()); return false; } @@ -333,7 +356,17 @@ namespace EMotionFX for (const FloatData& floatData : m_floatData) { - if (floatData.m_track.m_times.size() != floatData.m_track.m_values.size() || !VerifyStartEndTimeIntegrity(floatData.m_track.m_times, firstCheck, startTime, endTime) || !VerifyKeyTrackTimeIntegrity(floatData.m_track.m_times)) + if (floatData.m_track.m_times.size() != floatData.m_track.m_values.size()) + { + AZ_Error("EMotionFX", false, "Number of float keyframe times (%d) does not match the number of keyframe values (%d).", + floatData.m_track.m_times.size(), floatData.m_track.m_values.size()); + return false; + } + if (!VerifyStartEndTimeIntegrity(floatData.m_track.m_times, firstCheck, startTime, endTime)) + { + return false; + } + if (!VerifyKeyTrackTimeIntegrity(floatData.m_track.m_times)) { return false; } @@ -657,6 +690,8 @@ namespace EMotionFX { if (curTime < prevKeyTime) { + AZ_Error("EMotionFX", false, "Keyframe times need to be ascending. Current keyframe time (%f) is smaller than the previous (%f).", + curTime, prevKeyTime); return false; } prevKeyTime = curTime;