0
votes

I'm in the process of writing a bit of code to load some models, as a part of this I want to add interleaved vertex data to a VBO, however I've noticed some strange behavior when I try to add the data to the Vertex Buffer, a couple of the submeshes do not render. The vertices and indices themselves are perfectly fine when the when I use a single VBO for each element (vvv, tt, nnn). However, with the interleaved VBO, if I use a 3D vector for my VBO's std::vector of data, the full mesh will draw correctly (albeit with the textures screwed up, likely from using a 3D rather than 2D vector). To draw the mesh, I am looping each of the submeshes and using glDrawElementsBaseVertex thusly:

glDrawElementsBaseVertex(GL_TRIANGLES,
    g_submeshes[i].numIndices,
    GL_UNSIGNED_INT,
    (void*)(sizeof(uint)* g_submeshes[i].baseIndex),
    g_submeshes[i].baseVertex);

Can you spot anything I've done wrong?

Model loading function:

void Sprite::InitMesh(uint p_meshIndex,
    const aiMesh* p_mesh,
    vector<aiVector3D>& p_posVec,
    vector<aiVector3D>& p_normVec,
    vector<aiVector2D>& p_uvVec,
    vector<VertexBoneData>& p_bones,
    vector<uint>& p_indices)
{
    const aiVector3D m_zero(0.0f, 0.0f, 0.0f);
    const int m_totalSize = sizeof(aiVector3D)* 2 + sizeof(aiVector2D);

    int m_totalVerts = 0;
    int m_totalIndices = 0;
    for (uint i=0; i < g_scene->mNumMeshes; ++i)
    {
        aiMesh* m_mesh = g_scene->mMeshes[i];
        int m_numFaces = m_mesh->mNumFaces;
        g_matIndices.push_back(m_mesh->mMaterialIndex);
        int m_prevSize = g_vertexBuffer[0].GetCurrentSize();
        g_meshIndices.push_back(m_prevSize / m_totalSize);

        g_submeshes[i].materialIndex = m_mesh->mMaterialIndex;
        g_submeshes[i].numIndices = m_mesh->mNumFaces * 3;
        g_submeshes[i].baseVertex = m_totalVerts;
        g_submeshes[i].baseIndex = m_totalIndices;
        for (unsigned int m = 0; m < m_mesh->mNumVertices; ++m) //Initialise the meshes in the scene
        {
            const aiVector3D* m_pos = &(m_mesh->mVertices[m]);
            const aiVector3D* m_normal = &(m_mesh->mNormals[m]);
            const aiVector3D* m_tex = m_mesh->HasTextureCoords(0) ? &(m_mesh->mTextureCoords[0][m]) : &m_zero;
            p_posVec.push_back(aiVector3D(m_pos->x, m_pos->y, m_pos->z));
            p_normVec.push_back(aiVector3D(m_normal->x, m_normal->y, m_normal->z));
            p_uvVec.push_back(aiVector2D(m_tex->x, m_tex->y));

            g_vertexBuffer[0].AddData(&p_posVec[m], sizeof(p_posVec[m]));
            g_vertexBuffer[0].AddData(&p_uvVec[m], sizeof(p_uvVec[m]));
            g_vertexBuffer[0].AddData(&p_normVec[m], sizeof(p_normVec[m]));
        }

        for (uint j = 0; j < m_numFaces; ++j)
        {
            const aiFace& m_face = m_mesh->mFaces[j];
            assert(m_face.mNumIndices == 3);
            for (uint k = 0; k < 3; ++k)
            {
                p_indices.push_back(m_face.mIndices[k]);
                g_vertexBuffer[1].AddData(&(m_face.mIndices[k]), sizeof(GLuint));
            }
        }
        int m_meshVerts = m_mesh->mNumVertices;
        m_totalVerts += m_meshVerts;
        g_meshSizes.push_back((g_vertexBuffer[0].GetCurrentSize() - m_prevSize) / m_totalSize);
        m_totalIndices += g_submeshes[i].numIndices;

    }
}

The AddData function:

void VertexBufferObject::AddData(void* p_ptr_data, UINT p_dataSize)
{
    g_data.insert(g_data.end(), static_cast<BYTE*>(p_ptr_data), static_cast<BYTE*>(p_ptr_data) + p_dataSize);
    g_dataSize += p_dataSize;
}

The upload to the GPU

void Sprite::FinalizeVBO()
{
    glGenVertexArrays(1, &g_VAO);
    glBindVertexArray(g_VAO);

    g_vertexBuffer[0].BindVBO();
    g_vertexBuffer[0].UploadDataToGPU(GL_STATIC_DRAW);  
    glEnableVertexAttribArray(POSITION_LOCATION);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 2 * sizeof(aiVector3D)+sizeof(aiVector2D), 0);
    // Texture coordinates
    glEnableVertexAttribArray(TEX_COORD_LOCATION);
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(aiVector3D)+sizeof(aiVector2D), (void*)sizeof(aiVector3D));
    // Normal vectors
    glEnableVertexAttribArray(NORMAL_LOCATION);
    glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 2 * sizeof(aiVector3D)+sizeof(aiVector2D), (void*)(sizeof(aiVector3D)+sizeof(aiVector2D)));
    g_vertexBuffer[1].BindVBO(GL_ELEMENT_ARRAY_BUFFER);
    g_vertexBuffer[1].UploadDataToGPU(GL_STATIC_DRAW);
    glBindVertexArray(0);
}
1

1 Answers

0
votes

You're adding new meshes, but using the same indices

{
   p_indices.push_back(m_face.mIndices[k]);
   g_vertexBuffer[1].AddData(&(m_face.mIndices[k]), sizeof(GLuint));
}

Say you have two meshes each consisting of one triangle... your vertex buffer looks like this:

[ V0, V1, V2, V3, V4, V5 ]

And your index buffer ends up looking like this:

[ 0, 1, 2, 0, 1, 2 ]

But you want it to look like this:

[ 0, 1, 2, 3, 4, 5 ]

That means that when you're adding the indices to the element array buffer you have to increment them by the count all the indices already seen, otherwise they'll point to previous meshes.