2
\$\begingroup\$

I've imported control points, normals, and indices successfully and now i'm trying to import vertex colors, but something is not right. Here's the code:

        FbxLayerElementMaterial* pMaterialLayer = layer->GetMaterials();
        int numMatIndices = pMaterialLayer->GetIndexArray().GetCount();

        GLfloat *colors = new GLfloat[numMatIndices * 9];

        for (int i = 0; i <numMatIndices; i++)
        {
            //int matIndex = array->operator[](i);
            int matIndex  = pMaterialLayer->GetIndexArray()[i];

            FbxSurfaceMaterial *smat = mesh->GetNode()->GetMaterial(matIndex);
            if (smat->GetClassId().Is(FbxSurfaceLambert::ClassId))
            {
                FbxSurfaceLambert *lam = (FbxSurfaceLambert*)smat;

                FbxPropertyT<FbxDouble3> p = lam->Diffuse;
                FbxDouble3 info = p.Get();

                for (int j = 0; j < 3; j++)
                {
                    colors[i * 9 + j * 3 + 0] = (GLfloat)info[0];
                    colors[i * 9 + j * 3 + 1] = (GLfloat)info[1];
                    colors[i * 9 + j * 3 + 2] = (GLfloat)info[2];
                }
            }
        }

Here's what I exported from max, and what I got in my OpenGL application. enter image description here

I was inspecting memory dump and all colors are like they should be (in the order material indices were written in fbx file). Three SAME colors for three vertices in one triangle (total nine floats for one triangle). How is it even possible to have different vertex colors in one triangle?

Does it have something to do because I'm using index buffer for drawing vertices? My VertexBufferObject contains vertex positions, normals, indices, and colors. I'm drawing with glDrawElements call.

Can anyone help me with this?

@EDIT For those who asked, here's whole method for importing mesh:

