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);
}