root/OpenSceneGraph/trunk/src/osgPlugins/fbx/fbxRNode.cpp @ 12583

Revision 12583, 20.6 kB (checked in by robert, 3 years ago)

Conveted tabs to four spaces and added a return to end of file

  • Property svn:eol-style set to native
Line 
1#include <cassert>
2#include <memory>
3#include <sstream>
4
5#include <osg/io_utils>
6#include <osg/Notify>
7#include <osg/MatrixTransform>
8#include <osg/Material>
9#include <osg/Texture2D>
10
11#include <osgDB/FileNameUtils>
12#include <osgDB/ReadFile>
13
14#include <osgAnimation/AnimationManagerBase>
15#include <osgAnimation/Bone>
16#include <osgAnimation/Skeleton>
17#include <osgAnimation/StackedMatrixElement>
18#include <osgAnimation/StackedQuaternionElement>
19#include <osgAnimation/StackedRotateAxisElement>
20#include <osgAnimation/StackedScaleElement>
21#include <osgAnimation/StackedTranslateElement>
22#include <osgAnimation/UpdateBone>
23
24#if defined(_MSC_VER)
25    #pragma warning( disable : 4505 )
26    #pragma warning( default : 4996 )
27#endif
28#include <fbxsdk.h>
29
30#include "fbxReader.h"
31
32bool isAnimated(KFbxProperty& prop, KFbxScene& fbxScene)
33{
34    for (int i = 0; i < fbxScene.GetSrcObjectCount(FBX_TYPE(KFbxAnimStack)); ++i)
35    {
36        KFbxAnimStack* pAnimStack = KFbxCast<KFbxAnimStack>(fbxScene.GetSrcObject(FBX_TYPE(KFbxAnimStack), i));
37
38        const int nbAnimLayers = pAnimStack->GetMemberCount(FBX_TYPE(KFbxAnimLayer));
39        for (int j = 0; j < nbAnimLayers; j++)
40        {
41            KFbxAnimLayer* pAnimLayer = pAnimStack->GetMember(FBX_TYPE(KFbxAnimLayer), j);
42            if (prop.GetCurveNode(pAnimLayer, false))
43            {
44                return true;
45            }
46        }
47    }
48    return false;
49}
50
51bool isAnimated(KFbxProperty& prop, const char* channel, KFbxScene& fbxScene)
52{
53    for (int i = 0; i < fbxScene.GetSrcObjectCount(FBX_TYPE(KFbxAnimStack)); ++i)
54    {
55        KFbxAnimStack* pAnimStack = KFbxCast<KFbxAnimStack>(fbxScene.GetSrcObject(FBX_TYPE(KFbxAnimStack), i));
56
57        const int nbAnimLayers = pAnimStack->GetMemberCount(FBX_TYPE(KFbxAnimLayer));
58        for (int j = 0; j < nbAnimLayers; j++)
59        {
60            KFbxAnimLayer* pAnimLayer = pAnimStack->GetMember(FBX_TYPE(KFbxAnimLayer), j);
61            if (prop.GetCurve<KFbxAnimCurve>(pAnimLayer, channel, false))
62            {
63                return true;
64            }
65        }
66    }
67    return false;
68}
69
70osg::Quat makeQuat(const fbxDouble3& degrees, ERotationOrder fbxRotOrder)
71{
72    double radiansX = osg::DegreesToRadians(degrees[0]);
73    double radiansY = osg::DegreesToRadians(degrees[1]);
74    double radiansZ = osg::DegreesToRadians(degrees[2]);
75
76    switch (fbxRotOrder)
77    {
78    case eEULER_XYZ:
79        return osg::Quat(
80            radiansX, osg::Vec3d(1,0,0),
81            radiansY, osg::Vec3d(0,1,0),
82            radiansZ, osg::Vec3d(0,0,1));
83    case eEULER_XZY:
84        return osg::Quat(
85            radiansX, osg::Vec3d(1,0,0),
86            radiansZ, osg::Vec3d(0,0,1),
87            radiansY, osg::Vec3d(0,1,0));
88    case eEULER_YZX:
89        return osg::Quat(
90            radiansY, osg::Vec3d(0,1,0),
91            radiansZ, osg::Vec3d(0,0,1),
92            radiansX, osg::Vec3d(1,0,0));
93    case eEULER_YXZ:
94        return osg::Quat(
95            radiansY, osg::Vec3d(0,1,0),
96            radiansX, osg::Vec3d(1,0,0),
97            radiansZ, osg::Vec3d(0,0,1));
98    case eEULER_ZXY:
99        return osg::Quat(
100            radiansZ, osg::Vec3d(0,0,1),
101            radiansX, osg::Vec3d(1,0,0),
102            radiansY, osg::Vec3d(0,1,0));
103    case eEULER_ZYX:
104        return osg::Quat(
105            radiansZ, osg::Vec3d(0,0,1),
106            radiansY, osg::Vec3d(0,1,0),
107            radiansX, osg::Vec3d(1,0,0));
108    case eSPHERIC_XYZ:
109        {
110            //I don't know what eSPHERIC_XYZ means, so this is a complete guess.
111            osg::Quat quat;
112            quat.makeRotate(osg::Vec3d(1.0, 0.0, 0.0), osg::Vec3d(degrees[0], degrees[1], degrees[2]));
113            return quat;
114        }
115    default:
116        OSG_WARN << "Invalid FBX rotation mode." << std::endl;
117        return osg::Quat();
118    }
119}
120
121void makeLocalMatrix(const KFbxNode* pNode, osg::Matrix& m)
122{
123    /*From http://area.autodesk.com/forum/autodesk-fbx/fbx-sdk/the-makeup-of-the-local-matrix-of-an-kfbxnode/
124
125    Local Matrix = LclTranslation * RotationOffset * RotationPivot *
126      PreRotation * LclRotation * PostRotation * RotationPivotInverse *
127      ScalingOffset * ScalingPivot * LclScaling * ScalingPivotInverse
128
129    LocalTranslation : translate (xform -query -translation)
130    RotationOffset: translation compensates for the change in the rotate pivot point (xform -q -rotateTranslation)
131    RotationPivot: current rotate pivot position (xform -q -rotatePivot)
132    PreRotation : joint orientation(pre rotation)
133    LocalRotation: rotate transform (xform -q -rotation & xform -q -rotateOrder)
134    PostRotation : rotate axis (xform -q -rotateAxis)
135    RotationPivotInverse: inverse of RotationPivot
136    ScalingOffset: translation compensates for the change in the scale pivot point (xform -q -scaleTranslation)
137    ScalingPivot: current scale pivot position (xform -q -scalePivot)
138    LocalScaling: scale transform (xform -q -scale)
139    ScalingPivotInverse: inverse of ScalingPivot
140    */
141
142    // When this flag is set to false, the RotationOrder, the Pre/Post rotation
143    // values and the rotation limits should be ignored.
144    bool rotationActive = pNode->RotationActive.Get();
145
146    ERotationOrder fbxRotOrder = rotationActive ? pNode->RotationOrder.Get() : eEULER_XYZ;
147
148    fbxDouble3 fbxLclPos = pNode->LclTranslation.Get();
149    fbxDouble3 fbxRotOff = pNode->RotationOffset.Get();
150    fbxDouble3 fbxRotPiv = pNode->RotationPivot.Get();
151    fbxDouble3 fbxPreRot = pNode->PreRotation.Get();
152    fbxDouble3 fbxLclRot = pNode->LclRotation.Get();
153    fbxDouble3 fbxPostRot = pNode->PostRotation.Get();
154    fbxDouble3 fbxSclOff = pNode->ScalingOffset.Get();
155    fbxDouble3 fbxSclPiv = pNode->ScalingPivot.Get();
156    fbxDouble3 fbxLclScl = pNode->LclScaling.Get();
157
158    m.makeTranslate(osg::Vec3d(
159        fbxLclPos[0] + fbxRotOff[0] + fbxRotPiv[0],
160        fbxLclPos[1] + fbxRotOff[1] + fbxRotPiv[1],
161        fbxLclPos[2] + fbxRotOff[2] + fbxRotPiv[2]));
162    if (rotationActive)
163    {
164        m.preMultRotate(
165            makeQuat(fbxPostRot, fbxRotOrder) *
166            makeQuat(fbxLclRot, fbxRotOrder) *
167            makeQuat(fbxPreRot, fbxRotOrder));
168    }
169    else
170    {
171        m.preMultRotate(makeQuat(fbxLclRot, fbxRotOrder));
172    }
173    m.preMultTranslate(osg::Vec3d(
174        fbxSclOff[0] + fbxSclPiv[0] - fbxRotPiv[0],
175        fbxSclOff[1] + fbxSclPiv[1] - fbxRotPiv[1],
176        fbxSclOff[2] + fbxSclPiv[2] - fbxRotPiv[2]));
177    m.preMultScale(osg::Vec3d(fbxLclScl[0], fbxLclScl[1], fbxLclScl[2]));
178    m.preMultTranslate(osg::Vec3d(
179        -fbxSclPiv[0],
180        -fbxSclPiv[1],
181        -fbxSclPiv[2]));
182}
183
184void readTranslationElement(KFbxTypedProperty<fbxDouble3>& prop,
185                            osgAnimation::UpdateMatrixTransform* pUpdate,
186                            osg::Matrix& staticTransform,
187                            KFbxScene& fbxScene)
188{
189    fbxDouble3 fbxPropValue = prop.Get();
190    osg::Vec3d val(
191        fbxPropValue[0],
192        fbxPropValue[1],
193        fbxPropValue[2]);
194
195    if (isAnimated(prop, fbxScene))
196    {
197        if (!staticTransform.isIdentity())
198        {
199            pUpdate->getStackedTransforms().push_back(new osgAnimation::StackedMatrixElement(staticTransform));
200            staticTransform.makeIdentity();
201        }
202        pUpdate->getStackedTransforms().push_back(new osgAnimation::StackedTranslateElement("translate", val));
203    }
204    else
205    {
206        staticTransform.preMultTranslate(val);
207    }
208}
209
210void getRotationOrder(ERotationOrder fbxRotOrder, int order[/*3*/])
211{
212    switch (fbxRotOrder)
213    {
214    case eEULER_XZY:
215        order[0] = 0; order[1] = 2; order[2] = 1;
216        break;
217    case eEULER_YZX:
218        order[0] = 1; order[1] = 2; order[2] = 0;
219        break;
220    case eEULER_YXZ:
221        order[0] = 1; order[1] = 0; order[2] = 2;
222        break;
223    case eEULER_ZXY:
224        order[0] = 2; order[1] = 0; order[2] = 1;
225        break;
226    case eEULER_ZYX:
227        order[0] = 2; order[1] = 1; order[2] = 0;
228        break;
229    default:
230        order[0] = 0; order[1] = 1; order[2] = 2;
231    }
232}
233
234void readRotationElement(KFbxTypedProperty<fbxDouble3>& prop,
235                         ERotationOrder fbxRotOrder,
236                         bool quatInterpolate,
237                         osgAnimation::UpdateMatrixTransform* pUpdate,
238                         osg::Matrix& staticTransform,
239                         KFbxScene& fbxScene)
240{
241    if (isAnimated(prop, fbxScene))
242    {
243        if (quatInterpolate)
244        {
245            if (!staticTransform.isIdentity())
246            {
247                pUpdate->getStackedTransforms().push_back(
248                    new osgAnimation::StackedMatrixElement(staticTransform));
249                staticTransform.makeIdentity();
250            }
251            pUpdate->getStackedTransforms().push_back(new osgAnimation::StackedQuaternionElement(
252                "quaternion", makeQuat(prop.Get(), fbxRotOrder)));
253        }
254        else
255        {
256            const char* curveNames[3] = {KFCURVENODE_R_X, KFCURVENODE_R_Y, KFCURVENODE_R_Z};
257            osg::Vec3 axes[3] = {osg::Vec3(1,0,0), osg::Vec3(0,1,0), osg::Vec3(0,0,1)};
258
259            fbxDouble3 fbxPropValue = prop.Get();
260            fbxPropValue[0] = osg::DegreesToRadians(fbxPropValue[0]);
261            fbxPropValue[1] = osg::DegreesToRadians(fbxPropValue[1]);
262            fbxPropValue[2] = osg::DegreesToRadians(fbxPropValue[2]);
263
264            int order[3] = {0, 1, 2};
265            getRotationOrder(fbxRotOrder, order);
266
267            for (int i = 0; i < 3; ++i)
268            {
269                int j = order[2-i];
270                if (isAnimated(prop, curveNames[j], fbxScene))
271                {
272                    if (!staticTransform.isIdentity())
273                    {
274                        pUpdate->getStackedTransforms().push_back(new osgAnimation::StackedMatrixElement(staticTransform));
275                        staticTransform.makeIdentity();
276                    }
277
278                    pUpdate->getStackedTransforms().push_back(new osgAnimation::StackedRotateAxisElement(
279                        std::string("rotate") + curveNames[j], axes[j], fbxPropValue[j]));
280                }
281                else
282                {
283                    staticTransform.preMultRotate(osg::Quat(fbxPropValue[j], axes[j]));
284                }
285            }
286        }
287    }
288    else
289    {
290        staticTransform.preMultRotate(makeQuat(prop.Get(), fbxRotOrder));
291    }
292}
293
294void readScaleElement(KFbxTypedProperty<fbxDouble3>& prop,
295                      osgAnimation::UpdateMatrixTransform* pUpdate,
296                      osg::Matrix& staticTransform,
297                      KFbxScene& fbxScene)
298{
299    fbxDouble3 fbxPropValue = prop.Get();
300    osg::Vec3d val(
301        fbxPropValue[0],
302        fbxPropValue[1],
303        fbxPropValue[2]);
304
305    if (isAnimated(prop, fbxScene))
306    {
307        if (!staticTransform.isIdentity())
308        {
309            pUpdate->getStackedTransforms().push_back(new osgAnimation::StackedMatrixElement(staticTransform));
310            staticTransform.makeIdentity();
311        }
312        pUpdate->getStackedTransforms().push_back(new osgAnimation::StackedScaleElement("scale", val));
313    }
314    else
315    {
316        staticTransform.preMultScale(val);
317    }
318}
319
320void readUpdateMatrixTransform(osgAnimation::UpdateMatrixTransform* pUpdate, KFbxNode* pNode, KFbxScene& fbxScene)
321{
322    osg::Matrix staticTransform;
323
324    readTranslationElement(pNode->LclTranslation, pUpdate, staticTransform, fbxScene);
325
326    fbxDouble3 fbxRotOffset = pNode->RotationOffset.Get();
327    fbxDouble3 fbxRotPiv = pNode->RotationPivot.Get();
328    staticTransform.preMultTranslate(osg::Vec3d(
329        fbxRotPiv[0] + fbxRotOffset[0],
330        fbxRotPiv[1] + fbxRotOffset[1],
331        fbxRotPiv[2] + fbxRotOffset[2]));
332
333    // When this flag is set to false, the RotationOrder, the Pre/Post rotation
334    // values and the rotation limits should be ignored.
335    bool rotationActive = pNode->RotationActive.Get();
336
337    ERotationOrder fbxRotOrder = (rotationActive && pNode->RotationOrder.IsValid()) ?
338        pNode->RotationOrder.Get() : eEULER_XYZ;
339
340    if (rotationActive)
341    {
342        staticTransform.preMultRotate(makeQuat(pNode->PreRotation.Get(), fbxRotOrder));
343    }
344
345    readRotationElement(pNode->LclRotation, fbxRotOrder,
346        pNode->QuaternionInterpolate.IsValid() && pNode->QuaternionInterpolate.Get(),
347        pUpdate, staticTransform, fbxScene);
348
349    if (rotationActive)
350    {
351        staticTransform.preMultRotate(makeQuat(pNode->PostRotation.Get(), fbxRotOrder));
352    }
353
354    fbxDouble3 fbxSclOffset = pNode->ScalingOffset.Get();
355    fbxDouble3 fbxSclPiv = pNode->ScalingPivot.Get();
356    staticTransform.preMultTranslate(osg::Vec3d(
357        fbxSclOffset[0] + fbxSclPiv[0] - fbxRotPiv[0],
358        fbxSclOffset[1] + fbxSclPiv[1] - fbxRotPiv[1],
359        fbxSclOffset[2] + fbxSclPiv[2] - fbxRotPiv[2]));
360
361    readScaleElement(pNode->LclScaling, pUpdate, staticTransform, fbxScene);
362
363    staticTransform.preMultTranslate(osg::Vec3d(
364        -fbxSclPiv[0],
365        -fbxSclPiv[1],
366        -fbxSclPiv[2]));
367
368    if (!staticTransform.isIdentity())
369    {
370        pUpdate->getStackedTransforms().push_back(new osgAnimation::StackedMatrixElement(staticTransform));
371    }
372}
373
374osg::Group* createGroupNode(KFbxSdkManager& pSdkManager, KFbxNode* pNode,
375    const std::string& animName, const osg::Matrix& localMatrix, bool bNeedSkeleton,
376    std::map<KFbxNode*, osg::Node*>& nodeMap, KFbxScene& fbxScene)
377{
378    if (bNeedSkeleton)
379    {
380        osgAnimation::Bone* osgBone = new osgAnimation::Bone;
381        osgBone->setDataVariance(osg::Object::DYNAMIC);
382        osgBone->setName(pNode->GetName());
383        osgAnimation::UpdateBone* pUpdate = new osgAnimation::UpdateBone(animName);
384        readUpdateMatrixTransform(pUpdate, pNode, fbxScene);
385        osgBone->setUpdateCallback(pUpdate);
386
387        nodeMap.insert(std::pair<KFbxNode*, osg::Node*>(pNode, osgBone));
388
389        return osgBone;
390    }
391    else
392    {
393        bool bAnimated = !animName.empty();
394        if (!bAnimated && localMatrix.isIdentity())
395        {
396            osg::Group* pGroup = new osg::Group;
397            pGroup->setName(pNode->GetName());
398            return pGroup;
399        }
400
401        osg::MatrixTransform* pTransform = new osg::MatrixTransform(localMatrix);
402        pTransform->setName(pNode->GetName());
403
404        if (bAnimated)
405        {
406            osgAnimation::UpdateMatrixTransform* pUpdate = new osgAnimation::UpdateMatrixTransform(animName);
407            readUpdateMatrixTransform(pUpdate, pNode, fbxScene);
408            pTransform->setUpdateCallback(pUpdate);
409        }
410
411        return pTransform;
412    }
413}
414
415osgDB::ReaderWriter::ReadResult OsgFbxReader::readFbxNode(
416    KFbxNode* pNode,
417    bool& bIsBone, int& nLightCount)
418{
419    if (KFbxNodeAttribute* lNodeAttribute = pNode->GetNodeAttribute())
420    {
421        KFbxNodeAttribute::EAttributeType attrType = lNodeAttribute->GetAttributeType();
422        switch (attrType)
423        {
424        case KFbxNodeAttribute::eNURB:
425        case KFbxNodeAttribute::ePATCH:
426        case KFbxNodeAttribute::eNURBS_CURVE:
427        case KFbxNodeAttribute::eNURBS_SURFACE:
428            {
429                KFbxGeometryConverter lConverter(&pSdkManager);
430                if (!lConverter.TriangulateInPlace(pNode))
431                {
432                    OSG_WARN << "Unable to triangulate FBX NURBS " << pNode->GetName() << std::endl;
433                }
434            }
435            break;
436        default:
437            break;
438        }
439    }
440
441    bIsBone = false;
442    bool bCreateSkeleton = false;
443
444    KFbxNodeAttribute::EAttributeType lAttributeType = KFbxNodeAttribute::eUNIDENTIFIED;
445    if (pNode->GetNodeAttribute())
446    {
447        lAttributeType = pNode->GetNodeAttribute()->GetAttributeType();
448        if (lAttributeType == KFbxNodeAttribute::eSKELETON)
449        {
450            bIsBone = true;
451        }
452    }
453
454    if (!bIsBone && fbxSkeletons.find(pNode) != fbxSkeletons.end())
455    {
456        bIsBone = true;
457    }
458
459    unsigned nMaterials = pNode->GetMaterialCount();
460    std::vector<StateSetContent > stateSetList;
461
462    for (unsigned i = 0; i < nMaterials; ++i)
463    {
464        KFbxSurfaceMaterial* fbxMaterial = pNode->GetMaterial(i);
465        assert(fbxMaterial);
466        stateSetList.push_back(fbxMaterialToOsgStateSet.convert(fbxMaterial));
467    }
468
469    osg::NodeList skeletal, children;
470
471    int nChildCount = pNode->GetChildCount();
472    for (int i = 0; i < nChildCount; ++i)
473    {
474        KFbxNode* pChildNode = pNode->GetChild(i);
475
476        if (pChildNode->GetParent() != pNode)
477        {
478            //workaround for bug that occurs in some files exported from Blender
479            continue;
480        }
481
482        bool bChildIsBone = false;
483        osgDB::ReaderWriter::ReadResult childResult = readFbxNode(
484            pChildNode, bChildIsBone, nLightCount);
485        if (childResult.error())
486        {
487            return childResult;
488        }
489        else if (osg::Node* osgChild = childResult.getNode())
490        {
491            if (bChildIsBone)
492            {
493                if (!bIsBone) bCreateSkeleton = true;
494                skeletal.push_back(osgChild);
495            }
496            else
497            {
498                children.push_back(osgChild);
499            }
500        }
501    }
502
503    std::string animName = readFbxAnimation(pNode, pNode->GetName());
504
505    osg::Matrix localMatrix;
506    makeLocalMatrix(pNode, localMatrix);
507    bool bLocalMatrixIdentity = localMatrix.isIdentity();
508
509    osg::ref_ptr<osg::Group> osgGroup;
510
511    bool bEmpty = children.empty() && !bIsBone;
512
513    switch (lAttributeType)
514    {
515    case KFbxNodeAttribute::eMESH:
516        {
517            size_t bindMatrixCount = boneBindMatrices.size();
518            osgDB::ReaderWriter::ReadResult meshRes = readFbxMesh(pNode, stateSetList);
519            if (meshRes.error())
520            {
521                return meshRes;
522            }
523            else if (osg::Node* node = meshRes.getNode())
524            {
525                bEmpty = false;
526
527                if (bindMatrixCount != boneBindMatrices.size())
528                {
529                    //The mesh is skinned therefore the bind matrix will handle all transformations.
530                    localMatrix.makeIdentity();
531                    bLocalMatrixIdentity = true;
532                }
533
534                if (animName.empty() &&
535                    children.empty() &&
536                    skeletal.empty() &&
537                    bLocalMatrixIdentity)
538                {
539                    return osgDB::ReaderWriter::ReadResult(node);
540                }
541
542                children.insert(children.begin(), node);
543            }
544        }
545        break;
546    case KFbxNodeAttribute::eCAMERA:
547    case KFbxNodeAttribute::eLIGHT:
548        {
549            osgDB::ReaderWriter::ReadResult res =
550                lAttributeType == KFbxNodeAttribute::eCAMERA ?
551                readFbxCamera(pNode) : readFbxLight(pNode, nLightCount);
552            if (res.error())
553            {
554                return res;
555            }
556            else if (osg::Group* resGroup = dynamic_cast<osg::Group*>(res.getObject()))
557            {
558                bEmpty = false;
559                if (animName.empty() &&
560                    bLocalMatrixIdentity)
561                {
562                    osgGroup = resGroup;
563                }
564                else
565                {
566                    children.insert(children.begin(), resGroup);
567                }
568            }
569        }
570        break;
571    default:
572        break;
573    }
574
575    if (bEmpty)
576    {
577        osgDB::ReaderWriter::ReadResult(0);
578    }
579
580    if (!osgGroup) osgGroup = createGroupNode(pSdkManager, pNode, animName, localMatrix, bIsBone, nodeMap, fbxScene);
581
582    osg::Group* pAddChildrenTo = osgGroup.get();
583    if (bCreateSkeleton)
584    {
585        osgAnimation::Skeleton* osgSkeleton = getSkeleton(pNode, fbxSkeletons, skeletonMap);
586        osgSkeleton->setDefaultUpdateCallback();
587        pAddChildrenTo->addChild(osgSkeleton);
588        pAddChildrenTo = osgSkeleton;
589    }
590
591    for (osg::NodeList::iterator it = skeletal.begin(); it != skeletal.end(); ++it)
592    {
593        pAddChildrenTo->addChild(it->get());
594    }
595    for (osg::NodeList::iterator it = children.begin(); it != children.end(); ++it)
596    {
597        pAddChildrenTo->addChild(it->get());
598    }
599
600
601    return osgDB::ReaderWriter::ReadResult(osgGroup.get());
602}
603
604osgAnimation::Skeleton* getSkeleton(KFbxNode* fbxNode,
605    const std::set<const KFbxNode*>& fbxSkeletons,
606    std::map<KFbxNode*, osgAnimation::Skeleton*>& skeletonMap)
607{
608    //Find the first non-skeleton ancestor of the node.
609    while (fbxNode &&
610        ((fbxNode->GetNodeAttribute() &&
611        fbxNode->GetNodeAttribute()->GetAttributeType() == KFbxNodeAttribute::eSKELETON) ||
612        fbxSkeletons.find(fbxNode) != fbxSkeletons.end()))
613    {
614        fbxNode = fbxNode->GetParent();
615    }
616
617    std::map<KFbxNode*, osgAnimation::Skeleton*>::const_iterator it = skeletonMap.find(fbxNode);
618    if (it == skeletonMap.end())
619    {
620        osgAnimation::Skeleton* skel = new osgAnimation::Skeleton;
621        skel->setDefaultUpdateCallback();
622        skeletonMap.insert(std::pair<KFbxNode*, osgAnimation::Skeleton*>(fbxNode, skel));
623        return skel;
624    }
625    else
626    {
627        return it->second;
628    }
629}
Note: See TracBrowser for help on using the browser.