1
\$\begingroup\$

I'm having a problem understanding how to render the vertex data in fbx model into directx. This is my two functions and I've already triangulated all the mesh nodes.

bool FBXLoader::CopyVertexData(Mesh* mesh)
{
    FbxVector4 pos, nor;
    FbxNode* rootNode = mScene->GetRootNode();
    if (rootNode)
    {
        int iChildNodeCount = rootNode->GetChildCount();

        for (int i = 0; i < iChildNodeCount; i++)
        {
            // Child Node -> Object
            FbxNode* fbxChildNode = rootNode->GetChild(i);
            FbxMesh* fbxMesh = fbxChildNode->GetMesh();
            if (!fbxMesh)
                continue;
            int iVertexCount = fbxMesh->GetControlPointsCount();
            if (iVertexCount > 0)
            {
                SubMesh subMesh;
                int iPolyCount = fbxMesh->GetPolygonCount();
                for (int j = 0; j < iPolyCount; j++)
                {
                    // The poly size should be 3 since it's a triangle
                    int iPolySize = fbxMesh->GetPolygonSize(j);
                    // Get 3 vertices for the triangle
                    for (int k = 0; k < iPolySize; k++)
                    {
                        // Get index
                        int index = fbxMesh->GetPolygonVertex(j, k);
                        subMesh.indices.push_back(index);

                        // Get position
                        pos = fbxMesh->GetControlPointAt(index);
                        // Get normal
                        fbxMesh->GetPolygonVertexNormal(j, k, nor);

                        // Insert pos and nor data
                        Vertex vertex;
                        vertex.fPos = DirectX::XMFLOAT3((float)pos.mData[0], (float)pos.mData[1], (float)pos.mData[2]);
                        vertex.fNor = DirectX::XMFLOAT3((float)nor.mData[0], (float)nor.mData[1], (float)nor.mData[2]);
                        vertex.fTex = DirectX::XMFLOAT2(0.5f, 1.0f);
                        subMesh.vertices.push_back(vertex);
                    }
                }
                mesh->subMeshes.push_back(subMesh);
            }
        }
    }
    else
    {
        MessageBox(NULL, "Unable to create FBX Root Node object", "Error", MB_ICONERROR | MB_OK | MB_TASKMODAL);
        return false;
    }

    return true;
}

bool FBXLoader::CopyVertexDataTest(Mesh* mesh)
{
    FbxNode* rootNode = mScene->GetRootNode();
    if (rootNode)
    {
        int iChildNodeCount = rootNode->GetChildCount();

        for (int i = 0; i < iChildNodeCount; i++)
        {
            // Child Node -> Object
            FbxNode* fbxChildNode = rootNode->GetChild(i);
            FbxMesh* fbxMesh = fbxChildNode->GetMesh();
            if (!fbxMesh)
                continue;
            int iVertexCount = fbxMesh->GetControlPointsCount();
            if (iVertexCount > 0)
            {
                SubMesh subMesh;
                FbxVector4* pVertices = fbxMesh->GetControlPoints();
                for (int j = 0; j < iVertexCount; j++)
                {
                    Vertex vertex;
                    vertex.fPos = DirectX::XMFLOAT3((float)pVertices[j].mData[0], (float)pVertices[j].mData[1], (float)pVertices[j].mData[2]);
                    vertex.fNor = DirectX::XMFLOAT3(0.3f, 0.6f, 0.9f);
                    vertex.fTex = DirectX::XMFLOAT2(0.5f, 1.0f);
                    subMesh.vertices.push_back(vertex);
                }
                int iIndexCount = fbxMesh->GetPolygonVertexCount();
                //int* indices = new int[iIndexCount];
                int* indices = fbxMesh->GetPolygonVertices();
                for (int j = 0; j < iIndexCount; j++)
                {
                    subMesh.indices.push_back(indices[j]);
                }
                mesh->subMeshes.push_back(subMesh);
            }
        }
    }
    else
    {
        MessageBox(NULL, "Unable to create FBX Root Node object", "Error", MB_ICONERROR | MB_OK | MB_TASKMODAL);
        return false;
    }

    return true;
}

Here's the result using between those 2 functions. All images are the output of shader

CopyVertexData

Weird Mesh

CopyVertexDataTest Correct Mesh Data Wireframe

I exported the same model into .obj format for data checking between fbxMesh->GetControlPointAt(index) and fbxMesh->GetControlPoints(). So... my first question is why is it that GetControlPoints() gave me the same exact vertices data as the .obj data while GetControlPointsAt(...) gave different values?

Here's my second question. Let's use a cube model as an example case. A cube have 6 faces and each face have 6 vertices(2 triangles) which means a cube will have 12 triangles and 36 vertices. Assume that the cube have 6 polygon faces.

I load the cube fbx model and then I triangulate the mesh. I assumed that when I use GetPolygonCount(), I will get 12 triangulated polygons and each polygons will give 3 vertices. Is it wrong?

My solution

