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

Revision 11153, 17.6 kB (checked in by mplatings, 5 years ago)

Fix for some FBX files with multiple meshes bound to a bone.

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