Added support for Euler angles and step/linear/cubic-bezier interpolation.

This commit is contained in:
Michael PLATINGS
2010-06-08 17:32:36 +00:00
parent b81b167131
commit 82ea9597e5
8 changed files with 483 additions and 187 deletions

View File

@@ -72,6 +72,109 @@ void readKeys(KFbxAnimCurve* curveX, KFbxAnimCurve* curveY, KFbxAnimCurve* curve
}
}
void readKeys(KFbxAnimCurve* curveX, KFbxAnimCurve* curveY, KFbxAnimCurve* curveZ,
const fbxDouble3& defaultValue,
std::vector<osgAnimation::Vec3CubicBezierKeyframe>& keyFrameCntr, float scalar = 1.0f)
{
KFbxAnimCurve* curves[3] = {curveX, curveY, curveZ};
typedef std::set<double> TimeSet;
typedef std::map<double, osgAnimation::FloatCubicBezier> TimeValueMap;
TimeSet times;
TimeValueMap curveTimeMap[3];
for (int nCurve = 0; nCurve < 3; ++nCurve)
{
KFbxAnimCurve* pCurve = curves[nCurve];
int nKeys = pCurve ? pCurve->KeyGetCount() : 0;
if (!nKeys)
{
times.insert(0.0);
curveTimeMap[nCurve][0.0] = osgAnimation::FloatCubicBezier(defaultValue[nCurve] * scalar);
}
for (int i = 0; i < nKeys; ++i)
{
double fTime = pCurve->KeyGetTime(i).GetSecondDouble();
float val = pCurve->KeyGetValue(i);
times.insert(fTime);
KFCurveTangeantInfo leftTangent = pCurve->KeyGetLeftDerivativeInfo(i);
KFCurveTangeantInfo rightTangent = pCurve->KeyGetRightDerivativeInfo(i);
if (i > 0)
{
leftTangent.mDerivative *= fTime - pCurve->KeyGetTime(i - 1).GetSecondDouble();
}
if (i + 1 < pCurve->KeyGetCount())
{
rightTangent.mDerivative *= pCurve->KeyGetTime(i + 1).GetSecondDouble() - fTime;
}
osgAnimation::FloatCubicBezier key(
val * scalar,
(val + leftTangent.mDerivative / 3.0) * scalar,
(val + rightTangent.mDerivative / 3.0) * scalar);
curveTimeMap[nCurve][fTime] = key;
}
}
for (TimeSet::iterator it = times.begin(); it != times.end(); ++it)
{
double fTime = *it;
osg::Vec3 val, cpIn, cpOut;
for (int i = 0; i < 3; ++i)
{
if (curveTimeMap[i].empty()) continue;
TimeValueMap::iterator lb = curveTimeMap[i].lower_bound(fTime);
if (lb == curveTimeMap[i].end()) --lb;
val[i] = lb->second.getPosition();
cpIn[i] = lb->second.getControlPointIn();
cpOut[i] = lb->second.getControlPointOut();
}
keyFrameCntr.push_back(osgAnimation::Vec3CubicBezierKeyframe(fTime,
osgAnimation::Vec3CubicBezier(val, cpIn, cpOut)));
}
}
// osgAnimation requires control points to be in a weird order. This function
// reorders them from the conventional order to osgAnimation order.
template <typename T>
void reorderControlPoints(osgAnimation::TemplateKeyframeContainer<osgAnimation::TemplateCubicBezier<T> >& vkfCont)
{
if (vkfCont.size() <= 1)
{
if (vkfCont.size() == 1)
{
osgAnimation::TemplateCubicBezier<T> tcb = vkfCont.front().getValue();
T inCP = tcb.getControlPointIn();
tcb.setControlPointIn(tcb.getControlPointOut());
tcb.setControlPointOut(inCP);
vkfCont.front().setValue(tcb);
}
return;
}
osgAnimation::TemplateCubicBezier<T> first = vkfCont.front().getValue();
for (unsigned i = 0; i < vkfCont.size() - 1; ++i)
{
osgAnimation::TemplateCubicBezier<T> tcb = vkfCont[i].getValue();
tcb.setControlPointIn(tcb.getControlPointOut());
tcb.setControlPointOut(vkfCont[i + 1].getValue().getControlPointIn());
vkfCont[i].setValue(tcb);
}
osgAnimation::TemplateCubicBezier<T> last = vkfCont.back().getValue();
last.setControlPointIn(last.getControlPointOut());
last.setControlPointOut(first.getControlPointIn());
vkfCont.back().setValue(last);
}
osgAnimation::Channel* readFbxChannels(KFbxAnimCurve* curveX, KFbxAnimCurve* curveY,
KFbxAnimCurve* curveZ,
const fbxDouble3& defaultValue,
@@ -84,13 +187,44 @@ osgAnimation::Channel* readFbxChannels(KFbxAnimCurve* curveX, KFbxAnimCurve* cur
return 0;
}
osgAnimation::Vec3LinearChannel* pChannel = new osgAnimation::Vec3LinearChannel;
osgAnimation::Vec3KeyframeContainer* pKeyFrameCntr =
pChannel->getOrCreateSampler()->getOrCreateKeyframeContainer();
KFbxAnimCurveDef::EInterpolationType interpolationType = KFbxAnimCurveDef::eINTERPOLATION_CONSTANT;
if (curveX && curveX->KeyGetCount()) interpolationType = curveX->KeyGetInterpolation(0);
else if (curveY && curveY->KeyGetCount()) interpolationType = curveY->KeyGetInterpolation(0);
else if (curveZ && curveZ->KeyGetCount()) interpolationType = curveZ->KeyGetInterpolation(0);
osgAnimation::Channel* pChannel = 0;
if (interpolationType == KFbxAnimCurveDef::eINTERPOLATION_CUBIC)
{
osgAnimation::Vec3CubicBezierKeyframeContainer* pKeyFrameCntr = new osgAnimation::Vec3CubicBezierKeyframeContainer;
readKeys(curveX, curveY, curveZ, defaultValue, *pKeyFrameCntr);
reorderControlPoints(*pKeyFrameCntr);
osgAnimation::Vec3CubicBezierChannel* pCubicChannel = new osgAnimation::Vec3CubicBezierChannel;
pCubicChannel->getOrCreateSampler()->setKeyframeContainer(pKeyFrameCntr);
pChannel = pCubicChannel;
}
else
{
osgAnimation::Vec3KeyframeContainer* pKeyFrameCntr = new osgAnimation::Vec3KeyframeContainer;
readKeys(curveX, curveY, curveZ, defaultValue, *pKeyFrameCntr);
if (interpolationType == KFbxAnimCurveDef::eINTERPOLATION_CONSTANT)
{
osgAnimation::Vec3StepChannel* pStepChannel = new osgAnimation::Vec3StepChannel;
pStepChannel->getOrCreateSampler()->setKeyframeContainer(pKeyFrameCntr);
pChannel = pStepChannel;
}
else
{
osgAnimation::Vec3LinearChannel* pLinearChannel = new osgAnimation::Vec3LinearChannel;
pLinearChannel->getOrCreateSampler()->setKeyframeContainer(pKeyFrameCntr);
pChannel = pLinearChannel;
}
}
pChannel->setTargetName(targetName);
pChannel->setName(channelName);
readKeys(curveX, curveY, curveZ, defaultValue, *pKeyFrameCntr);
return pChannel;
}
@@ -145,13 +279,15 @@ osgAnimation::Channel* readFbxChannelsQuat(
osgAnimation::Animation* addChannels(
osgAnimation::Channel* pTranslationChannel,
osgAnimation::Channel* pRotationChannel,
osgAnimation::Channel* pRotationChannels[],
osgAnimation::Channel* pScaleChannel,
osg::ref_ptr<osgAnimation::AnimationManagerBase>& pAnimManager,
const char* pTakeName)
{
if (pTranslationChannel ||
pRotationChannel ||
pRotationChannels[0] ||
pRotationChannels[1] ||
pRotationChannels[2] ||
pScaleChannel)
{
if (!pAnimManager) pAnimManager = new osgAnimation::BasicAnimationManager;
@@ -174,7 +310,9 @@ osgAnimation::Animation* addChannels(
}
if (pTranslationChannel) pAnimation->addChannel(pTranslationChannel);
if (pRotationChannel) pAnimation->addChannel(pRotationChannel);
if (pRotationChannels[0]) pAnimation->addChannel(pRotationChannels[0]);
if (pRotationChannels[1]) pAnimation->addChannel(pRotationChannels[1]);
if (pRotationChannels[2]) pAnimation->addChannel(pRotationChannels[2]);
if (pScaleChannel) pAnimation->addChannel(pScaleChannel);
@@ -184,26 +322,122 @@ osgAnimation::Animation* addChannels(
return 0;
}
osgAnimation::Animation* readFbxAnimation(KFbxNode* pNode,
KFbxAnimLayer* pAnimLayer, const char* pTakeName, const char* targetName,
osg::ref_ptr<osgAnimation::AnimationManagerBase>& pAnimManager)
void readFbxRotationAnimation(osgAnimation::Channel* channels[3],
KFbxNode* pNode,
KFbxAnimLayer* pAnimLayer, const char* targetName)
{
if (!pNode->LclRotation.IsValid())
{
return;
}
ERotationOrder rotOrder = pNode->RotationOrder.IsValid() ? pNode->RotationOrder.Get() : eEULER_XYZ;
osgAnimation::Channel* pTranslationChannel = 0;
osgAnimation::Channel* pRotationChannel = 0;
if (pNode->LclRotation.IsValid())
if (pNode->QuaternionInterpolate.IsValid() && pNode->QuaternionInterpolate.Get())
{
fbxDouble3 fbxBaseValue = pNode->LclRotation.Get();
pRotationChannel = readFbxChannelsQuat(
channels[0] = readFbxChannelsQuat(
pNode->LclRotation.GetCurve<KFbxAnimCurve>(pAnimLayer, KFCURVENODE_R_X),
pNode->LclRotation.GetCurve<KFbxAnimCurve>(pAnimLayer, KFCURVENODE_R_Y),
pNode->LclRotation.GetCurve<KFbxAnimCurve>(pAnimLayer, KFCURVENODE_R_Z),
pNode->LclRotation.Get(),
targetName, rotOrder);
}
else
{
char* curveNames[3] = {KFCURVENODE_R_X, KFCURVENODE_R_Y, KFCURVENODE_R_Z};
fbxDouble3 fbxPropValue = pNode->LclRotation.Get();
fbxPropValue[0] = osg::DegreesToRadians(fbxPropValue[0]);
fbxPropValue[1] = osg::DegreesToRadians(fbxPropValue[1]);
fbxPropValue[2] = osg::DegreesToRadians(fbxPropValue[2]);
for (int i = 0; i < 3; ++i)
{
KFbxAnimCurve* curve = pNode->LclRotation.GetCurve<KFbxAnimCurve>(pAnimLayer, curveNames[i]);
if (!curve)
{
continue;
}
KFbxAnimCurveDef::EInterpolationType interpolationType = KFbxAnimCurveDef::eINTERPOLATION_CONSTANT;
if (curve && curve->KeyGetCount()) interpolationType = curve->KeyGetInterpolation(0);
if (interpolationType == KFbxAnimCurveDef::eINTERPOLATION_CUBIC)
{
osgAnimation::FloatCubicBezierKeyframeContainer* pKeyFrameCntr = new osgAnimation::FloatCubicBezierKeyframeContainer;
for (int j = 0; j < curve->KeyGetCount(); ++j)
{
double fTime = curve->KeyGetTime(j).GetSecondDouble();
float angle = curve->KeyGetValue(j);
//KFbxAnimCurveDef::EWeightedMode tangentWeightMode = curve->KeyGet(j).GetTangentWeightMode();
KFCurveTangeantInfo leftTangent = curve->KeyGetLeftDerivativeInfo(j);
KFCurveTangeantInfo rightTangent = curve->KeyGetRightDerivativeInfo(j);
if (j > 0)
{
leftTangent.mDerivative *= fTime - curve->KeyGetTime(j - 1).GetSecondDouble();
}
if (j + 1 < curve->KeyGetCount())
{
rightTangent.mDerivative *= curve->KeyGetTime(j + 1).GetSecondDouble() - fTime;
}
osgAnimation::FloatCubicBezier key(
osg::DegreesToRadians(angle),
osg::DegreesToRadians(angle + leftTangent.mDerivative / 3.0),
osg::DegreesToRadians(angle - rightTangent.mDerivative / 3.0));
pKeyFrameCntr->push_back(osgAnimation::FloatCubicBezierKeyframe(
fTime,
key));
}
reorderControlPoints(*pKeyFrameCntr);
osgAnimation::FloatCubicBezierChannel* pCubicChannel = new osgAnimation::FloatCubicBezierChannel;
pCubicChannel->getOrCreateSampler()->setKeyframeContainer(pKeyFrameCntr);
channels[i] = pCubicChannel;
}
else
{
osgAnimation::FloatKeyframeContainer* keys = new osgAnimation::FloatKeyframeContainer;
for (int j = 0; j < curve->KeyGetCount(); ++j)
{
KFbxAnimCurveKey key = curve->KeyGet(j);
keys->push_back(osgAnimation::FloatKeyframe(
key.GetTime().GetSecondDouble(),
static_cast<float>(osg::DegreesToRadians(key.GetValue()))));
}
if (interpolationType == KFbxAnimCurveDef::eINTERPOLATION_CONSTANT)
{
osgAnimation::FloatStepChannel* pStepChannel = new osgAnimation::FloatStepChannel();
pStepChannel->getOrCreateSampler()->setKeyframeContainer(keys);
channels[i] = pStepChannel;
}
else
{
osgAnimation::FloatLinearChannel* pLinearChannel = new osgAnimation::FloatLinearChannel();
pLinearChannel->getOrCreateSampler()->setKeyframeContainer(keys);
channels[i] = pLinearChannel;
}
}
channels[i]->setTargetName(targetName);
channels[i]->setName(std::string("rotate") + curveNames[i]);
}
}
}
osgAnimation::Animation* readFbxAnimation(KFbxNode* pNode,
KFbxAnimLayer* pAnimLayer, const char* pTakeName, const char* targetName,
osg::ref_ptr<osgAnimation::AnimationManagerBase>& pAnimManager)
{
osgAnimation::Channel* pTranslationChannel = 0;
osgAnimation::Channel* pRotationChannels[3] = {0};
readFbxRotationAnimation(pRotationChannels, pNode, pAnimLayer, targetName);
if (pNode->LclTranslation.IsValid())
{
@@ -218,7 +452,7 @@ osgAnimation::Animation* readFbxAnimation(KFbxNode* pNode,
osgAnimation::Channel* pScaleChannel = readFbxChannels(
pNode->LclScaling, pAnimLayer, targetName, "scale");
return addChannels(pTranslationChannel, pRotationChannel, pScaleChannel, pAnimManager, pTakeName);
return addChannels(pTranslationChannel, pRotationChannels, pScaleChannel, pAnimManager, pTakeName);
}
std::string OsgFbxReader::readFbxAnimation(KFbxNode* pNode, const char* targetName)
@@ -239,7 +473,7 @@ std::string OsgFbxReader::readFbxAnimation(KFbxNode* pNode, const char* targetNa
{
KFbxAnimLayer* pAnimLayer = pAnimStack->GetMember(FBX_TYPE(KFbxAnimLayer), j);
if (osgAnimation::Animation* pAnimation = ::readFbxAnimation(
if (osgAnimation::Animation* pAnimation = ::readFbxAnimation(
pNode, pAnimLayer, pTakeName, targetName, pAnimationManager))
{
result = targetName;