bool Mesh::Create(FbxMesh *mesh)
{
    FbxScene *scene = mesh->GetScene();
    FbxAnimEvaluator *eval = scene->GetAnimationEvaluator();
    FbxMatrix transform = eval->GetNodeGlobalTransform(mesh->GetNode());
    glm::mat4x4 glmMat = FbxMatToGlm(transform);

    // *************** VERTEX POSITIONS ***************

    int numVertices = mesh->GetControlPointsCount();
    GLfloat *vertices = new GLfloat[numVertices * 3];
    for (int i = 0; i < numVertices; i++)
    {
        FbxVector4 vec = transform.MultNormalize(mesh->GetControlPointAt(i));

        vertices[i * 3 + 0] = (GLfloat)vec.mData[0];
        vertices[i * 3 + 1] = (GLfloat)vec.mData[1];
        vertices[i * 3 + 2] = (GLfloat)vec.mData[2];
    }

    glGenBuffers(1, &vertexBuffer);
    glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
    glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat)* 3 * numVertices, vertices, GL_STATIC_DRAW);

    delete[] vertices;

    // ****************** INDICES ***************

    numIndices = mesh->GetPolygonVertexCount();
    int *indices = mesh->GetPolygonVertices();

    glGenBuffers(1, &indexBuffer);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(int)* numIndices, indices, GL_STATIC_DRAW);

    delete[] indices;

    // *********** NORMALS *********

    FbxGeometryElementNormal *normalElement = mesh->GetElementNormal();
    if (normalElement)
    {
        int numNormals = mesh->GetPolygonCount() * 3;
        GLfloat *normals = new GLfloat[numNormals * 3];

        int vertexCounter = 0;

        for (int polyCounter = 0; polyCounter < mesh->GetPolygonCount(); polyCounter++)
        {
            for (int i = 0; i < 3; i++)
            {
                FbxVector4 normal = normalElement->GetDirectArray().GetAt(vertexCounter);

                glm::vec4 glmNormal = FbxVecToGlm(normal);
                glmNormal = glmMat * glmNormal;

                normals[vertexCounter * 3 + 0] = (GLfloat)glmNormal[0];
                normals[vertexCounter * 3 + 1] = (GLfloat)glmNormal[1];
                normals[vertexCounter * 3 + 2] = (GLfloat)glmNormal[2];

                vertexCounter++;
            }
        }

        glGenBuffers(1, &normalsBuffer);
        glBindBuffer(GL_ARRAY_BUFFER, normalsBuffer);
        glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat)* 3 * numNormals, normals, GL_STATIC_DRAW);

        delete[] normals;


    }
    // ********* COLORS *************

    FbxLayer *layer = mesh->GetLayer(0);
    FbxLayerElementMaterial* pMaterialLayer = layer->GetMaterials();
    int numMatIndices = pMaterialLayer->GetIndexArray().GetCount();

    GLfloat *colors = new GLfloat[numMatIndices * 9];

    for (int i = 0; i < numMatIndices; i++)
    {
        //int matIndex = array->operator[](i);
        int matIndex = pMaterialLayer->GetIndexArray()[i];

        FbxSurfaceMaterial *smat = mesh->GetNode()->GetMaterial(matIndex);
        if (smat->GetClassId().Is(FbxSurfaceLambert::ClassId))
        {
            FbxSurfaceLambert *lam = (FbxSurfaceLambert*)smat;

            FbxPropertyT<FbxDouble3> p = lam->Diffuse;
            FbxDouble3 info = p.Get();

            for (int j = 0; j < 3; j++)
            {
                colors[i * 9 + j * 3 + 0] = (GLfloat)info[0];
                colors[i * 9 + j * 3 + 1] = (GLfloat)info[1];
                colors[i * 9 + j * 3 + 2] = (GLfloat)info[2];
            }
        }
    }

    glGenBuffers(1, &colorsBuffer);
    glBindBuffer(GL_ARRAY_BUFFER, colorsBuffer);
    glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat)* 9 * numMatIndices, colors, GL_STATIC_DRAW);

    delete[] colors;



    glGenVertexArrays(1, &vao);
    glBindVertexArray(vao);

    glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);

    glBindBuffer(GL_ARRAY_BUFFER, colorsBuffer);
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, 0);

    glBindBuffer(GL_ARRAY_BUFFER, normalsBuffer);
    glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, 0);

    glEnableVertexAttribArray(0);
    glEnableVertexAttribArray(1);
    glEnableVertexAttribArray(2);

    return true;
}
\$\endgroup\$
  • \$\begingroup\$ Of course it's possible to have different vertex colors in one triangle, that's why they're called vertex colors and not triangle colors. :) Anyway, can you show how you're building the vertex buffer? You're presumably looking up the wrong colors from the material list when you're building the vertices. \$\endgroup\$ – Nathan Reed Jun 18 '14 at 5:09
  • \$\begingroup\$ might be normals pointing into wrong direction \$\endgroup\$ – Lufi Jun 18 '14 at 7:20
  • \$\begingroup\$ @NathanReed Of course I know that triangles can have different vertex colors, what I meant is how is it possible here, when I packed them into the buffer in that way that each three consecutive colors are the same. I guess it HAS to do something with vertex index buffer. I posted whole method. Thanks! \$\endgroup\$ – instancedName Jun 18 '14 at 11:33
  • \$\begingroup\$ OK, there's definitely something missing here. It looks like the arrays of positions, normals, and colors are being generated with different sizes and coming from totally different data structures. I don't know how FBX files work so I can't tell you exactly how to fix it, but for rendering you would need to generate vertex buffers where all the components - position, normal, and color - have the same number of vertices, and are indexed by the same indices. In other words you can't have separate indices for positions, normals, and colors like this code seems to be using. \$\endgroup\$ – Nathan Reed Jun 18 '14 at 19:47
  • \$\begingroup\$ @NathanReed I checked it right now. There are total of 36 vertices, 36 indices, 36 normals, and 36 colors. Kinda makes me question myself what's the point of indices if there are same number of them and vertices. But never mind that, mesh is drawing fine except for colors, which means that index buffer is indexing those buffers as it should, it just seems that colors are not placed in their buffer as they should be. I don't use separate indices for drawing, but I am using fbx's material indices to get colors from the file. It seems they are not really consistent. \$\endgroup\$ – instancedName Jun 18 '14 at 22:06
1
\$\begingroup\$

Beside the potentially wrong color you are seeing, it really looks like you also have normal issue witht the way I see the gradient being done on the triangle. I had something similar happening to me in the past, and it was the normals that were incorrect because I wasn't checking the mapping mode and reference mode of the my normal elements before fetching the values. I wonder if you have the same issue because you are also not checking either before doing this:

