Wie kann ich FBX-Animationen mit dem FBX SDK importieren?


7

Ich habe die Netze korrekt mit all ihren Eckpunkten, Indizes, UVs und Normalen geladen. Ich versuche gerade, die Animationen richtig zum Laufen zu bringen. Ich habe mir die FBX SDK-Dokumentation mit wenig Hilfe angesehen. Wenn mir jemand beim Einstieg helfen oder mich in die richtige Richtung weisen könnte, wäre ich sehr dankbar. Ich habe Code hinzugefügt, damit Sie eine Vorstellung davon bekommen, was ich tue. Ich sollte in der Lage sein, diesen Code irgendwo in der Lade-FBX-Funktion zu platzieren und ihn funktionieren zu lassen.

//GETTING ANIMAION DATA
for(int i = 0; i < scene->GetSrcObjectCount<FbxAnimStack>(); ++i)
{
    FbxAnimStack* lAnimStack = scene->GetSrcObject<FbxAnimStack>(i);

    FbxString stackName = "Animation Stack Name: ";
    stackName += lAnimStack->GetName();
    string sStackName = stackName;

    int numLayers = lAnimStack->GetMemberCount<FbxAnimLayer>();
    for(int j = 0; j < numLayers; ++j)
    {
        FbxAnimLayer* lAnimLayer = lAnimStack->GetMember<FbxAnimLayer>(j);

        FbxString layerName = "Animation Stack Name: ";
        layerName += lAnimLayer->GetName();
        string sLayerName = layerName;

        queue<FbxNode*> nodes;

        FbxNode* tempNode = scene->GetRootNode();

        while(tempNode != NULL)
        {
            FbxAnimCurve* lAnimCurve = tempNode->LclTranslation.GetCurve(lAnimLayer, FBXSDK_CURVENODE_COMPONENT_X);

            if(lAnimCurve != NULL)
            {
                //I know something needs to be done here but I dont know what.
            }

            for(int i = 0; i < tempNode->GetChildCount(false); ++i)
            {
                nodes.push(tempNode->GetChild(i));
            }

            if(nodes.size() > 0)
            {
                tempNode = nodes.front();
                nodes.pop();
            }
            else
            {
                tempNode = NULL;
            }
        }               
    }       
}

Hier ist die volle Funktion

