AnimationChannel* createAnimationChannel(FbxNode* fbxNode, unsigned int targetAttrib, const vector<float>& keyTimes, const vector<float>& keyValues) { AnimationChannel* channel = new AnimationChannel(); channel->setTargetId(fbxNode->GetName()); channel->setKeyTimes(keyTimes); channel->setKeyValues(keyValues); channel->setInterpolation(AnimationChannel::LINEAR); channel->setTargetAttribute(targetAttrib); return channel; }
void FBXSceneEncoder::loadAnimationChannels(FbxAnimLayer* animLayer, FbxNode* fbxNode, Animation* animation) { const char* name = fbxNode->GetName(); //Node* node = _gamePlayFile.getNode(name); // Determine which properties are animated on this node // Find the transform at each key frame // TODO: Ignore properties that are not animated (scale, rotation, translation) // This should result in only one animation channel per animated node. float startTime = FLT_MAX, stopTime = -1.0f, frameRate = -FLT_MAX; bool tx = false, ty = false, tz = false, rx = false, ry = false, rz = false, sx = false, sy = false, sz = false; FbxAnimCurve* animCurve = NULL; animCurve = getCurve(fbxNode->LclTranslation, animLayer, FBXSDK_CURVENODE_COMPONENT_X); if (animCurve) { tx = true; findMinMaxTime(animCurve, &startTime, &stopTime, &frameRate); } animCurve = getCurve(fbxNode->LclTranslation, animLayer, FBXSDK_CURVENODE_COMPONENT_Y); if (animCurve) { ty = true; findMinMaxTime(animCurve, &startTime, &stopTime, &frameRate); } animCurve = getCurve(fbxNode->LclTranslation, animLayer, FBXSDK_CURVENODE_COMPONENT_Z); if (animCurve) { tz = true; findMinMaxTime(animCurve, &startTime, &stopTime, &frameRate); } animCurve = getCurve(fbxNode->LclRotation, animLayer, FBXSDK_CURVENODE_COMPONENT_X); if (animCurve) { rx = true; findMinMaxTime(animCurve, &startTime, &stopTime, &frameRate); } animCurve = getCurve(fbxNode->LclRotation, animLayer, FBXSDK_CURVENODE_COMPONENT_Y); if (animCurve) { ry = true; findMinMaxTime(animCurve, &startTime, &stopTime, &frameRate); } animCurve = getCurve(fbxNode->LclRotation, animLayer, FBXSDK_CURVENODE_COMPONENT_Z); if (animCurve) { rz = true; findMinMaxTime(animCurve, &startTime, &stopTime, &frameRate); } animCurve = getCurve(fbxNode->LclScaling, animLayer, FBXSDK_CURVENODE_COMPONENT_X); if (animCurve) { sx = true; findMinMaxTime(animCurve, &startTime, &stopTime, &frameRate); } animCurve = getCurve(fbxNode->LclScaling, animLayer, FBXSDK_CURVENODE_COMPONENT_Y); if (animCurve) { sy = true; findMinMaxTime(animCurve, &startTime, &stopTime, &frameRate); } animCurve = getCurve(fbxNode->LclScaling, animLayer, FBXSDK_CURVENODE_COMPONENT_Z); if (animCurve) { sz = true; findMinMaxTime(animCurve, &startTime, &stopTime, &frameRate); } if (!(sx || sy || sz || rx || ry || rz || tx || ty || tz)) return; // no animation channels assert(startTime != FLT_MAX); assert(stopTime >= 0.0f); // Determine which animation channels to create vector<unsigned int> channelAttribs; if (sx && sy && sz) { if (rx || ry || rz) { if (tx && ty && tz) { channelAttribs.push_back(Transform::ANIMATE_SCALE_ROTATE_TRANSLATE); } else { channelAttribs.push_back(Transform::ANIMATE_SCALE_ROTATE); if (tx) channelAttribs.push_back(Transform::ANIMATE_TRANSLATE_X); if (ty) channelAttribs.push_back(Transform::ANIMATE_TRANSLATE_Y); if (tz) channelAttribs.push_back(Transform::ANIMATE_TRANSLATE_Z); } } else { if (tx && ty && tz) { channelAttribs.push_back(Transform::ANIMATE_SCALE_TRANSLATE); } else { channelAttribs.push_back(Transform::ANIMATE_SCALE); if (tx) channelAttribs.push_back(Transform::ANIMATE_TRANSLATE_X); if (ty) channelAttribs.push_back(Transform::ANIMATE_TRANSLATE_Y); if (tz) channelAttribs.push_back(Transform::ANIMATE_TRANSLATE_Z); } } } else { if (rx || ry || rz) { if (tx && ty && tz) { channelAttribs.push_back(Transform::ANIMATE_ROTATE_TRANSLATE); } else { channelAttribs.push_back(Transform::ANIMATE_ROTATE); if (tx) channelAttribs.push_back(Transform::ANIMATE_TRANSLATE_X); if (ty) channelAttribs.push_back(Transform::ANIMATE_TRANSLATE_Y); if (tz) channelAttribs.push_back(Transform::ANIMATE_TRANSLATE_Z); } } else { if (tx && ty && tz) { channelAttribs.push_back(Transform::ANIMATE_TRANSLATE); } else { if (tx) channelAttribs.push_back(Transform::ANIMATE_TRANSLATE_X); if (ty) channelAttribs.push_back(Transform::ANIMATE_TRANSLATE_Y); if (tz) channelAttribs.push_back(Transform::ANIMATE_TRANSLATE_Z); } } if (sx) channelAttribs.push_back(Transform::ANIMATE_SCALE_X); if (sy) channelAttribs.push_back(Transform::ANIMATE_SCALE_Y); if (sz) channelAttribs.push_back(Transform::ANIMATE_SCALE_Z); } unsigned int channelCount = channelAttribs.size(); assert(channelCount > 0); // Allocate channel list const int channelStart = animation->getAnimationChannelCount(); for (unsigned int i = 0; i < channelCount; ++i) { AnimationChannel* channel = new AnimationChannel(); channel->setTargetId(name); channel->setInterpolation(AnimationChannel::LINEAR); channel->setTargetAttribute(channelAttribs[i]); animation->add(channel); } // Evaulate animation curve in increments of frameRate and populate channel data. FbxAMatrix fbxMatrix; Matrix matrix; double increment = 1000.0 / (double)frameRate; int frameCount = (int)ceil((double)(stopTime - startTime) / increment) + 1; // +1 because stop time is inclusive // If the animation for this node only has only 1 key frame and it is equal to the node's transform then ignore it. // This is a work around for a bug in the Blender FBX exporter. if (frameCount == 1 && fbxMatrix == fbxNode->EvaluateLocalTransform(0)) { return; } for (int frame = 0; frame < frameCount; ++frame) { double time = startTime + (frame * (double)increment); // Note: We used to clamp time to stop time, but FBX sdk does not always produce // and accurate stopTime (sometimes it is rounded down for some reason), so I'm // disabling this clamping for now as it seems more accurate under normal circumstances. //time = std::min(time, (double)stopTime); // Evalulate the animation at this time FbxTime kTime; kTime.SetMilliSeconds((FbxLongLong)time); fbxMatrix = fbxNode->EvaluateLocalTransform(kTime); copyMatrix(fbxMatrix, matrix); // Decompose the evalulated transformation matrix into separate // scale, rotation and translation. Vector3 scale; Quaternion rotation; Vector3 translation; matrix.decompose(&scale, &rotation, &translation); rotation.normalize(); // Append keyframe data to all channels for (unsigned int i = channelStart, channelEnd = channelStart + channelCount; i < channelEnd; ++i) { appendKeyFrame(fbxNode, animation->getAnimationChannel(i), (float)time, scale, rotation, translation); } } if (_groupAnimation != animation) { _gamePlayFile.addAnimation(animation); } }
void GPBFile::decomposeTransformAnimationChannel(Animation* animation, const AnimationChannel* channel) { const std::vector<float>& keyTimes = channel->getKeyTimes(); const std::vector<float>& keyValues = channel->getKeyValues(); const size_t keyTimesSize = keyTimes.size(); const size_t keyValuesSize = keyValues.size(); std::vector<float> scaleKeyValues; std::vector<float> rotateKeyValues; std::vector<float> translateKeyValues; scaleKeyValues.reserve(keyTimesSize * 3); rotateKeyValues.reserve(keyTimesSize * 4); translateKeyValues.reserve(keyTimesSize * 3); for (size_t kv = 0; kv < keyValuesSize; kv += 10) { scaleKeyValues.push_back(keyValues[kv]); scaleKeyValues.push_back(keyValues[kv+1]); scaleKeyValues.push_back(keyValues[kv+2]); rotateKeyValues.push_back(keyValues[kv+3]); rotateKeyValues.push_back(keyValues[kv+4]); rotateKeyValues.push_back(keyValues[kv+5]); rotateKeyValues.push_back(keyValues[kv+6]); translateKeyValues.push_back(keyValues[kv+7]); translateKeyValues.push_back(keyValues[kv+8]); translateKeyValues.push_back(keyValues[kv+9]); } // replace transform animation channel with translate, rotate and scale animation channels // Don't add the scale channel if all the key values are close to 1.0 size_t oneCount = (size_t)std::count_if(scaleKeyValues.begin(), scaleKeyValues.end(), isAlmostOne); if (scaleKeyValues.size() != oneCount) { AnimationChannel* scaleChannel = new AnimationChannel(); scaleChannel->setTargetId(channel->getTargetId()); scaleChannel->setKeyTimes(channel->getKeyTimes()); scaleChannel->setTangentsIn(channel->getTangentsIn()); scaleChannel->setTangentsOut(channel->getTangentsOut()); scaleChannel->setInterpolations(channel->getInterpolationTypes()); scaleChannel->setTargetAttribute(Transform::ANIMATE_SCALE); scaleChannel->setKeyValues(scaleKeyValues); scaleChannel->removeDuplicates(); animation->add(scaleChannel); } AnimationChannel* rotateChannel = new AnimationChannel(); rotateChannel->setTargetId(channel->getTargetId()); rotateChannel->setKeyTimes(channel->getKeyTimes()); rotateChannel->setTangentsIn(channel->getTangentsIn()); rotateChannel->setTangentsOut(channel->getTangentsOut()); rotateChannel->setInterpolations(channel->getInterpolationTypes()); rotateChannel->setTargetAttribute(Transform::ANIMATE_ROTATE); rotateChannel->setKeyValues(rotateKeyValues); rotateChannel->removeDuplicates(); animation->add(rotateChannel); AnimationChannel* translateChannel = new AnimationChannel(); translateChannel->setTargetId(channel->getTargetId()); translateChannel->setKeyTimes(channel->getKeyTimes()); translateChannel->setTangentsIn(channel->getTangentsIn()); translateChannel->setTangentsOut(channel->getTangentsOut()); translateChannel->setInterpolations(channel->getInterpolationTypes()); translateChannel->setTargetAttribute(Transform::ANIMATE_TRANSLATE); translateChannel->setKeyValues(translateKeyValues); translateChannel->removeDuplicates(); animation->add(translateChannel); }