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\$
4
  • \$\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
    Commented Feb 22, 2015 at 12:41
  • \$\begingroup\$ It's an output of a shader \$\endgroup\$
    – D13
    Commented Feb 24, 2015 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
    Commented Feb 24, 2015 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
    Commented Feb 25, 2015 at 7:58

1 Answer 1

0
\$\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\$
2
  • \$\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
    Commented Feb 24, 2015 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\$ Commented Jun 24, 2015 at 6:15

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .