root/OpenSceneGraph/trunk/src/osgPlugins/fbx/fbxRAnimation.cpp @ 13466

Revision 13466, 17.6 kB (checked in by robert, 12 hours ago)

From Jason Beverage, "It looks like the Callback header got accidentally removed from the CMakeLists.txt in the submission yesterday for the geometry instancing example."

  • Property svn:eol-style set to native
Line 
1#include <osg/MatrixTransform>
2
3#include <osgAnimation/Animation>
4#include <osgAnimation/BasicAnimationManager>
5#include <osgAnimation/Channel>
6#include <osgAnimation/Sampler>
7
8#if defined(_MSC_VER)
9    #pragma warning( disable : 4505 )
10    #pragma warning( default : 4996 )
11#endif
12#include <fbxsdk.h>
13#include "fbxReader.h"
14
15osg::Quat makeQuat(const FbxDouble3&, EFbxRotationOrder);
16
17osg::Quat makeQuat(const osg::Vec3& radians, EFbxRotationOrder fbxRotOrder)
18{
19    FbxDouble3 degrees(
20        osg::RadiansToDegrees(radians.x()),
21        osg::RadiansToDegrees(radians.y()),
22        osg::RadiansToDegrees(radians.z()));
23    return makeQuat(degrees, fbxRotOrder);
24}
25
26void readKeys(FbxAnimCurve* curveX, FbxAnimCurve* curveY, FbxAnimCurve* curveZ,
27              const FbxDouble3& defaultValue,
28              std::vector<osgAnimation::TemplateKeyframe<osg::Vec3> >& keyFrameCntr, float scalar = 1.0f)
29{
30    FbxAnimCurve* curves[3] = {curveX, curveY, curveZ};
31
32    typedef std::set<double> TimeSet;
33    typedef std::map<double, float> TimeFloatMap;
34    TimeSet times;
35    TimeFloatMap curveTimeMap[3];
36
37    for (int nCurve = 0; nCurve < 3; ++nCurve)
38    {
39        FbxAnimCurve* pCurve = curves[nCurve];
40
41        int nKeys = pCurve ? pCurve->KeyGetCount() : 0;
42
43        if (!nKeys)
44        {
45            times.insert(0.0);
46            curveTimeMap[nCurve][0.0] = defaultValue[nCurve] * scalar;
47        }
48
49        for (int i = 0; i < nKeys; ++i)
50        {
51            FbxAnimCurveKey key = pCurve->KeyGet(i);
52            double fTime = key.GetTime().GetSecondDouble();
53            times.insert(fTime);
54            curveTimeMap[nCurve][fTime] = static_cast<float>(key.GetValue()) * scalar;
55        }
56    }
57
58    for (TimeSet::iterator it = times.begin(); it != times.end(); ++it)
59    {
60        double fTime = *it;
61        osg::Vec3 val;
62        for (int i = 0; i < 3; ++i)
63        {
64            if (curveTimeMap[i].empty()) continue;
65
66            TimeFloatMap::iterator lb = curveTimeMap[i].lower_bound(fTime);
67            if (lb == curveTimeMap[i].end()) --lb;
68            val[i] = lb->second;
69        }
70        keyFrameCntr.push_back(osgAnimation::Vec3Keyframe(fTime, val));
71    }
72}
73
74void readKeys(FbxAnimCurve* curveX, FbxAnimCurve* curveY, FbxAnimCurve* curveZ,
75              const FbxDouble3& defaultValue,
76              std::vector<osgAnimation::Vec3CubicBezierKeyframe>& keyFrameCntr, float scalar = 1.0f)
77{
78    FbxAnimCurve* curves[3] = {curveX, curveY, curveZ};
79
80    typedef std::set<double> TimeSet;
81    typedef std::map<double, osgAnimation::FloatCubicBezier> TimeValueMap;
82    TimeSet times;
83    TimeValueMap curveTimeMap[3];
84
85    for (int nCurve = 0; nCurve < 3; ++nCurve)
86    {
87        FbxAnimCurve* pCurve = curves[nCurve];
88
89        int nKeys = pCurve ? pCurve->KeyGetCount() : 0;
90
91        if (!nKeys)
92        {
93            times.insert(0.0);
94            curveTimeMap[nCurve][0.0] = osgAnimation::FloatCubicBezier(defaultValue[nCurve] * scalar);
95        }
96
97        for (int i = 0; i < nKeys; ++i)
98        {
99            double fTime = pCurve->KeyGetTime(i).GetSecondDouble();
100            float val = pCurve->KeyGetValue(i);
101            times.insert(fTime);
102            FbxAnimCurveTangentInfo leftTangent = pCurve->KeyGetLeftDerivativeInfo(i);
103            FbxAnimCurveTangentInfo rightTangent = pCurve->KeyGetRightDerivativeInfo(i);
104
105            if (i > 0)
106            {
107                leftTangent.mDerivative *= fTime - pCurve->KeyGetTime(i - 1).GetSecondDouble();
108            }
109            if (i + 1 < pCurve->KeyGetCount())
110            {
111                rightTangent.mDerivative *= pCurve->KeyGetTime(i + 1).GetSecondDouble() - fTime;
112            }
113
114            osgAnimation::FloatCubicBezier key(
115                val * scalar,
116                (val - leftTangent.mDerivative / 3.0) * scalar,
117                (val + rightTangent.mDerivative / 3.0) * scalar);
118
119            curveTimeMap[nCurve][fTime] = key;
120        }
121    }
122
123    for (TimeSet::iterator it = times.begin(); it != times.end(); ++it)
124    {
125        double fTime = *it;
126        osg::Vec3 val, cpIn, cpOut;
127        for (int i = 0; i < 3; ++i)
128        {
129            if (curveTimeMap[i].empty()) continue;
130
131            TimeValueMap::iterator lb = curveTimeMap[i].lower_bound(fTime);
132            if (lb == curveTimeMap[i].end()) --lb;
133            val[i] = lb->second.getPosition();
134            cpIn[i] = lb->second.getControlPointIn();
135            cpOut[i] = lb->second.getControlPointOut();
136        }
137
138        keyFrameCntr.push_back(osgAnimation::Vec3CubicBezierKeyframe(fTime,
139            osgAnimation::Vec3CubicBezier(val, cpIn, cpOut)));
140    }
141}
142
143// osgAnimation requires control points to be in a weird order. This function
144// reorders them from the conventional order to osgAnimation order.
145template <typename T>
146void reorderControlPoints(osgAnimation::TemplateKeyframeContainer<osgAnimation::TemplateCubicBezier<T> >& vkfCont)
147{
148    if (vkfCont.size() <= 1)
149    {
150        if (vkfCont.size() == 1)
151        {
152            osgAnimation::TemplateCubicBezier<T> tcb = vkfCont.front().getValue();
153            T inCP = tcb.getControlPointIn();
154            tcb.setControlPointIn(tcb.getControlPointOut());
155            tcb.setControlPointOut(inCP);
156            vkfCont.front().setValue(tcb);
157        }
158        return;
159    }
160
161    osgAnimation::TemplateCubicBezier<T> first = vkfCont.front().getValue();
162
163    for (unsigned i = 0; i < vkfCont.size() - 1; ++i)
164    {
165        osgAnimation::TemplateCubicBezier<T> tcb = vkfCont[i].getValue();
166        tcb.setControlPointIn(tcb.getControlPointOut());
167        tcb.setControlPointOut(vkfCont[i + 1].getValue().getControlPointIn());
168        vkfCont[i].setValue(tcb);
169    }
170
171    osgAnimation::TemplateCubicBezier<T> last = vkfCont.back().getValue();
172    last.setControlPointIn(last.getControlPointOut());
173    last.setControlPointOut(first.getControlPointIn());
174    vkfCont.back().setValue(last);
175}
176
177osgAnimation::Channel* readFbxChannels(FbxAnimCurve* curveX, FbxAnimCurve* curveY,
178    FbxAnimCurve* curveZ,
179    const FbxDouble3& defaultValue,
180    const char* targetName, const char* channelName)
181{
182    if (!(curveX && curveX->KeyGetCount()) &&
183        !(curveY && curveY->KeyGetCount()) &&
184        !(curveZ && curveZ->KeyGetCount()))
185    {
186        return 0;
187    }
188
189    FbxAnimCurveDef::EInterpolationType interpolationType = FbxAnimCurveDef::eInterpolationConstant;
190    if (curveX && curveX->KeyGetCount()) interpolationType = curveX->KeyGetInterpolation(0);
191    else if (curveY && curveY->KeyGetCount()) interpolationType = curveY->KeyGetInterpolation(0);
192    else if (curveZ && curveZ->KeyGetCount()) interpolationType = curveZ->KeyGetInterpolation(0);
193
194    osgAnimation::Channel* pChannel = 0;
195
196    if (interpolationType == FbxAnimCurveDef::eInterpolationCubic)
197    {
198        osgAnimation::Vec3CubicBezierKeyframeContainer* pKeyFrameCntr = new osgAnimation::Vec3CubicBezierKeyframeContainer;
199        readKeys(curveX, curveY, curveZ, defaultValue, *pKeyFrameCntr);
200        reorderControlPoints(*pKeyFrameCntr);
201
202        osgAnimation::Vec3CubicBezierChannel* pCubicChannel = new osgAnimation::Vec3CubicBezierChannel;
203        pCubicChannel->getOrCreateSampler()->setKeyframeContainer(pKeyFrameCntr);
204        pChannel = pCubicChannel;
205    }
206    else
207    {
208        osgAnimation::Vec3KeyframeContainer* pKeyFrameCntr = new osgAnimation::Vec3KeyframeContainer;
209        readKeys(curveX, curveY, curveZ, defaultValue, *pKeyFrameCntr);
210
211        if (interpolationType == FbxAnimCurveDef::eInterpolationConstant)
212        {
213            osgAnimation::Vec3StepChannel* pStepChannel = new osgAnimation::Vec3StepChannel;
214            pStepChannel->getOrCreateSampler()->setKeyframeContainer(pKeyFrameCntr);
215            pChannel = pStepChannel;
216        }
217        else
218        {
219            osgAnimation::Vec3LinearChannel* pLinearChannel = new osgAnimation::Vec3LinearChannel;
220            pLinearChannel->getOrCreateSampler()->setKeyframeContainer(pKeyFrameCntr);
221            pChannel = pLinearChannel;
222        }
223    }
224
225    pChannel->setTargetName(targetName);
226    pChannel->setName(channelName);
227
228    return pChannel;
229}
230
231osgAnimation::Channel* readFbxChannels(
232    FbxPropertyT<FbxDouble3>& fbxProp, FbxAnimLayer* pAnimLayer,
233    const char* targetName, const char* channelName)
234{
235    if (!fbxProp.IsValid()) return 0;
236
237    return readFbxChannels(
238        fbxProp.GetCurve(pAnimLayer, "X"),
239        fbxProp.GetCurve(pAnimLayer, "Y"),
240        fbxProp.GetCurve(pAnimLayer, "Z"),
241        fbxProp.Get(),
242        targetName, channelName);
243}
244
245osgAnimation::Channel* readFbxChannelsQuat(
246    FbxAnimCurve* curveX, FbxAnimCurve* curveY, FbxAnimCurve* curveZ,
247    const FbxDouble3& defaultValue,
248    const char* targetName, EFbxRotationOrder rotOrder)
249{
250    if (!(curveX && curveX->KeyGetCount()) &&
251        !(curveY && curveY->KeyGetCount()) &&
252        !(curveZ && curveZ->KeyGetCount()))
253    {
254        return 0;
255    }
256
257    osgAnimation::QuatSphericalLinearChannel* pChannel = new osgAnimation::QuatSphericalLinearChannel;
258    pChannel->setTargetName(targetName);
259    pChannel->setName("quaternion");
260    typedef std::vector<osgAnimation::TemplateKeyframe<osg::Vec3> > KeyFrameCntr;
261    KeyFrameCntr eulerFrameCntr;
262    readKeys(curveX, curveY, curveZ, defaultValue, eulerFrameCntr, static_cast<float>(osg::PI / 180.0));
263
264    osgAnimation::QuatSphericalLinearSampler::KeyframeContainerType& quatFrameCntr =
265        *pChannel->getOrCreateSampler()->getOrCreateKeyframeContainer();
266    quatFrameCntr.reserve(eulerFrameCntr.size());
267
268    for (KeyFrameCntr::iterator it = eulerFrameCntr.begin(), end = eulerFrameCntr.end();
269        it != end; ++it)
270    {
271        const osg::Vec3& euler = it->getValue();
272        quatFrameCntr.push_back(osgAnimation::QuatKeyframe(
273            it->getTime(), makeQuat(euler, rotOrder)));
274    }
275
276    return pChannel;
277}
278
279osgAnimation::Animation* addChannels(
280    osgAnimation::Channel* pTranslationChannel,
281    osgAnimation::Channel* pRotationChannels[],
282    osgAnimation::Channel* pScaleChannel,
283    osg::ref_ptr<osgAnimation::AnimationManagerBase>& pAnimManager,
284    const char* pTakeName)
285{
286    if (pTranslationChannel ||
287        pRotationChannels[0] ||
288        pRotationChannels[1] ||
289        pRotationChannels[2] ||
290        pScaleChannel)
291    {
292        if (!pAnimManager) pAnimManager = new osgAnimation::BasicAnimationManager;
293
294        osgAnimation::Animation* pAnimation = 0;
295        const osgAnimation::AnimationList& anims = pAnimManager->getAnimationList();
296        for (size_t i = 0; i < anims.size(); ++i)
297        {
298            if (anims[i]->getName() == pTakeName)
299            {
300                pAnimation = anims[i].get();
301            }
302        }
303
304        if (!pAnimation)
305        {
306            pAnimation = new osgAnimation::Animation;
307            pAnimation->setName(pTakeName);
308            pAnimManager->registerAnimation(pAnimation);
309        }
310
311        if (pTranslationChannel) pAnimation->addChannel(pTranslationChannel);
312        if (pRotationChannels[0]) pAnimation->addChannel(pRotationChannels[0]);
313        if (pRotationChannels[1]) pAnimation->addChannel(pRotationChannels[1]);
314        if (pRotationChannels[2]) pAnimation->addChannel(pRotationChannels[2]);
315        if (pScaleChannel) pAnimation->addChannel(pScaleChannel);
316
317
318        return pAnimation;
319    }
320
321    return 0;
322}
323
324void readFbxRotationAnimation(osgAnimation::Channel* channels[3],
325    FbxNode* pNode,
326    FbxAnimLayer* pAnimLayer, const char* targetName)
327{
328    if (!pNode->LclRotation.IsValid())
329    {
330        return;
331    }
332
333    EFbxRotationOrder rotOrder = pNode->RotationOrder.IsValid() ? pNode->RotationOrder.Get() : eEulerXYZ;
334
335    if (pNode->QuaternionInterpolate.IsValid() && pNode->QuaternionInterpolate.Get())
336    {
337        channels[0] = readFbxChannelsQuat(
338            pNode->LclRotation.GetCurve(pAnimLayer, FBXSDK_CURVENODE_COMPONENT_X),
339            pNode->LclRotation.GetCurve(pAnimLayer, FBXSDK_CURVENODE_COMPONENT_Y),
340            pNode->LclRotation.GetCurve(pAnimLayer, FBXSDK_CURVENODE_COMPONENT_Z),
341            pNode->LclRotation.Get(),
342            targetName, rotOrder);
343    }
344    else
345    {
346        const char* curveNames[3] = {FBXSDK_CURVENODE_COMPONENT_X, FBXSDK_CURVENODE_COMPONENT_Y, FBXSDK_CURVENODE_COMPONENT_Z};
347
348        FbxDouble3 fbxPropValue = pNode->LclRotation.Get();
349        fbxPropValue[0] = osg::DegreesToRadians(fbxPropValue[0]);
350        fbxPropValue[1] = osg::DegreesToRadians(fbxPropValue[1]);
351        fbxPropValue[2] = osg::DegreesToRadians(fbxPropValue[2]);
352
353        for (int i = 0; i < 3; ++i)
354        {
355            FbxAnimCurve* curve = pNode->LclRotation.GetCurve(pAnimLayer, curveNames[i]);
356            if (!curve)
357            {
358                continue;
359            }
360
361            FbxAnimCurveDef::EInterpolationType interpolationType = FbxAnimCurveDef::eInterpolationConstant;
362            if (curve && curve->KeyGetCount()) interpolationType = curve->KeyGetInterpolation(0);
363
364            if (interpolationType == FbxAnimCurveDef::eInterpolationCubic)
365            {
366                osgAnimation::FloatCubicBezierKeyframeContainer* pKeyFrameCntr = new osgAnimation::FloatCubicBezierKeyframeContainer;
367
368                for (int j = 0; j < curve->KeyGetCount(); ++j)
369                {
370                    double fTime = curve->KeyGetTime(j).GetSecondDouble();
371                    float angle = curve->KeyGetValue(j);
372                    //FbxAnimCurveDef::EWeightedMode tangentWeightMode = curve->KeyGet(j).GetTangentWeightMode();
373
374                    FbxAnimCurveTangentInfo leftTangent = curve->KeyGetLeftDerivativeInfo(j);
375                    FbxAnimCurveTangentInfo rightTangent = curve->KeyGetRightDerivativeInfo(j);
376                    if (j > 0)
377                    {
378                        leftTangent.mDerivative *= fTime - curve->KeyGetTime(j - 1).GetSecondDouble();
379                    }
380                    if (j + 1 < curve->KeyGetCount())
381                    {
382                        rightTangent.mDerivative *= curve->KeyGetTime(j + 1).GetSecondDouble() - fTime;
383                    }
384                    osgAnimation::FloatCubicBezier key(
385                        osg::DegreesToRadians(angle),
386                        osg::DegreesToRadians(angle - leftTangent.mDerivative / 3.0),
387                        osg::DegreesToRadians(angle + rightTangent.mDerivative / 3.0));
388
389                    pKeyFrameCntr->push_back(osgAnimation::FloatCubicBezierKeyframe(
390                        fTime,
391                        key));
392                }
393
394                reorderControlPoints(*pKeyFrameCntr);
395
396                osgAnimation::FloatCubicBezierChannel* pCubicChannel = new osgAnimation::FloatCubicBezierChannel;
397                pCubicChannel->getOrCreateSampler()->setKeyframeContainer(pKeyFrameCntr);
398                channels[i] = pCubicChannel;
399            }
400            else
401            {
402                osgAnimation::FloatKeyframeContainer* keys = new osgAnimation::FloatKeyframeContainer;
403
404                for (int j = 0; j < curve->KeyGetCount(); ++j)
405                {
406                    FbxAnimCurveKey key = curve->KeyGet(j);
407                    keys->push_back(osgAnimation::FloatKeyframe(
408                        key.GetTime().GetSecondDouble(),
409                        static_cast<float>(osg::DegreesToRadians(key.GetValue()))));
410                }
411
412                if (interpolationType == FbxAnimCurveDef::eInterpolationConstant)
413                {
414                    osgAnimation::FloatStepChannel* pStepChannel = new osgAnimation::FloatStepChannel();
415                    pStepChannel->getOrCreateSampler()->setKeyframeContainer(keys);
416                    channels[i] = pStepChannel;
417                }
418                else
419                {
420                    osgAnimation::FloatLinearChannel* pLinearChannel = new osgAnimation::FloatLinearChannel();
421                    pLinearChannel->getOrCreateSampler()->setKeyframeContainer(keys);
422                    channels[i] = pLinearChannel;
423                }
424            }
425
426            channels[i]->setTargetName(targetName);
427            channels[i]->setName(std::string("rotate") + curveNames[i]);
428        }
429    }
430}
431
432osgAnimation::Animation* readFbxAnimation(FbxNode* pNode,
433    FbxAnimLayer* pAnimLayer, const char* pTakeName, const char* targetName,
434    osg::ref_ptr<osgAnimation::AnimationManagerBase>& pAnimManager)
435{
436    osgAnimation::Channel* pTranslationChannel = 0;
437    osgAnimation::Channel* pRotationChannels[3] = {0};
438    readFbxRotationAnimation(pRotationChannels, pNode, pAnimLayer, targetName);
439
440
441    if (pNode->LclTranslation.IsValid())
442    {
443        pTranslationChannel = readFbxChannels(
444            pNode->LclTranslation.GetCurve(pAnimLayer, FBXSDK_CURVENODE_COMPONENT_X),
445            pNode->LclTranslation.GetCurve(pAnimLayer, FBXSDK_CURVENODE_COMPONENT_Y),
446            pNode->LclTranslation.GetCurve(pAnimLayer, FBXSDK_CURVENODE_COMPONENT_Z),
447            pNode->LclTranslation.Get(),
448            targetName, "translate");
449    }
450
451    osgAnimation::Channel* pScaleChannel = readFbxChannels(
452        pNode->LclScaling, pAnimLayer, targetName, "scale");
453
454    return addChannels(pTranslationChannel, pRotationChannels, pScaleChannel, pAnimManager, pTakeName);
455}
456
457std::string OsgFbxReader::readFbxAnimation(FbxNode* pNode, const char* targetName)
458{
459    std::string result;
460    for (int i = 0; i < fbxScene.GetSrcObjectCount<FbxAnimStack>(); ++i)
461    {
462        FbxAnimStack* pAnimStack = FbxCast<FbxAnimStack>(fbxScene.GetSrcObject<FbxAnimStack>(i));
463
464        int nbAnimLayers = pAnimStack->GetMemberCount<FbxAnimLayer>();
465
466        const char* pTakeName = pAnimStack->GetName();
467
468        if (!pTakeName || !*pTakeName)
469            continue;
470
471        for (int j = 0; j < nbAnimLayers; j++)
472        {
473            FbxAnimLayer* pAnimLayer = pAnimStack->GetMember<FbxAnimLayer>(j);
474            osgAnimation::Animation* pAnimation = ::readFbxAnimation(pNode, pAnimLayer, pTakeName, targetName, pAnimationManager);
475            if (pAnimation)
476            {
477                result = targetName;
478            }
479        }
480    }
481    return result;
482}
Note: See TracBrowser for help on using the browser.