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

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

Improved widget/VolumeSettings updates to use new Property.ModifiedCount? to make sure updates are only done when required.

  • 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.