🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

Skeletal Animation - Loading from FBX

Started by
2 comments, last by isu diss 4 years, 5 months ago

Hi, fellow devs, I've successfully loaded 3d models from fbx files. The only problem I face is constructing vertex structure with skeletal data(bone ids and weights) from the model. I know how to retrieve those data from fbx. Here's my code for above process.

Mesh FBXCLoader::ProcessMesh(ID3D11Device * dev, ID3D11DeviceContext *devcon, FbxMesh * mesh)
{
    std::vector<VERTEX> meshvertices;
    ID3D11ShaderResourceView *meshtexture = nullptr;

    FbxVector4 *vertices = mesh->GetControlPoints();

    for (int j = 0; j < mesh->GetPolygonCount(); j++)
    {
        int numVertices = mesh->GetPolygonSize(j);

        FbxLayerElementArrayTemplate<FbxVector2> *uvVertices = 0;
        mesh->GetTextureUV(&uvVertices, FbxLayerElement::eTextureDiffuse);

        for (int k = 0; k < numVertices; k++)
        {
            int controlPointIndex = mesh->GetPolygonVertex(j, k);

            VERTEX vertex;

            vertex.pos.x = (float)vertices[controlPointIndex].mData[0];
            vertex.pos.y = (float)vertices[controlPointIndex].mData[1];
            vertex.pos.z = (float)vertices[controlPointIndex].mData[2];

            vertex.tex.x = (float)uvVertices->GetAt(mesh->GetTextureUVIndex(j, k)).mData[0];
            vertex.tex.y = 1.0f - (float)uvVertices->GetAt(mesh->GetTextureUVIndex(j, k)).mData[1];

            controlpoints[controlPointIndex] = (int)meshvertices.size();
            meshvertices.push_back(vertex);
        }
    }

    int materialcount = mesh->GetNode()->GetSrcObjectCount<FbxSurfaceMaterial>();

    for (int i = 0; i < materialcount; i++)
    {
        FbxSurfaceMaterial *material = (FbxSurfaceMaterial*)mesh->GetNode()->GetSrcObject<FbxSurfaceMaterial>(i);

        if (material)
        {
            FbxProperty prop = material->FindProperty(FbxSurfaceMaterial::sDiffuse);

            const FbxTexture* texture = FbxCast<FbxTexture>(prop.GetSrcObject<FbxTexture>(0));
            const FbxFileTexture* filetexture = FbxCast<FbxFileTexture>(texture);

            ID3D11ShaderResourceView *meshctexture    = LoadTexture(dev, devcon, filetexture->GetFileName());
            meshtexture = meshctexture;
        }
    }

    const FbxVector4 lT = mesh->GetNode()->GetGeometricTranslation(FbxNode::eSourcePivot);
    const FbxVector4 lR = mesh->GetNode()->GetGeometricRotation(FbxNode::eSourcePivot);
    const FbxVector4 lS = mesh->GetNode()->GetGeometricScaling(FbxNode::eSourcePivot);

    FbxAMatrix geometryTransform = FbxAMatrix(lT, lR, lS);

    for (unsigned int deformerIndex = 0; deformerIndex < (UINT)mesh->GetDeformerCount(); ++deformerIndex)
    {
        FbxSkin* skin = reinterpret_cast<FbxSkin*>(mesh->GetDeformer(deformerIndex, FbxDeformer::eSkin));
        if (!skin)
            continue;

        for (unsigned int clusterIndex = 0; clusterIndex < (UINT)skin->GetClusterCount(); ++clusterIndex)
        {
            FbxCluster* cluster = skin->GetCluster(clusterIndex);
            std::string jointname = cluster->GetLink()->GetName();
            unsigned int jointIndex = FindJointIndex(jointname);

            FbxAMatrix transformMatrix;
            FbxAMatrix transformLinkMatrix;
            FbxAMatrix globalBindposeInverseMatrix;

            cluster->GetTransformMatrix(transformMatrix);
            cluster->GetTransformLinkMatrix(transformLinkMatrix);
            globalBindposeInverseMatrix = transformLinkMatrix.Inverse() * transformMatrix * geometryTransform;

            skeleton.mJoints[jointIndex].mGlobalBindposeInverse = globalBindposeInverseMatrix;
            skeleton.mJoints[jointIndex].mNode = cluster->GetLink();

            int *boneVertexIndices = cluster->GetControlPointIndices();
            double *boneVertexWeights = cluster->GetControlPointWeights();

            // Iterate through all the vertices, which are affected by the bone
            int numBoneVertexIndices = cluster->GetControlPointIndicesCount();
            for (int boneVertexIndex = 0; boneVertexIndex < numBoneVertexIndices; boneVertexIndex++)
            {
                int vertexid = controlpoints[boneVertexIndices[boneVertexIndex]];
                 meshvertices[vertexid].boneids.x = jointIndex;
                 meshvertices[vertexid].boneids.y = jointIndex;
                 meshvertices[vertexid].boneids.z = jointIndex;
                 meshvertices[vertexid].boneids.w = jointIndex;

                meshvertices[vertexid].weights.x =  (float)boneVertexWeights[boneVertexIndex];
                meshvertices[vertexid].weights.y =  (float)boneVertexWeights[boneVertexIndex];
                meshvertices[vertexid].weights.z =  (float)boneVertexWeights[boneVertexIndex];
                meshvertices[vertexid].weights.w =  (float)boneVertexWeights[boneVertexIndex];

            }

            FbxAnimStack* animstack = fbxScene->GetSrcObject<FbxAnimStack>(0);
            FbxString animstackname = animstack->GetName();
            FbxTakeInfo* takeinfo = fbxScene->GetTakeInfo(animstackname);
            FbxTime start = takeinfo->mLocalTimeSpan.GetStart();
            FbxTime end = takeinfo->mLocalTimeSpan.GetStop();
            FbxLongLong animationlength = end.GetFrameCount(FbxTime::eFrames30) - start.GetFrameCount(FbxTime::eFrames30) + 1;
            Keyframe** anim = &skeleton.mJoints[jointIndex].mAnimation;

            for (FbxLongLong i = start.GetFrameCount(FbxTime::eFrames30); i <= end.GetFrameCount(FbxTime::eFrames30); ++i)
            {
                FbxTime time;
                time.SetFrame(i, FbxTime::eFrames30);
                *anim = new Keyframe();
                (*anim)->mFrameNum = i;
                FbxAMatrix transformoffset = mesh->GetNode()->EvaluateGlobalTransform(1.0) * geometryTransform;
                (*anim)->mGlobalTransform = transformoffset.Inverse() * cluster->GetLink()->EvaluateGlobalTransform(time);
                anim = &((*anim)->mNext);
            }
        }
    }

    return Mesh(dev, meshvertices, meshtexture);
}



