Import/Export BVH question

Import/Export BVH question

ebeschetRKDHJ
Participant Participant
3,444 Views
14 Replies
Message 1 of 15

Import/Export BVH question

ebeschetRKDHJ
Participant
Participant

Hello,

 

We are currently working on our 3d software import/export process.

We need to import .bvh files and we saw that it's possible with your fbx sdk (we are already use it for fbx).

 

After a try, it works well ! But now, we would like to export BVH files.

After using the FbxExporter initialize funtion (virtual bool Initialize(const char* pFileName, int pFileFormat = -1, FbxIOSettings* pIOSettings = NULL)) with pFileFormat = -1, Export function returns false and our resulted file is empty.

 

We are a bit disapointed because on your website, we can find 2 different informations :

- "Remarks: According to the file suffix, a specialized writer will be created internally. Ex: for .fbx files a FBX Writer, for .3ds files, a 3ds writer, etc. Supported files formats: FBX 5/6/7 Binary & ASCII, Collada, DXF, OBJ, 3DS"

 

- "MotionFiles readers/writers are now registered in the public FBX SDK. This means that the FBX SDK can now import and export the following motion file formats: Biovision (BVH), MotionAnalysis (HTR/TRC), Acclaim (ASF/AMC), Vicon (C3D), Adaptive Optics (AOA), and Superfluo (MCD)."

 

Our question : Can we export .bvh files with the fbx sdk ? If yes, what are we doing wrong ?

 

Regards,

Nukeygara team

0 Likes
3,445 Views
14 Replies
Replies (14)
Message 2 of 15

regalir
Autodesk
Autodesk

Hi,

 

yes the FBX SDK can write BVH files. However, due to the nature of the BVH format, your FBX scene must follow a few rules:

  1. You need to mark a 'root' node so the BVH writer knows where the hierarchy starts. You can achieve this by calling the FbxNode::SetSelected(true) on the node you have elected as the root
  2. All the objects names must NOT contain spaces
  3. You can select the correct writer using:
    int lFormat = lSdkManager->GetIOPluginRegistry()->FindWriterIDByExtension("bvh");
    
    // Create an exporter.
    FbxExporter* lExporter = FbxExporter::Create(lSdkManager, "");
    
    // Initialize the exporter.
    lResult = lExporter->Initialize(lNewFileName, lFormat, lSdkManager->GetIOSettings());​
  4. If you want to write animation as well, you need to specify the Frame count and the start time using the following properties (the values you see are the defaults used if you do not change them):

 

IOS_REF.SetIntProp(EXP_MOB_FRAME_COUNT, 0);
IOS_REF.SetTimeProp(EXP_MOB_START, FBXSDK_TIME_ZERO);
​

 

I have attached a simple FBX file used to generate the BVH (below). During export, I set the frame count to 3. There are 2 animated objects in the FBX files, therefore you can see 3 values for the translation and 3 values for the rotation  for both nodes on each line of the MOTION section.

 

HIERARCHY
ROOT MyRoot
{
OFFSET -0.45317 2.82824 -0.51851
CHANNELS 6 Xposition Yposition Zposition Zrotation Xrotation Yrotation
JOINT J1
{
OFFSET 39.879 0.445741 -0.0817193
CHANNELS 6 Xposition Yposition Zposition Zrotation Xrotation Yrotation
End Site
{
OFFSET 33.9878 0 0
}
}
}
MOTION
Frames: 3
Frame Time: 0.0333333
-0.45317 2.82824 -0.51851 0 0 -0 39.879 0.445741 -0.0817193 0 0 -0
-0.45317 2.82824 -0.51851 -0 0 0.00597333 39.879 0.445741 -0.0817193 0 0 -0
-0.45317 2.82824 -0.51851 -0 0 0.0237867 39.879 0.445741 -0.0817193 0 0 -0

0 Likes
Message 3 of 15

ebeschetRKDHJ
Participant
Participant

Hello,

 

Thanks for your answer !

 

We tried to export a bvh with the following code :

 

// Create an exporter.
FbxExporter* lExporter = FbxExporter::Create(manager, "");

int lFormatBVH = manager->GetIOPluginRegistry()->FindWriterIDByExtension("bvh");

if (lExporter->Initialize(charStr, lFormatBVH, manager->GetIOSettings()) == false)
{
return false;
}

 

IOS_REF.SetIntProp(EXP_MOB_FRAME_COUNT, 0);
IOS_REF.SetTimeProp(EXP_MOB_START, FBXSDK_TIME_ZERO);

lExporter->SetProgressCallback((FbxProgressCallback)ProgressCallback);

lStatus = lExporter->Export(_scene);

 

lStatus is always false and our result file is empty... lStatus is true and our result file is good when we export fbx and obj files.

 

We tried with FbxNode::SetSelected(true) and verified names not contains space (we used your fbx file).

 

Do you have any ideas ? How can we debug this export ? Is it our _scene setup that is causing the problem ?

 

Thanks a lot !

 

Regards,

Nukeygara team

 

0 Likes
Message 4 of 15

regalir
Autodesk
Autodesk

Hi,

 

the code you have pasted looks a lot like the samples that are shipping with the FBX SDK. The only few points I would raise here are:

  1. make sure that IOS_REF is the same (reference instead of pointer) as manager->GetIOSettings() (or simply use this last statement instead) for setting the FRAME_COUNT and START values).
  2. your root node (the one you called SetSelected(true)) is not the scene->GetRootNode(). I am assuming it is already the case but, if not, please create a new child of it and attach your other nodes to this new node. FYI, the RootNode() object is a in-memory anchor point and never gets saved to a file.
  3. You can also use the call lExporter->GetStatus().to retrieve the internal error value (if you are lucky 😉 it will tell you what went wrong. You can take a look in the Common.cxx files in the samples of the FBX SDK to see how it is used.
  4. Finally, the BVH writer is processing FbxNode objects only, since it is only interested in the T, R and S so make sure that your scene is looking something like below (of course the hierarchy can look totally different, depending on your requirements):

 

            FBxScene::RootNode
                   |
                 MyRoot (FbxNode)
                 /   \
    ChildA (FbxNode)   ChildB (FbxNode)
              |
        ChildC (FbxNode)

 

                                   

If the above conditions are met, my FBX file should export to BVH without problems. In fact, setting the FRAME_COUNT and START to 0, I am getting the following bfh file:

 

 

HIERARCHY
ROOT MyRoot
{
  OFFSET -0.45317 2.82824 -0.51851
  CHANNELS 6 Xposition Yposition Zposition Zrotation Xrotation Yrotation
  JOINT J1
  {
    OFFSET 39.879 0.445741 -0.0817193
    CHANNELS 6 Xposition Yposition Zposition Zrotation Xrotation Yrotation
    End Site
    {
      OFFSET 33.9878 0 0
    }
  }
}
MOTION
Frames:	0
Frame Time:	0.0333333

 

 

I am not sure it does make sense, though, that you export a BVH without animation. After all, it is a motion file so, what would be the point of such a file without motion? 😉

0 Likes
Message 5 of 15

ebeschetRKDHJ
Participant
Participant

Hello,

 

Thanks a lot again for your help !

 

We got "Can not find root node" with the lExporter->GetStatus() call !

As you told us, we probably have a problem with the FbxNode::SetSelected method.

 

We tried to use it this way (newNode is not our _scene->GetRootNode()):

 

// create a FbxNode
FbxNode* newNode = FbxNode::Create(_scene, nodeInfoI.GetName());
newNode->SetSelected(true);

However, we did not find any doc or example on this method (on the internet or even in fbxnode.h)...

 

Regards,

Nukeygara team

0 Likes
Message 6 of 15

ebeschetRKDHJ
Participant
Participant

Hello @regalir !

 

The FbxNode::SetSelected method doesn't work for us. Could you please detail how we could correctly use it or give us a doc ?

 

Regards,

Nukeygara team

0 Likes
Message 7 of 15

regalir
Autodesk
Autodesk

Apologies for the delay in answering this.

 

Have you correctly attached your 'newNode' to the scene using scene->GetRootNode()->AddChild() ? Just creating a node with the scene as argument will not add it to the scene graph. Your steps should look like:

 

FbxNode* newNode = FbxNode::Create(_scene, nodeInfoI.GetName());
newNode->SetSelected(true);

_scene->GetRootNode()->AddChild(newNode);

The rest of your code should be okay. The SetSelected() function belong to the FbxObject and all it does is set a flag.

0 Likes
Message 8 of 15

genk05223122
Participant
Participant

@regalir 

Hi. I'm trying to convert from FBX to BVH and am using this as a reference, but the message "Can not find root node" is still displayed.

Is there anything else you would like to add or any reference material?

0 Likes
Message 9 of 15

regalir
Autodesk
Autodesk

The "Can not find root node" error simply means that you have not called SetSelected(true) on the node that you want to be the root of the BVH. Assuming that "your" root is the only child of the FbxScene::GetRootNode() - as I've shown in the simple scene graph in a previous post - the following snipped of code should be okay to export to BVH and not have the error. The important lines are 6,7 and 8 😉 and, if there are no other errors in your setup, 'stat' on line 19 will be empty!

    if (lResult && !lOutFilePath.IsEmpty())
    {
        lSdkManager->GetIOSettings()->SetIntProp(EXP_MOB_FRAME_COUNT, 0);
        lSdkManager->GetIOSettings()->SetTimeProp(EXP_MOB_START, FBXSDK_TIME_ZERO);

        FbxNode* bvhRoot = lScene->GetRootNode()->GetChild(0);
        if (bvhRoot)
            bvhRoot->SetSelected(true);

        //lResult = SaveScene(lSdkManager, lScene, lOutFilePath.Buffer(), 0);
        int lFormat = lSdkManager->GetIOPluginRegistry()->FindWriterIDByExtension("bvh");

        // Create an exporter.
        FbxExporter* lExporter = FbxExporter::Create(lSdkManager, "");

        // Initialize the exporter.
        lExporter->Initialize(lOutFilePath.Buffer(), lFormat, lSdkManager->GetIOSettings());
        lResult = lExporter->Export(lScene);
        FbxStatus& stat = lExporter->GetStatus();

        // Destroy the exporter.
        lExporter->Destroy();
    }

Reminder: As I mentioned earlier in the posts, do not use lScene->GetRootNode() as the root of the BVH !

0 Likes
Message 10 of 15

genk05223122
Participant
Participant

 

HIERARCHY
ROOT BVH:reference
{
  OFFSET 0 0 0
  CHANNELS 6 Xposition Yposition Zposition Zrotation Xrotation Yrotation
  JOINT MyRoot
  {
    OFFSET 0 0 0
    CHANNELS 6 Xposition Yposition Zposition Zrotation Xrotation Yrotation
    JOINT J1
    {
      OFFSET 39.879 0.445741 -0.0817193
      CHANNELS 6 Xposition Yposition Zposition Zrotation Xrotation Yrotation
      End Site
      {
        OFFSET 33.9878 0 0
      }
    }
  }
}
MOTION
Frames:	0
Frame Time:	0.0333333

@regalir 

 

Thank you for your quick response.
The error has now disappeared.
However, when I convert the exported BVH file back to FBX and then back to BVH, the ROOT name changes to "BVH:reference" as shown above. Do you know the cause of this?

 

This is the code that converted from BVH to FBX.

 

FbxManager* manager = FbxManager::Create();
FbxScene* scene = FbxScene::Create(manager, "");
FbxImporter* importer = FbxImporter::Create(manager, "");

int formatBVH = manager->GetIOPluginRegistry()->FindReaderIDByExtension("bvh");
importer->Initialize(bvh_path, formatBVH, manager->GetIOSettings());
importer->Import(scene);

FbxExporter* exporter = FbxExporter::Create(manager, "");
exporter->Initialize(fbx_path);

bool status = exporter->Export(scene);

 

 

0 Likes
Message 11 of 15

regalir
Autodesk
Autodesk

Yes I do! 😉

This is actually the default behaviour of the BVH reader to keep all the "skeleton" joints defined in the BVH file under a unique node so they can be more easily identified and manipulated.  We do provide the possibility to change this and just connect everything to the scene->GetRootNode(). However, be aware that, if the scene you are using to import the BVH data in already contains data (nodes, lights, materials, etc.), all the BVH joints will automatically become children of GetRootNode() and when you have to manipulate them you will have more work to do to walk through all the children of GetRootNode() , find the nodes you are interested in and manipulate them individually.

 

To change the behaviour, you just need to call:

manager->GetIOSettings()->SetBoolProp(IMP_BIOVISION_BVH_CREATE_REFERENCE_NODE, false);

before the call to:

importer->Initialize(bvh_path, formatBVH, manager->GetIOSettings());

Depending on your workflow(s) both approaches can make sense. However I suggest you keep using the default behaviour as much as possible and if you don't desire to explicity use the "BVH:Reference" name, just rename the node to something more meaningful right after the

importer->Import(scene)

call. Then, when you re-export the FBX scene back to BVH, your ROOT node will have the name you've set!

0 Likes
Message 12 of 15

genk05223122
Participant
Participant

I see. Thank you for your easy to understand answer.

The OFFSET value directly under MyRoot also does not match. Are there any settings for this?

 

 

ROOT MyRoot
{
  OFFSET -0.45317 2.82824 -0.51851
ROOT MyRoot
{
  OFFSET 0 0 0

 

 

 

And,
・How to change FrameTimes(Converting a 60F FBX file to BVH returns 30F)
・How to optionally convert one data to BVH when there are multiple animation data in FBX

・How to get Channels in BVH file

Is it possible to implement these?

0 Likes
Message 13 of 15

regalir
Autodesk
Autodesk

I haven't actually tested the following code but, from memory, I think this is how you can proceed 😊
For multiple animation stacks:

        // Select one of the AnimStack from the FBX scene
        int desiredStackID = 0;
        int nbAnimStacks = lScene->GetSrcObjectCount<FbxAnimStack>();
        FbxAnimStack* desiredStack = nullptr;
        for (int as = 0; as < nbAnimStacks; as++)
        {
            if (as == desiredStackID)
            {
                desiredStack = lScene->GetSrcObject<FbxAnimStack>(as);
                break;
            }
        }
        // make sure we make it the current one!
        if (desiredStack)
            lScene->SetCurrentAnimationStack(desiredStack);

 
And, hopefully, a combination of the following settings could help with the other issues:

        // available options for the BVH importer/exporter (see \include\fbxsdk\fileio\fbxiosettingspath.h)
        // the _MOB_ variable are generic for the MotionBase - they apply to all the Motion file formats.
        lSdkManager->GetIOSettings()->SetIntProp(EXP_MOB_FRAME_COUNT, 0);
        lSdkManager->GetIOSettings()->SetTimeProp(EXP_MOB_START, FBXSDK_TIME_ZERO);
        lSdkManager->GetIOSettings()->SetDoubleProp(EXP_MOB_FRAME_RATE, 60.0);
        lSdkManager->GetIOSettings()->SetBoolProp(EXP_BIOVISION_BVH_MOTION_TRANSLATION, false);
        lSdkManager->GetIOSettings()->SetBoolProp(EXP_MOB_FROM_GLOBAL_POSITION, false);

        // import setting
        lSdkManager->GetIOSettings()->SetTimeProp(IMP_MOB_START, FBXSDK_TIME_ZERO);
        lSdkManager->GetIOSettings()->SetIntProp(IMP_MOB_FRAME_COUNT, 0);
        lSdkManager->GetIOSettings()->SetDoubleProp(IMP_MOB_FRAME_RATE, 60.0);
        lSdkManager->GetIOSettings()->SetBoolProp(IMP_BIOVISION_BVH_CREATE_REFERENCE_NODE, false);



 

0 Likes
Message 14 of 15

genk05223122
Participant
Participant

@regalir 

Thank you. I will try to refer to it.

Also, no matter what setting I tried, the OFFSET directly under ROOT remained at 0. Is this due to Import or Export?

0 Likes
Message 15 of 15

genk05223122
Participant
Participant

@regalir 

Is there any solution to this?
Apparently, when I imported BVH, LclTranslation was already returned as 0.
Is there anything else to set when importing?

0 Likes