bool FBXLoader::LoadFBX(ParentMeshObject* _parentMesh, char* _filePath, bool _hasTexture)
{
    FbxManager* fbxManager = FbxManager::Create();
if(!fbxManager)
{
    printf( "ERROR %s : %d failed creating FBX Manager!\n", __FILE__, __LINE__ );
}

FbxIOSettings* ioSettings = FbxIOSettings::Create(fbxManager, IOSROOT);
fbxManager->SetIOSettings(ioSettings);

FbxString filePath = FbxGetApplicationDirectory();
fbxManager->LoadPluginsDirectory(filePath.Buffer());

FbxScene* scene = FbxScene::Create(fbxManager, "");

int fileMinor, fileRevision;
int sdkMajor, sdkMinor, sdkRevision;
int fileFormat;

FbxManager::GetFileFormatVersion(sdkMajor, sdkMinor, sdkRevision);
FbxImporter* importer = FbxImporter::Create(fbxManager, "");

if(!fbxManager->GetIOPluginRegistry()->DetectReaderFileFormat(_filePath, fileFormat))
{
    //Unrecognizable file format. Try to fall back on FbxImorter::eFBX_BINARY
    fileFormat = fbxManager->GetIOPluginRegistry()->FindReaderIDByDescription("FBX binary (*.fbx)");
}

bool importStatus = importer->Initialize(_filePath, fileFormat, fbxManager->GetIOSettings());
importer->GetFileVersion(fileMinor, fileMinor, fileRevision);

if(!importStatus)
{
    printf( "ERROR %s : %d FbxImporter Initialize failed!\n", __FILE__, __LINE__ );
    return false;
}

importStatus = importer->Import(scene);

if(!importStatus)
{
    printf( "ERROR %s : %d FbxImporter failed to import the file to the scene!\n", __FILE__, __LINE__ );
    return false;
}

FbxAxisSystem sceneAxisSystem = scene->GetGlobalSettings().GetAxisSystem();
FbxAxisSystem axisSystem( FbxAxisSystem::eYAxis, FbxAxisSystem::eParityOdd, FbxAxisSystem::eLeftHanded );

if(sceneAxisSystem != axisSystem)
{
    axisSystem.ConvertScene(scene);
}

TriangulateRecursive(scene->GetRootNode());

FbxArray<FbxMesh*> meshes;
FillMeshArray(scene, meshes);

unsigned short vertexCount = 0;
unsigned short triangleCount = 0;
unsigned short faceCount = 0;
unsigned short materialCount = 0;

int numberOfVertices = 0;
for(int i = 0; i < meshes.GetCount(); ++i)
{
    numberOfVertices += meshes[i]->GetPolygonVertexCount();
}



Face face;
vector<Face> faces;
int indicesCount = 0;

int ptrMove = 0;

float wValue = 0.0f;

if(!_hasTexture)
{
    wValue = 1.0f;
}

for(int i = 0; i < meshes.GetCount(); ++i)
{
    int vertexCount = 0;
    vertexCount = meshes[i]->GetControlPointsCount();
    if(vertexCount == 0)
        continue;

    VertexType* vertices;
    vertices = new VertexType[vertexCount];

    int triangleCount = meshes[i]->GetPolygonVertexCount() / 3;
    indicesCount = meshes[i]->GetPolygonVertexCount();

    FbxVector4* fbxVerts = new FbxVector4[vertexCount];
    int arrayIndex = 0;
    memcpy(fbxVerts, meshes[i]->GetControlPoints(), vertexCount * sizeof(FbxVector4));

    for(int j = 0; j < triangleCount; ++j)
    {
        int index = 0;
        FbxVector4 fbxNorm(0, 0, 0, 0);
        FbxVector2 fbxUV(0, 0);
        bool texCoordFound = false;
        face.indices[0] = index = meshes[i]->GetPolygonVertex(j, 0);
        vertices[index].position.x = (float)fbxVerts[index][0];
        vertices[index].position.y = (float)fbxVerts[index][1];
        vertices[index].position.z = (float)fbxVerts[index][2];
        vertices[index].position.w = wValue;
        meshes[i]->GetPolygonVertexNormal(j, 0, fbxNorm);
        vertices[index].normal.x = (float)fbxNorm[0];
        vertices[index].normal.y = (float)fbxNorm[1];
        vertices[index].normal.z = (float)fbxNorm[2];
        texCoordFound = meshes[i]->GetPolygonVertexUV(j, 0, "map1", fbxUV);
        vertices[index].texture.x = (float)fbxUV[0];
        vertices[index].texture.y = (float)fbxUV[1];

        face.indices[1] = index = meshes[i]->GetPolygonVertex(j, 1);
        vertices[index].position.x = (float)fbxVerts[index][0];
        vertices[index].position.y = (float)fbxVerts[index][1];
        vertices[index].position.z = (float)fbxVerts[index][2];
        vertices[index].position.w = wValue;
        meshes[i]->GetPolygonVertexNormal(j, 1, fbxNorm);
        vertices[index].normal.x = (float)fbxNorm[0];
        vertices[index].normal.y = (float)fbxNorm[1];
        vertices[index].normal.z = (float)fbxNorm[2];
        texCoordFound = meshes[i]->GetPolygonVertexUV(j, 1, "map1", fbxUV);
        vertices[index].texture.x = (float)fbxUV[0];
        vertices[index].texture.y = (float)fbxUV[1];

        face.indices[2] = index = meshes[i]->GetPolygonVertex(j, 2);
        vertices[index].position.x = (float)fbxVerts[index][0];
        vertices[index].position.y = (float)fbxVerts[index][1];
        vertices[index].position.z = (float)fbxVerts[index][2];
        vertices[index].position.w = wValue;
        meshes[i]->GetPolygonVertexNormal(j, 2, fbxNorm);
        vertices[index].normal.x = (float)fbxNorm[0];
        vertices[index].normal.y = (float)fbxNorm[1];
        vertices[index].normal.z = (float)fbxNorm[2];
        texCoordFound = meshes[i]->GetPolygonVertexUV(j, 2, "map1", fbxUV);
        vertices[index].texture.x = (float)fbxUV[0];
        vertices[index].texture.y = (float)fbxUV[1];

        faces.push_back(face);
    }

    meshes[i]->Destroy();
    meshes[i] = NULL;

    int indexCount = faces.size() * 3;
    unsigned long* indices = new unsigned long[faces.size() * 3]; 
    int indicie = 0;
    for(unsigned int i = 0; i < faces.size(); ++i)
    {
        indices[indicie++] = faces[i].indices[0];
        indices[indicie++] = faces[i].indices[1];
        indices[indicie++] = faces[i].indices[2];
    }
    faces.clear();
    _parentMesh->AddChild(vertices, indices, vertexCount, indexCount);
}

return true;
}

