Inside Sabertooth
Learn how Sabertooth uses 3ds Max to create 3D interactive projects, including HBO Go’s Game of Thrones interactive experience
  • 1/3
You are here: Forum Home / Autodesk® FBX® / FBX SDK / How to find out if an object is animated?
  RSS 2.0 ATOM  

How to find out if an object is animated?
Rate this thread
 
49910
 
Permlink of this thread  
avatar
  • Location: Midvale, UT
  • Total Posts: 144
  • Joined: 25 March 2010 10:49 AM

Howdy,

Is there a way to find out if an object is animated in the imported fbx file, so that if it isn’t, I can skip allocating animation tracks for that object?

Adios,
Cactus Dan



Replies: 0
avatar

If this is zero, then there are no animations present

pScene->GetSrcObjectCount(FBX_TYPE(KFbxAnimStack))



Replies: 0
avatar

Howdy,

Thanks for the info, but what about for individual objects?

For example, suppose the file to import has skeletal animation, camera animation but no light animation in the take. What I’d want to do is set animation keys in my application for the imported skeleton and camera but skip the light.

Adios,
Cactus Dan



Replies: 1
/userdata/avatar/3yvwf23us_doug100x100.png

You will have to do a pass over animation layers and check each node, I think.

Author: Doug Rogers

Replied: 28 November 2010 02:13 AM  
avatar

Howdy,

What do you mean “animation layer”?

Doing a search for “animation layer” doesn’t seem to get me very far. The only thing that I found in the docs was:

HKFCurveNode mLayer;        // Ctrl Curve (Animation layering)

... from the kfcurvenode.h

Adios,
Cactus Dan



Replies: 1
/userdata/avatar/3yvwf23us_doug100x100.png

Something like this:

void FBXLoader::AddAnimation(KFbxScenepScene)
{

 KFbxNode
rootNode pScene->GetRootNode();

  for (
int i 0pScene->GetSrcObjectCount(FBX_TYPE(KFbxAnimStack)); i++)
  
{
    KFbxAnimStack
lAnimStack KFbxCast<KFbxAnimStack>(pScene->GetSrcObject(FBX_TYPE(KFbxAnimStack), i));
    
pScene->GetEvaluator()->SetContext(lAnimStack);

    
std::string name lAnimStack->GetName();

    
m_animationStackMap[name] lAnimStack;

    
AddAnimationRecursive(lAnimStackrootNodem_pRootFrame);
  
}
}

void FBXLoader
::AddAnimationRecursive(KFbxAnimStackpAnimStackKFbxNodepNodeFBXFrame pFrame)
{
  int nbAnimLayers 
pAnimStack->GetMemberCount(FBX_TYPE(KFbxAnimLayer));

  
std::string takeName pAnimStack->GetName();  

  
assert(m_takeNameToAnimationSetMap.find(takeName) != m_takeNameToAnimationSetMap.end());

  
FBXAnimationSet *pAnimationSet m_takeNameToAnimationSetMap.find(takeName)->second.get();

  for (
int layerNo 0layerNo nbAnimLayerslayerNo++)
  
{
    KFbxAnimLayer
lAnimLayer pAnimStack->GetMember(FBX_TYPE(KFbxAnimLayer), layerNo);


    
AddAnimationRecursive(lAnimLayerpNodetakeNamepAnimationSetpFrame);
  
}
}

void FBXLoader
::AddAnimationRecursive(KFbxAnimLayerpAnimLayerKFbxNodepNodestd::string &takeName
                                      
FBXAnimationSet *pAnimationSet
                                      
FBXFrame pFrame)
{

 
//AddAnimation(pAnimLayer, pNode, takeName, pAnimationSet, pFrame);
    
bool bNodeHasAnimation HasSomeFCurves(pNodepAnimLayer);  // <<---------- check if this node has animation

 
int childCount pNode->GetChildCount();

 
FBXFrame pChildFrame = (FBXFrame *)pFrame->pFrameFirstChild;
 for (
int i 0childCounti++)
 
{
 assert
(pChildFrame);
 
AddAnimationRecursive(pAnimLayerpNode->GetChild(i), takeNamepAnimationSetpChildFrame);
 
pChildFrame = (FBXFrame *)pChildFrame->pFrameSibling;
 
}
}