bool FBXLoader::CopyVertexData(Mesh* mesh)
{
    FbxVector4 pos, nor;
    FbxNode* rootNode = mScene->GetRootNode();
    if (rootNode)
    {
        int iChildNodeCount = rootNode->GetChildCount();

        for (int i = 0; i < iChildNodeCount; i++)
        {
            // Child Node -> Object
            FbxNode* fbxChildNode = rootNode->GetChild(i);
            FbxMesh* fbxMesh = fbxChildNode->GetMesh();
            if (!fbxMesh)
                continue;
            int iVertexCount = fbxMesh->GetControlPointsCount();
            if (iVertexCount > 0)
            {
                int indicesIndex = 0;
                SubMesh subMesh;
                // Get all positions
                FbxVector4* pVertices = fbxMesh->GetControlPoints();
                int iPolyCount = fbxMesh->GetPolygonCount();
                for (int j = 0; j < iPolyCount; j++)
                {
                    // The poly size should be 3 since it's a triangle
                    int iPolySize = fbxMesh->GetPolygonSize(j);
                    // Get 3 vertices of the triangle
                    for (int k = 0; k < iPolySize; k++)
                    {
                        // Get index
                        int index = fbxMesh->GetPolygonVertex(j, k);
                        subMesh.indices.push_back(indicesIndex++);

                        // Get normal
                        fbxMesh->GetPolygonVertexNormal(j, k, nor);

                        // Insert pos and nor data
                        Vertex vertex = Vertex();
                        vertex.fPos = DirectX::XMFLOAT3(static_cast<float>(pVertices[index].mData[0]), static_cast<float>(pVertices[index].mData[1]), static_cast<float>(pVertices[index].mData[2]));
                        vertex.fNor = DirectX::XMFLOAT3(static_cast<float>(nor.mData[0]), static_cast<float>(nor.mData[1]), static_cast<float>(nor.mData[2]));
                        vertex.fTex = DirectX::XMFLOAT2(0.0f, 0.0f);
                        subMesh.vertices.push_back(vertex);
                    }
                }
                mesh->subMeshes.push_back(subMesh);
            }
        }
    }
    else
    {
        MessageBox(NULL, "Unable to create FBX Root Node object", "Error", MB_ICONERROR | MB_OK | MB_TASKMODAL);
        return false;
    }

    return true;
}

Result

enter image description here

\$\endgroup\$
  • \$\begingroup\$ Could you describe what we see above in the first image? Is it the depth map or the output of a shader? \$\endgroup\$ – Robert Feb 22 '15 at 12:41
  • \$\begingroup\$ It's an output of a shader \$\endgroup\$ – D13 Feb 24 '15 at 8:40
  • \$\begingroup\$ Okay. If it still does not work check your input layout. The layout described at Device->CreateInputLayout must match the strides provided at DeviceContext->IASetVertexBuffers. \$\endgroup\$ – Robert Feb 24 '15 at 15:13
  • \$\begingroup\$ It's already matched the layout. My actual problem were caused by how I get the position data. Thanks for trying to help me :) \$\endgroup\$ – D13 Feb 25 '15 at 7:58
1
\$\begingroup\$

I had the same issues. Check if you are using LH or RH coordinate system. To use RH (what I would suggest since most tools do) create your projection matrix with :

XMMATRIX perspMatrix = XMMatrixPerspectiveFovRH(angle, aspect, 0.1f, 100.0f);
XMStoreFloat4x4(m_pProjMatrix, XMMatrixTranspose(perspMatrix));

and when setting up your rasterizer use :

D3D11_RASTERIZER_DESC desc;
desc.CullMode = D3D11_CULL_BACK;
desc.FrontCounterClockwise = true;

Otherwise you have to convert from RH to LH i.e. if you are importing .fbx from Maya

I think it would be more clever to copy all control points in advance (before traversing the mesh) by :

    auto axisSystem = fbxScene->GetGlobalSettings().GetAxisSystem();
    auto controlPoints = mesh->GetControlPoints();
    auto controlPointsCount = mesh->GetControlPointsCount();

    // Copy all control points
    for (auto cp = 0; cp < controlPointsCount; cp++)
    {
        auto point = controlPoints[cp];
        auto newVertex = new Vertex();
        newVertex->Position = ConvertFbxVector4ToXMFLOAT3(&point, axisSystem, 1.0f);
        vertices->push_back(*newVertex);
    }

whrere ConvertFbxVector4ToXMFLOAT3 is your on function to invert or change axis depending on the actual axis system. For normal RH coordinate systems (+Y-Up, + Z-Front), nothing has to be converted. Then you work on your copied verices like this :

    for (auto v = 0; v < polygonSize; v++)
    {
        auto vertexIndex = mesh->GetPolygonVertex(p, v);
        auto newVertex = new Vertex(vertices->at(vertexIndex));

        // Create the normal
        FbxVector4 normal;
        mesh->GetPolygonVertexNormal(p, v, normal);
        newVertex->Normal = XMFLOAT3
        {
            static_cast<float>(normal.mData[0]),
            static_cast<float>(normal.mData[1]),
            static_cast<float>(normal.mData[2])
        };

            // Use a standard color for all vertices
        newVertex->Color = XMFLOAT4
        {
            0.7f, 0.2f, 0.7f, 0.6f
        };

        // Dont set that now
        newVertex->UV = XMFLOAT2
        {
            0.0f, 0.0f
        };
        vertices->at(vertexIndex) = *newVertex;
        indices->push_back(vertexIndex);
    }

I will get 12 triangulated polygons and each polygons will give 3 vertices. Is it wrong?

No, you are right but I know what you mean. I've tried the same with Blender (creating cube and importing it as FBX) and what I got is 4 indices per polygon (4 * 6 = 24) instead of 3 (2 * 3 * 6 = 36) which afaik Direct3D does not accept.

\$\endgroup\$
  • \$\begingroup\$ I managed to fix the problem by following the way you copied the vertices. After checking through my .obj loader codes, I think I'm making a big mistake on how I construct my vertex data since there is only very few data to create the vertex buffer. Will post my new solution once I have the time to check my codes thoroughly and code a new one. \$\endgroup\$ – D13 Feb 24 '15 at 10:41
  • \$\begingroup\$ You might want to take a look at the Samples Content Exporter from the DirectX SDK, and DirectXMesh as well. \$\endgroup\$ – Chuck Walbourn Jun 24 '15 at 6:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.