FbxVector4 normal = normalElement->GetDirectArray().GetAt(vertexCounter);

You can only do this if your normalElement mapping mode is FbxGeometryElement::eByPolygonVertex and if its reference mode is FbxGeometryElement::eDirect. This might be the reason why your normals look incorrect (if they are indeed incorrect).

Try doing the following to get your normals:

int vertexCounter = 0;

for (int polyCounter = 0; polyCounter < mesh->GetPolygonCount(); polyCounter++)
{
    int polygonSize = mesh->GetPolygonSize(polyCounter);
    for (int i = 0; i < polygonSize; i++)
    {
        FbxVector4 normal;
        switch (normalElement->GetMappingMode())
        {
            case FbxGeometryElement::eByControlPoint:
            {
                int controlPointId = mesh->GetPolygonVertex(polyCounter, i);
                switch(normalElement->GetReferenceMode())
                {
                    case FbxGeometryElement::eDirect:
                    {
                        normal = normalElement->GetDirectArray().GetAt(controlPointId);
                        break;
                    }
                    case FbxGeometryElement::eIndexToDirect:
                    {
                        normalIndex = normalElement->GetIndexArray().GetAt(controlPointId);
                        normal = normalElement->GetDirectArray().GetAt(controlPointId);
                        break;
                    }
                    default:
                    {
                        break;
                    }
                }
                break;
            }
            case FbxGeometryElement::eByPolygonVertex:
            {
                switch(normalElement->GetReferenceMode())
                {
                    case FbxGeometryElement::eDirect:
                    {
                        normal = normalElement->GetDirectArray().GetAt(vertexCounter);
                        break;
                    }
                    case FbxGeometryElement::eIndexToDirect:
                    {
                        normalIndex = normalElement->GetIndexArray().GetAt(vertexCounter);
                        normal = normalElement->GetDirectArray().GetAt(normalIndex);
                        break;
                    }
                    default:
                    {
                        break;
                    }
                }
                break;
            }
            default:
            {
                break;
            }
        }

        glm::vec4 glmNormal = FbxVecToGlm(normal);
        glmNormal = glmMat * glmNormal;

        normals[vertexCounter * 3 + 0] = (GLfloat)glmNormal[0];
        normals[vertexCounter * 3 + 1] = (GLfloat)glmNormal[1];
        normals[vertexCounter * 3 + 2] = (GLfloat)glmNormal[2];

        vertexCounter++;
    }
}

Make sure FbxVecToGlm doesn't do any funny business and free of typos/bugs.

As for the color, I can't really tell if what you are doing is correct or not since I don't have a lot of experience dealing with FbxSurfaceLambert. I usually get my vertex colors this way (very similar to the way I get my normals):

const FbxGeometryElementVertexColor* colorElement = mesh->GetElementVertexColor();

FbxColor color;
switch (colorElement->GetMappingMode())
{
    case FbxGeometryElement::eByControlPoint:
    {
        switch (colorElement->GetReferenceMode())
        {
            case FbxGeometryElement::eDirect:
            {
                color = colorElement->GetDirectArray().GetAt(controlPointId);
                break;
            }
            case FbxGeometryElement::eIndexToDirect:
            {
                int id = colorElement->GetIndexArray().GetAt(controlPointId);
                color = colorElement->GetDirectArray().GetAt(id);
                break;
            }
            default:
            {
                break;
            }
        }
        break;
    }
    case FbxGeometryElement::eByPolygonVertex:
    {
        switch (colorElement->GetReferenceMode())
        {
            case FbxGeometryElement::eDirect:
            {
                color = colorElement->GetDirectArray().GetAt(vertexId);
                break;
            }
            case FbxGeometryElement::eIndexToDirect:
            {
                int id = colorElement->GetIndexArray().GetAt(vertexId);
                color = colorElement->GetDirectArray().GetAt(id);
                break;
            }
            default:
            {
                break;
            }
        }
        break;
    }
    default:
    {
        break;
    }
}

Hopefully, that info will help you and/or someone else. It could very well be something else that is messing up your colors (and normals).

Good luck!

\$\endgroup\$

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.