bool HasSomeFCurves
(KFbxObjectpNodeKFbxAnimLayerpAnimLayer)
{
  
// return true as soon as one property on the object (or it's attributes)
  // has an fcurve with one or more keys.
  
if (!pNode
    return 
false;

  
bool hasKeys false;
  
pNode->RootProperty.BeginCreateOrFindProperty();
  
KFbxProperty prop pNode->GetFirstProperty();
  while (
prop.IsValid() && hasKeys == false)
  
{
    KFbxAnimCurveNode
fcn prop.GetCurveNode(pAnimLayerfalse);
    
hasKeys HasKeysOnFCurves(fcn);     
    if (
hasKeys)
    
{
      
const char name fcn->GetName();
      
KFbxAnimCurvecurve fcn->GetCurve(0);

    
}
    prop 
pNode->GetNextProperty(prop);
  
}
  pNode
->RootProperty.EndCreateOrFindProperty();
  return 
hasKeys;
}
Author: Doug Rogers

Replied: 28 November 2010 04:32 AM  
avatar

Howdy,

Thanks for the code example.

Unfortunately, I’m using the 2010 sdk at the moment, and a few of the classes in your example aren’t available.

Right now I’m on Mac OS, using FBX2010 with Xcode 2.5, to stay compatible with the host application that I’m writing the import/export plugin for, so I’m a little hesitant to move to 2011. :(

Are there any known major incompatibilities if I move to 2011?

Adios,
Cactus Dan



Replies: 1
/userdata/avatar/3yvwf23us_doug100x100.png

>Are there any known major incompatibilities if I move to 2011?
The animation system is the biggest difference, and IMHO, much better.

You can still do the same thing in the older SDK, though.

void FBXLoader::AddAnimationRecursive(KFbxNodepNodeAnimationFrame pFrame)
{

  AddAnimation
(pNodepFrame);


  
int childCount pNode->GetChildCount();


  
AnimationFrame pChildFrame = (AnimationFrame *)pFrame->pFrameFirstChild;
  for (
int i 0childCounti++)
  
{
    assert
(pChildFrame);
    
AddAnimationRecursive(pNode->GetChild(i), pChildFrame);
    
pChildFrame = (AnimationFrame *)pChildFrame->pFrameSibling;
  
}
}



void FBXLoader
::AddAnimation(KFbxScenepScene)
{
  HRESULT hr
;
  
KFbxNoderootNode pScene->GetRootNode();


  
AddAnimationRecursive(rootNodem_pRootFrame);



}

void FBXLoader
::AddAnimation(KFbxNodepNodeAnimationFrame *pFrame)
{
    int takeNodeCount 
pNode->GetTakeNodeCount();


  for(
int i 0<  takeNodeCounti++)
  
{
    KFbxTakeNode
pTakeNode pNode->GetTakeNode(i);
    
// check for default take or take with no entries
   
}
}
Author: Doug Rogers

Replied: 28 November 2010 09:29 AM  
avatar

Howdy,

Thanks for pointing me in the right direction. I managed to get something working in FBX2010.

Here’s what I did:

bool HasFBXAnimation(KFbxNode *pNode)
{
     Bool hasKeys 
FALSE;
 
     
KFbxProperty prop pNode->GetFirstProperty();
 
     while(
prop.IsValid())
     
{
          KFCurveNode 
*fcn prop.GetKFCurveNode();
          if(
fcn && fcn->KeyGetCount() > 0)
          
{
               hasKeys 
TRUE;
          
}
          prop 
pNode->GetNextProperty(prop);
     
}
 
     
return hasKeys;
}

That seems to work fine. Does that look OK to you?

Adios,
Cactus Dan



Replies: 1
/userdata/avatar/3yvwf23us_doug100x100.png

You might have to bracket it with:

pNode->RootProperty.BeginCreateOrFindProperty();

  
pNode->RootProperty.EndCreateOrFindProperty();

Not sure, though.

Also, there is no point continuing to scan once hasKeys is true.

Author: Doug Rogers

Replied: 28 November 2010 12:09 PM  
avatar

Howdy,

Well, I was going to add a check for which properties have keys, for example if a joint only has rotation keys, then I don’t want to allocate translation and scale tracks in my application and fill them with keys.

But I’m having a strange thing happen. I have a “BuildJointSkeleton()” function which converts the skeleton nodes to my joints, and if I run the check for animation keys in that function, it only works for the first imported take. For all other imported takes or files it then returns false. Even if I close and open a new document, it still returns false. The only way for it to return true again is to quit and restart the application.

Have you ever encountered that kind of behavior?

If I only do the check for animation keys in my “LoadTake()” function, then it returns true for each take that is loaded and also each file that is merged into the document. But doing the check there, really slows down loading the animation take.

I may need to re-examine how I’m loading the take. Right now the loops are setup where it loops through the objects inside the loop through the frames. Maybe I should loop through the frames inside of looping through the objects so that the check for animation keys is only called once per object. Right now it’s calling the check function the same number of times as there are frames, for each object. :O

Adios,
Cactus Dan



Replies: 2
/userdata/avatar/3yvwf23us_doug100x100.png

I would recommend update to the latest SDK.  It handles animation much better and the more animation work you do with the older version, the more work it will be to update.  It only took me a day to port over my application.

Author: Doug Rogers

Replied: 29 November 2010 04:15 AM  
/userdata/avatar/vx3501hqr_small.jpg

Hi, Cactus,
This might not be very helpful, but the latest SDK provided a function IsAnimated(KFbxObject* pObj) in kfbxutilities.h, which is basically doing the same thing as what you did by HasFBXAnimation.

Author: Jiayang Xu

Replied: 29 November 2010 07:58 PM  
avatar

Howdy,

Well, I think I’ve found an easier more efficient way to do what I wanted to do:

chartakeName pNode->GetCurrentTakeNodeName();
KFCurveNode *fcn pNode->LclTranslation.GetKFCurveNode(falsetakeName);
if(
fcn && fcn->KeyGetCount() > 0)
{
     
// import the animation
}

... and then do the same for scale and rotation, or any other property my import plugin will support.

This way it won’t have to cycle through all of the properties to check for the properties that my import plugin will support. It will go directly to the supported property to check for animation keys.

Adios,
Cactus Dan



Replies: 0
avatar
  • nian.wu
  • Posted: 01 December 2010 01:54 PM

In FBX 2011.3, the API KFbxNode::GetAnimationInterval() can tell you if there is animation for this FBX node, whick do the same thing as your above code. This API also check the node’s children recursively.
Please check FBX 2010, I remember it also has the same API.



Nian Wu
AutoDesk FBX Team

Replies: 0