1
Schauen Sie sich das ViewScene SDK-Beispiel an - es enthält den Code zum Laden und Abspielen von Animationen.
Jovan

Antworten:


8

Die FBX-Dokumentation ist manchmal schmerzhaft, und dies ist definitiv eine davon.

Ich habe auf zwei Arten auf Animationsdaten zugegriffen. Das erste wird im ImportScene-Beispiel verwendet, das mit dem SDK geliefert wird, und es ist die Art und Weise, wie Sie versuchen, Dinge zu tun. In Ihrem Beispiel müssten Sie, nachdem Sie über eine gültige lAnimCurve verfügen, die Anzahl der in dieser Kurve gespeicherten Keyframes abfragen und dann einzeln darauf zugreifen. Es ist ein ziemlich komplexer Prozess. Ich würde Sie auf die Datei DisplayAnimation.cxx im ImportScene-Beispiel verweisen, um zu sehen, wie sie es tun.

Das Problem dabei ist, dass Sie dann alle fehlenden Informationen ermitteln müssen. In der Animation, mit der ich arbeite, habe ich Keyframe-Daten für Frame 0, 35 und 70. Jetzt müsste ich feststellen, ob die Interpolation linear oder kubisch ist, was eine kompliziertere und fehleranfälligere Programmierung erfordert.

Ich weiß zu diesem Zeitpunkt auch nicht, wie schnell die Animation ausgeführt wird - 30 fps, 24 fps, 60 fps oder eine benutzerdefinierte Zahl -. Obwohl ich weiß, dass ich 70 Frames habe, weiß ich eigentlich nicht, wie lange die Animation dauern soll .

Stattdessen würde ich vorschlagen, in die KFbxAnimEvaluator-Klasse einzutauchen. Dies macht das Leben viel einfacher, da es alle möglichen Animationsmaterialien für Sie herausfindet. Wirklich, das ist die SDK-Seite, die Sie im Auge behalten sollten.

Hier ist ein Beispielcode, wie ich die Zeiten aufschlüssle. Angenommen, lAnimStackCount ist die Anzahl der Animationsstapel in meiner Datei.

for(i = 0; i < lAnimStackCount; i++) {
   KFbxTakeInfo* lTakeInfo = lImporter->GetTakeInfo();

   KTime start = lTakeInfo->mLocalTimeSpan.GetStart();
   KTime end = lTakeInfo->mLocalTimeSpan.GetStop();

   // now you know how many seconds the animation runs, and can figure out how many
   // keyframes you need. I usually export animations as 30fps
}

Von hier aus können Sie die Funktion GetNodeLocalTransform () in KFbxAnimEvaluator verwenden, um die Transformationsmatrix zu bestimmten Zeiten abzurufen. Sie erhalten eine endgültige Antwortmatrix, aus der Sie die TRS-Informationen abrufen können.

Ich weiß, dass das vage ist, aber mein spezifischer Code befindet sich nicht auf diesem Computer. Hoffentlich ist es hoch genug, um zu helfen.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.