FBXLOADER.H

class FBXCLoader
{
public:
    FBXCLoader(void);
    ~FBXCLoader(void);

    void LoadFBX(HWND hwnd, ID3D11Device *dev, ID3D11DeviceContext *devcon, const char* filename);

    void Draw(ID3D11DeviceContext *devcon);

    XMMATRIX GetAnimatedMatrix(int index);

    Skeleton skeleton;

private:
    FbxManager *fbxsdkManager;
    FbxScene *fbxScene;
    std::map<int, int> controlpoints;
    std::vector<Mesh> meshes;
    HWND hwnd;

    void ProcessNode(ID3D11Device *dev, ID3D11DeviceContext *devcon, FbxNode *node, FbxGeometryConverter *gConverter);

    Mesh ProcessMesh(ID3D11Device* dev, ID3D11DeviceContext *devcon, FbxMesh *mesh);

    void ProcessSkeletonHeirarchy(FbxNode* rootnode);

    void ProcessSkeletonHeirarchyre(FbxNode* node, int depth, int index, int parentindex);

    unsigned int FindJointIndex(const std::string& jointname);

    ID3D11ShaderResourceView *LoadTexture(ID3D11Device *dev, ID3D11DeviceContext *devcon, const char* texturefilename);

};
Advertisement

My article might have useful info, it was years ago I wrote it though and for .x format

https://www.gamedev.net/tutorials/programming/graphics/animating-characters-with-directx-r3632/

Doug

can you help me on fbx?

This topic is closed to new replies.

Advertisement