I have some code that loops through a set of objects and renders instances of those objects. The list of objects that needs to be rendered is stored as a std::map<MeshResource*, std::vector<MeshRendererer*>>, where an object of class MeshResource contains the vertices and indices with the actual data, and an object of classMeshRenderer defines the point in space the mesh is to be rendered at.
My rendering code is as follows:
glDisable(GL_BLEND);
glEnable(GL_CULL_FACE);
glDepthMask(GL_TRUE);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
for (std::map<MeshResource*, std::vector<MeshRenderer*> >::iterator it = renderables.begin(); it != renderables.end(); it++)
{
it->first->setupBeforeRendering();
cout << "<";
for (unsigned long i =0; i < it->second.size(); i++)
{
//Pass in an identity matrix to the vertex shader- used here only for debugging purposes; the real code correctly inputs any matrix.
uniformizeModelMatrix(Matrix4::IDENTITY);
/**
* StartHere fix rendering problem.
* Ruled out:
* Vertex buffers correctly.
* Index buffers correctly.
* Matrices correct?
*/
it->first->render();
}
it->first->cleanupAfterRendering();
}
geometryPassShader->disable();
glDepthMask(GL_FALSE);
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
The function in MeshResource that handles setting up the uniforms is as follows:
void MeshResource::setupBeforeRendering()
{
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
glEnableVertexAttribArray(3);
glEnableVertexAttribArray(4);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, iboID);
glBindBuffer(GL_ARRAY_BUFFER, vboID);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), 0); // Vertex position
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid*) 12); // Vertex normal
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid*) 24); // UV layer 0
glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid*) 32); // Vertex color
glVertexAttribPointer(4, 1, GL_UNSIGNED_SHORT, GL_FALSE, sizeof(Vertex), (const GLvoid*) 44); //Material index
}
The code that renders the object is this:
void MeshResource::render()
{
glDrawElements(GL_TRIANGLES, geometry->numIndices, GL_UNSIGNED_SHORT, 0);
}
And the code that cleans up is this:
void MeshResource::cleanupAfterRendering()
{
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glDisableVertexAttribArray(2);
glDisableVertexAttribArray(3);
glDisableVertexAttribArray(4);
}
The end result of this is that I get a black screen, although the end of my rendering pipeline after the rendering code (essentially just drawing axes and lines on the screen) works properly, so I'm fairly sure it's not an issue with the passing of uniforms. If, however, I change the code slightly so that the rendering code calls the setup immediately before rendering, like so:
void MeshResource::render()
{
setupBeforeRendering();
glDrawElements(GL_TRIANGLES, geometry->numIndices, GL_UNSIGNED_SHORT, 0);
}
The program works as desired. I don't want to have to do this, though, as my aim is to set up vertex, material, etc. data once per object type and then render each instance updating only the transformation information.
The uniformizeModelMatrix works as follows:
void RenderManager::uniformizeModelMatrix(Matrix4 matrix)
{
glBindBuffer(GL_UNIFORM_BUFFER, globalMatrixUBOID);
glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(Matrix4), matrix.ptr());
glBindBuffer(GL_UNIFORM_BUFFER, 0);
}
Related
I have an application displaying some 3D rendering.
I encounter some graphical problems with VBO, when integrating my application on different user's laptops. Vertex Buffer Object work perfectly fine in out development stations
First laptop embeds a AMD Radeon HD 6470M -> OpenGL 4.1
On this laptop, I've got some :
old fashion way opengl code, working fine.
vbo implemented : No data of the VBO is displayed
Here the code responsible of the drawing of my VBO :
// Compute this on the client side to attempt compute it for each vertex
Matrix4 modelview = view * model;
// Links matrix values to entry shader matrices for the specified shader
glUniformMatrix4fv(glGetUniformLocation(shaderID, "projection"), 1, GL_TRUE, projection.getValues());
glUniformMatrix4fv(glGetUniformLocation(shaderID, "modelview"), 1, GL_TRUE, modelview.getValues());
GLfloat color[4] = {material_->getDiffuse()[0], material_->getDiffuse()[1], material_->getDiffuse()[2], lgc3d::alphaFromSelection(selected)};
glUniform4fv(glGetUniformLocation(shaderID, "color"), 1, color);
// Get the positions in the shader for data
glEnableVertexAttribArray(VPos_index);
glEnableVertexAttribArray(VNor_index);
glEnableVertexAttribArray(VTex_index);
// Bind the buffers we want access
glBindBuffer(GL_ARRAY_BUFFER, VBO_index_vertices);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, VBO_index_indices3);
glBindTexture(GL_TEXTURE_2D, material_->getTexture().getID());
{
// Precise how the data have to be read by OpenGL (defining offset), for triangles
glVertexAttribPointer(VPos_index, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), BUFFER_OFFSET(0));
glVertexAttribPointer(VNor_index, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), BUFFER_OFFSET(offsetof(Vertex, normals)));
glVertexAttribPointer(VTex_index, 2, GL_FLOAT, GL_TRUE, sizeof(Vertex), BUFFER_OFFSET(offsetof(Vertex, textcoords)));
glDrawElements(GL_TRIANGLES, nb_tri_ * 3, GL_UNSIGNED_INT, 0);
}
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, VBO_index_indices4);
{
// Precise how the data have to be read by OpenGL (defining offset), for quads
glVertexAttribPointer(VPos_index, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), BUFFER_OFFSET(0));
glVertexAttribPointer(VNor_index, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), BUFFER_OFFSET(offsetof(Vertex, normals)));
glVertexAttribPointer(VTex_index, 2, GL_FLOAT, GL_TRUE, sizeof(Vertex), BUFFER_OFFSET(offsetof(Vertex, textcoords)));
glDrawElements(GL_QUADS, nb_qua_ * 4, GL_UNSIGNED_INT, 0);
}
// Unbind everything
glDisableVertexAttribArray(VPos_index);
glDisableVertexAttribArray(VNor_index);
glDisableVertexAttribArray(VTex_index);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindTexture(GL_TEXTURE_2D, 0);
Do I use any too recent function ? I really don't have this feeling.
The non-VBO objects are displayed perfectly:
{
// defines an array of generic vertex attribute data, of index 0
glEnableVertexAttribArray(0);
// Get eye position
Vector3D eyev(cam->getEyePosition());
float eyet[3] = {(float)eyev.X, (float)eyev.Y, (float)eyev.Z};
// Specify data location for OpenGL
glVertexAttribPointer(0, 3, GL_DOUBLE, GL_FALSE, 0, vertices_);
// Links matrix values to entry shader matrices for the specified shader
glUniformMatrix4fv(glGetUniformLocation(shaderID, "projection"), 1, GL_TRUE, projection.getValues());
glUniformMatrix4fv(glGetUniformLocation(shaderID, "modelview"), 1, GL_TRUE, modelview.getValues());
glUniform3fv(glGetUniformLocation(shaderID, "cameraEye"), 1, eyet);
glLineWidth(1);
// Order OpenGL to draw
glDrawArrays(GL_LINES, 0, nb_coord_ / 3);
// Inactivates the generic vertex attribute data of index 0
glDisableVertexAttribArray(0);
}
Second laptop embeds a Intel Graphic 3000 -> OpenGL 3.0
Here, if I only drop the mouse over the OpenGL canevas, it crashes. Nothing is never displayed... even the background clearing color.
I spent attention do not to use deprecated functions and I really thought that everything would be compatible with a huge bunch a computers/laptops. Does anyone have any idea ?
Everything is displayed in a QGLWidget, with Qt5.8. Problems happens on 64bits platforms, tested on Windows 7 Professional.
actually Im a bit confused about using glBufferSubData and glMapBuffer. In my program I'm loading a mesh of Triangles so i created a Struct of Vertex and initialized my VertexBuffer with the data of whole mesh. I implemented ray-casting and ray-triangle intersection. What im trying to do is, if my cursor intersects with the mesh, the intersected triangle changes his color as long its get intersected. Its working at the moment but when I try to load a bigger mesh with 50.000+ Vertices it doesnt work anymore. I am updating my whole VBO with glBufferData because I dont understand how I can update only Color of Triangles with glBufferSubData. Can someone explain me how I can update only the specific part (e.g. Color) of my VBO ?
struct Vertex
{
glm::vec3 Pos;
glm::vec3 Normal;
glm::vec3 Color;
};
VertexBuffer(void* vertices, size_t size)
{
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER, size, vertices, GL_DYNAMIC_DRAW);
glBindVertexArray(0);
}
void Render()
{
glBindVertexArray(vertexBuffer->VAO);
glUseProgram(Fill->program);
glUniformMatrix4fv(glGetUniformLocation(Fill->program, "model"), 1, GL_FALSE, glm::value_ptr(model));
glUniformMatrix4fv(glGetUniformLocation(Fill->program, "view"), 1, GL_FALSE, glm::value_ptr(view));
glUniformMatrix4fv(glGetUniformLocation(Fill->program, "projection"), 1, GL_FALSE, glm::value_ptr(proj));
for (int j = 0; j < numVertices; j += 3){
if (intersectPlane(this->Vertices[j], this->Vertices[j + 1], this->Vertices[j + 2], ray, orig)){
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer->buffer);
this->Vertices[j].Color = glm::vec3(1.0, 0.0, 0.0);
this->Vertices[j + 1].Color = glm::vec3(1.0, 0.0, 0.0);
this->Vertices[j + 2].Color = glm::vec3(1.0, 0.0, 0.0);
glBufferData(GL_ARRAY_BUFFER, numVertices * sizeof(Vertex), Vertices, GL_DYNAMIC_DRAW);
}
else{
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer->buffer);
this->Vertices[j].Color = glm::vec3(0.695f, 0.695f, 0.695f);
this->Vertices[j + 1].Color = glm::vec3(0.695f, 0.695f, 0.695f);
this->Vertices[j + 2].Color = glm::vec3(0.695f, 0.695f, 0.695f);
glBufferData(GL_ARRAY_BUFFER, numVertices * sizeof(Vertex), Vertices, GL_DYNAMIC_DRAW);
}
}
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer->buffer);
GLuint posLoc = glGetAttribLocation(Fill->program, "Position");
GLuint norm = glGetAttribLocation(Fill->program, "Normal");
GLuint colo = glGetAttribLocation(Fill->program, "Color");
glVertexAttribPointer(posLoc, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, Pos));
glVertexAttribPointer(norm, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, Normal));
glVertexAttribPointer(colo, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, Color));
glEnableVertexAttribArray(posLoc);
glEnableVertexAttribArray(norm);
glEnableVertexAttribArray(colo);
glDrawArrays(GL_TRIANGLES, 0, numVertices);
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glUseProgram(0);
}
glBufferSubData updates part (or the whole) of the buffer without the need to recreate it.
In your case you can do some calculus to know the position in bytes inside the buffer (so called "offset") of the edge currently selected, and update the buffer just for that pair of vertices.
glMapBuffer gives you a (virtual) pointer to the buffer. You can read or write to that address directly using your C/C++ functions. Be aware to "unmap" when done.
Now, your buffer layout is Pos,Normal,Color and repeat. So: PxPyPzNxNyNzCrCgCbPxPyPzNxNyNzCrCgCbPxPyPzNxNyNzCrCgCb... "interleaved data". You must be carefull with the positions (bytes) you update.
I've just started learning opengl and I was trying to implement VBOs.
this is what I'm doing:
in the main method before I iterate, for each mesh I initialize its VBOs.
The mesh->pos and mesh->norm contain the points and the normals of the triangles and the quads of the mesh.
The mesh->triangle and mesh->quad contain the indices.
for (auto mesh : scene->meshes)
{
mesh->vboPos = 0;
glGenBuffers (1, &mesh->vboPos);
glBindBuffer (GL_ARRAY_BUFFER, mesh->vboPos);
glBufferData (GL_ARRAY_BUFFER, 3 * mesh->pos.size() * sizeof(GL_FLOAT), mesh->pos.data(), GL_STATIC_DRAW);
mesh->vboNorm = 0;
glGenBuffers (1, &mesh->vboNorm);
glBindBuffer (GL_ARRAY_BUFFER, mesh->vboNorm);
glBufferData (GL_ARRAY_BUFFER, 3 * mesh->norm.size() * sizeof(GL_FLOAT), mesh->norm.data(), GL_STATIC_DRAW);
mesh->vbiTriangle = 0;
glGenBuffers (1, &mesh-> vbiTriangle);
glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, mesh-> vbiTriangle);
glBufferData (GL_ELEMENT_ARRAY_BUFFER, 3 * mesh->triangle.size() * sizeof(GL_UNSIGNED_INT), mesh->triangle.data(), GL_STATIC_DRAW);
mesh->vbiQuad = 0;
glGenBuffers (1, &mesh->vbiQuad);
glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, mesh->vbiQuad);
glBufferData (GL_ELEMENT_ARRAY_BUFFER, 4 * mesh->quad.size() * sizeof(GL_UNSIGNED_INT), mesh->quad.data(), GL_STATIC_DRAW);
}
while(not glfwWindowShouldClose(window))
{
...
}
After this inside the shade method I call the draw for each mesh I have. This is how the mesh code looks like:
struct Mesh {
frame3f frame = identity_frame3f; // frame
vector<vec3f> pos; // vertex position
vector<vec3f> norm; // vertex normal
vector<vec3i> triangle; // triangle
vector<vec4i> quad; // quad
Material* mat = new Material(); // material
GLuint vboPos = 0;
GLuint vboNorm = 0;
GLuint vbiTriangle =0;
GLuint vbiQuad =0;
int count = 0;
void draw()
{
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, vboPos);
glBindBuffer(GL_ARRAY_BUFFER, vboNorm);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbiTriangle);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbiQuad);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, 0);
glDrawElements(GL_TRIANGLES, triangle.size() * 3, GL_UNSIGNED_INT, 0);
glDrawElements(GL_QUADS, quad.size() * 4, GL_UNSIGNED_INT, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
}
I don't really know what's the problem causing this, but I'm pretty sure I didn't understand something of how VBOs work. Can you enlighten me?
You are trying to do too many things at once here and I have a feeling the driver is overrunning an array trying to read the wrong element array.
Your draw function needs to be re-written:
void draw()
{
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
/* Setup your Position array */
glBindBuffer(GL_ARRAY_BUFFER, vboPos);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
/* Then setup your Normal array */
glBindBuffer(GL_ARRAY_BUFFER, vboNorm);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, 0);
/* DO NOT DO THIS -- you are using generic vertex attributes. */
//glEnableClientState(GL_VERTEX_ARRAY);
/* First the Triangles */
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbiTriangle);
glDrawElements(GL_TRIANGLES, triangle.size() * 3, GL_UNSIGNED_INT, 0);
/* Now the Quads */
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbiQuad);
glDrawElements(GL_QUADS, quad.size() * 4, GL_UNSIGNED_INT, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
}
I have a model class which contains the buffers for the model to draw, it's implementation looks like this:
Model::Model(std::vector<Vertex> vertices, std::vector<short> indices)
{
mVertices = vertices;
mIndices = indices;
mMatrix = glm::mat4(1.0f);
mIsTextured = false;
Initialize();
}
Model::~Model()
{
glDeleteBuffers(1, &mVertexBuffer);
glDeleteBuffers(1, &mIndiceBuffer);
}
void Model::Initialize()
{
glGenBuffers(1, &mVertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, mVertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex)*mVertices.size(), &mVertices[0], GL_STATIC_DRAW);
glGenBuffers(1, &mIndiceBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mIndiceBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(short)*mIndices.size(), &mIndices[0], GL_STATIC_DRAW);
}
Now I've encountered a very weird problem with the destructor, I use this class like this:
Renderer *renderer = new Renderer();
Model m = parseSKNFromFile("model.skn");
m.ApplyTexture(textureID);
while (!glfwWindowShouldClose(window))
{
update();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
renderer->RenderModel(&m);
glfwSwapBuffers(window);
glfwPollEvents();
}
Using the Model class this way triggers a runtime Access Violation Reading Location error, but if I comment the glDeleteBuffers call inside the constructor everything working find.
It looks like somehow those delete functions called out of nowhere and I cant figure out how and why.
Here's the RenderModel function too:
mShader.bind();
glm::mat4 MVP = mProjection * glm::lookAt(glm::vec3(0, 100, 200), glm::vec3(0, 100, 0), glm::vec3(0, 1, 0)) * model->GetMatrix();
glUniformMatrix4fv(mShader.getUniformLocation("MVP") , 1, GL_FALSE, &MVP[0][0]);
if (model->IsTextured())
{
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, model->GetTexture());
glUniform1i(model->GetTexture(), 0);
}
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
glEnableVertexAttribArray(3);
glEnableVertexAttribArray(4);
glBindBuffer(GL_ARRAY_BUFFER, model->GetVertexBuffer());
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)0); //float position[3]
glVertexAttribPointer(1, 1, GL_INT, GL_FALSE, sizeof(Vertex), (void*)12); //char boneIndex[4]
glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)16); //float weights[4]
glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)32); //float normals[3]
glVertexAttribPointer(4, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)44); //float textureCords[2]
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, model->GetIndiceBuffer());
glDrawElements(GL_TRIANGLES, model->GetIndiceSize(), GL_UNSIGNED_SHORT, (void*)0);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glDisableVertexAttribArray(2);
glDisableVertexAttribArray(3);
glDisableVertexAttribArray(4);
An assumption: You do not have (can not have) a proper copy constructor/assignment operator.
Hence:
private;
Model(const Model&); // No copy
Model& operator = (const Model&); // No copy
Since you are creating an inline object of Model it will be destroyed automatically when it goes out of scope and that scope is at the end of the function where you instantiate a Renderer.
I would suggest changing the Model to a heap allocated object and destroy it manually before you free the Renderer and before you destroy the window.
Model* m = parseSKNFromFile( "model.skn" );
There are some other suggestions that I would make like taking the arrays of indices and vertices as const references in the constructor of the Model. Also I don't think it is a great idea to call gl commands from the destructor of the object, it would be better to separate that type of functionality to separate functions in the Model as well as not initialize the OpenGL buffers in the constructor either. The reasons for that is in case you want to separate object allocation from the renderer initialization so that you can be loading them on a separate thread from the rendering thread.
I'm working on a 3D model loader. It can loads my own format. I wrote my own exporter for Blender, it works well. The model format can handle multiple meshes(objects) in one model. Each mesh can have a different texture. I've already written a loader which is working well, but doesn't use shaders.
I switched to shaders, but something is going wrong, the textures aren't appear correctly. Here is my drawing function, I'm sure the mistake is somewhere here:
void CModel::draw(glm::mat4 &MVP)
{
glActiveTexture(GL_TEXTURE0);
glEnable(GL_TEXTURE_2D);
for(unsigned int i=0; i<m_numObjects; i++)
{
glUseProgram(m_programID);
glUniformMatrix4fv(m_matrixUniform, 1, GL_FALSE, &MVP[0][0]);
glBindTexture(GL_TEXTURE_2D, m_textureIDs[i]);
glUniform1i(m_textureUniform, 0);
glBindBuffer(GL_ARRAY_BUFFER, m_bufferIDs[i]);
// vertices
glEnableVertexAttribArray(0);
glVertexAttribPointer(
0, // must match the layout in the shader.
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
sizeof(float)*8, // stride
(void*)0 // array buffer offset
);
// UVs
glEnableVertexAttribArray(1);
glVertexAttribPointer(
1,
2,
GL_FLOAT,
GL_FALSE,
sizeof(float)*8,
(void*)6
);
glDrawArrays(GL_TRIANGLES, 0, m_numElements[i]);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glUseProgram(0);
}
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glDisable(GL_TEXTURE_2D);
}
The vertex and fragment shaders are also working well.
The previous version (without shaders) was this (this worked well):
void CModel::draw()
{
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_VERTEX_ARRAY);
glClientActiveTexture(GL_TEXTURE0);
glActiveTexture(GL_TEXTURE0);
glEnable(GL_TEXTURE_2D);
for(unsigned int i=0; i<m_numObjects; i++)
{
glBindTexture(GL_TEXTURE_2D, m_textureIDs[i]);
glBindBuffer(GL_ARRAY_BUFFER, m_bufferIDs[i]);
glTexCoordPointer(2, GL_FLOAT, sizeof(float)*8, (float*)(sizeof(float)*6));
glNormalPointer( GL_FLOAT, sizeof(float)*8, (float*)(sizeof(float)*3));
glVertexPointer( 3, GL_FLOAT, sizeof(float)*8, 0);
glDrawArrays(GL_TRIANGLES, 0, m_numElements[i]);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisable(GL_TEXTURE_2D);
}
Here is the entire class:
#include "global.h"
#include "CModel.h"
#include "CModelLoader.h"
#include "CShaderLoader.h"
CModel::CModel(){}
CModel::~CModel()
{
// TODO free memory
}
/** #brief Load mbm file
*
* #fileName: mdm model file name we want to load and draw
*/
void CModel::init(char *fileName)
{
CModelLoader loader;
CShaderLoader shaders;
loader.loadData(fileName);
loader.createDataArray( m_dataArray,
m_dataArraySizes,
m_numObjects,
m_numElements,
m_textureIDs );
glGenVertexArrays(1, &m_vertexArrayID);
glBindVertexArray(m_vertexArrayID);
m_programID = shaders.loadShaders("vertexshader.vert", "fragmentshader.frag");
m_bufferIDs = new unsigned int[m_numObjects];
glGenBuffers(m_numObjects, m_bufferIDs);
for(unsigned int i=0; i<m_numObjects; i++)
{
glBindBuffer(GL_ARRAY_BUFFER, m_bufferIDs[i]);
glBufferData(GL_ARRAY_BUFFER, sizeof(float)*m_dataArraySizes[i], m_dataArray[i], GL_STATIC_DRAW);
}
}
/** #brief Drawing the mdm model
*
*/
void CModel::draw(glm::mat4 &MVP)
{
glEnable(GL_TEXTURE_2D);
glActiveTexture(GL_TEXTURE0);
for(unsigned int i=0; i<m_numObjects; i++)
{
glUseProgram(m_programID);
unsigned int matrixUniform = glGetUniformLocation(m_programID, "MVP");
unsigned int textureUniform = glGetUniformLocation(m_programID, "myTextureSampler");
glUniformMatrix4fv(matrixUniform, 1, GL_FALSE, &MVP[0][0]);
glUniform1i(textureUniform, 0);
glBindTexture(GL_TEXTURE_2D, m_textureIDs[i]);
glBindBuffer(GL_ARRAY_BUFFER, m_bufferIDs[i]);
// vertices
glEnableVertexAttribArray(0);
glVertexAttribPointer(
0, // must match the layout in the shader.
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
sizeof(float)*8, // stride
(void*)0 // array buffer offset
);
// UVs
glEnableVertexAttribArray(1);
glVertexAttribPointer(
1,
2,
GL_FLOAT,
GL_FALSE,
sizeof(float)*8,
(void*)6
);
glDrawArrays(GL_TRIANGLES, 0, m_numElements[i]);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glUseProgram(0);
}
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glDisable(GL_TEXTURE_2D);
}
Finally I solved it. The problem was that I used one array for vertices, normals and texture coordinates instead of storing in separate arrays and bind them separately.