Reputation: 3311
I have an Eigen::MatrixXf with vertices (N*3) and faces (N*3) as variables mvTemp2 and mF.
If I draw my vertices regularly, they give the correct output based on the code below:
while(1){
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glEnable(GL_LIGHTING);
glShadeModel( GL_SMOOTH );
glEnable( GL_TEXTURE_2D );
glViewport( 0, 0, (float)renderWidth/1, (float)renderHeight/1. );
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
gluPerspective( 60, (float)renderWidth/(float)renderHeight, 0.1, 10000. );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
glPushMatrix();
glTranslatef(0,-0.5,-0.5);
// glBindVertexArray(vao);
// glDrawElements(GL_TRIANGLES, indexdata.size(), GL_UNSIGNED_BYTE, (void*)0);
for(int i=0; i<smpl.mF.rows(); i++){
glBegin(GL_POLYGON);
for(int j=0; j<smpl.mF.cols(); j++){
indexdata.push_back(smpl.mF(i,j)+1);
}
glVertex3fv((const GLfloat*)&vertexdata[smpl.mF(i,0)].position);
glVertex3fv((const GLfloat*)&vertexdata[smpl.mF(i,1)].position);
glVertex3fv((const GLfloat*)&vertexdata[smpl.mF(i,2)].position);
glEnd();
}
glPopMatrix();
glutSwapBuffers();
glutPostRedisplay();
std::this_thread::sleep_for(std::chrono::milliseconds(10));
glutMainLoopEvent();
}
However, if I use vertex buffers, i get rubbish output:
// Iterate v
for(int i=0; i<smpl.mVTemp2.rows(); i++){
Vertex v;
for(int j=0; j<smpl.mVTemp2.cols(); j++){
v.position[j] = smpl.mVTemp2(i,j);
}
vertexdata.push_back(v);
}
std::vector<GLubyte> indexdata;
// Iterate f
for(int i=0; i<smpl.mF.rows(); i++){
for(int j=0; j<smpl.mF.cols(); j++){
indexdata.push_back(smpl.mF(i,j));
}
}
// Create and bind a VAO
GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
// Create and bind a BO for vertex data
GLuint vbuffer;
glGenBuffers(1, &vbuffer);
glBindBuffer(GL_ARRAY_BUFFER, vbuffer);
// copy data into the buffer object
glBufferData(GL_ARRAY_BUFFER, vertexdata.size() * sizeof(Vertex), &vertexdata[0], GL_STATIC_DRAW);
// set up vertex attributes
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, position)); // vertices
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_TRUE, sizeof(Vertex), (void*)offsetof(Vertex, normal)); // normals
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, texcoord)); // normals
// Create and bind a BO for index data
GLuint ibuffer;
glGenBuffers(1, &ibuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibuffer);
// copy data into the buffer object
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexdata.size() * sizeof(GLubyte), &indexdata[0], GL_STATIC_DRAW);
glBindVertexArray(0);
while(1){
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glEnable(GL_LIGHTING);
glShadeModel( GL_SMOOTH );
glEnable( GL_TEXTURE_2D );
glViewport( 0, 0, (float)renderWidth/1, (float)renderHeight/1. );
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
gluPerspective( 60, (float)renderWidth/(float)renderHeight, 0.1, 10000. );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
glPushMatrix();
glTranslatef(0,-0.5,-0.5);
glBindVertexArray(vao);
glDrawElements(GL_TRIANGLES, indexdata.size(), GL_UNSIGNED_BYTE, (void*)0);
glPopMatrix();
glutSwapBuffers();
glutPostRedisplay();
std::this_thread::sleep_for(std::chrono::milliseconds(10));
glutMainLoopEvent();
}
I can't understand what I am doing wrong. I am able to draw the faces normally with regular old glVertex and it works, but is too slow. So I want to use vertex buffers, but the code always gives junk output. Why is this the case? EDIT:
I have solved the problem, however my normals are now wrong. If I draw it normally with Vertex and Normal calls, it works:
std::vector<Vertex> vertexdata;
for(int i=0; i<object.vertices.size(); i++){
Vertex v;
v.position[0] = object.vertices.at(i).coords[0];
v.position[1] = object.vertices.at(i).coords[1];
v.position[2] = object.vertices.at(i).coords[2];
v.normal[0] = object.computedNormals.at(i).coords[0];
v.normal[1] = object.computedNormals.at(i).coords[1];
v.normal[2] = object.computedNormals.at(i).coords[2];
vertexdata.push_back(v);
}
std::vector<GLushort> indexdata;
for(int i=0; i<object.faces.size(); i++){
OBJFace& face = object.faces.at(i);
indexdata.push_back(face.items[0].vertexIndex);
indexdata.push_back(face.items[1].vertexIndex);
indexdata.push_back(face.items[2].vertexIndex);
glBegin(GL_POLYGON);
glNormal3fv(vertexdata[face.items[0].vertexIndex].normal);
glVertex3fv(vertexdata[face.items[0].vertexIndex].position);
glNormal3fv(vertexdata[face.items[1].vertexIndex].normal);
glVertex3fv(vertexdata[face.items[1].vertexIndex].position);
glNormal3fv(vertexdata[face.items[2].vertexIndex].normal);
glVertex3fv(vertexdata[face.items[2].vertexIndex].position);
glEnd();
}
However, if I use it with Vertex Buffers, it does not:
std::vector<Vertex> vertexdata;
for(int i=0; i<object.vertices.size(); i++){
Vertex v;
v.position[0] = object.vertices.at(i).coords[0];
v.position[1] = object.vertices.at(i).coords[1];
v.position[2] = object.vertices.at(i).coords[2];
v.normal[0] = object.computedNormals.at(i).coords[0];
v.normal[1] = object.computedNormals.at(i).coords[1];
v.normal[2] = object.computedNormals.at(i).coords[2];
vertexdata.push_back(v);
}
std::vector<GLushort> indexdata;
for(int i=0; i<object.faces.size(); i++){
OBJFace& face = object.faces.at(i);
indexdata.push_back(face.items[0].vertexIndex);
indexdata.push_back(face.items[1].vertexIndex);
indexdata.push_back(face.items[2].vertexIndex);
}
glBindVertexArray(vao);
glBindBuffer(GL_ARRAY_BUFFER, vbuffer);
// copy data into the buffer object
glBufferData(GL_ARRAY_BUFFER, vertexdata.size() * sizeof(Vertex), &vertexdata[0], GL_STATIC_DRAW);
// set up vertex attributes
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, position)); // vertices
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, normal)); // normals
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, texcoord)); // normals
// Create and bind a BO for index data
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibuffer);
// copy data into the buffer object
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexdata.size() * sizeof(GLushort), &indexdata[0], GL_STATIC_DRAW);
glBindVertexArray(0);
glBindVertexArray(vao);
glDrawElements(GL_TRIANGLES, indexdata.size(), GL_UNSIGNED_SHORT, (void*)0);
Upvotes: 0
Views: 148
Reputation: 211258
In addition to the answer of Nicol Bolas:
It looks like as the number of indices is too much to encode them in bytes (GLubyte
). A byte can store data in the range [0, 255], so only 256 indices can be encoded in a byte. Use GLushort
instead. The range of GLushort
is [0, 65535]:
std::vector<GLushort> indexdata;
....
GLuint ibuffer;
glGenBuffers(1, &ibuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexdata.size()*sizeof(GLushort),
indexdata.data(), GL_STATIC_DRAW);
....
glDrawElements(GL_TRIANGLES, indexdata.size(), GL_UNSIGNED_SHORT, (void*)0);
Upvotes: 1
Reputation: 474376
You are not using shaders for vertex processing. As such, generic vertex attributes (as provided by VertexAttrib
functions) cannot be used. So, you can either switch to using shaders, or use fixed-function attributes:
// set up vertex attributes
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, sizeof(Vertex), (void*)offsetof(Vertex, position)); // vertices
glEnableClientState(GL_NORMAL_ARRAY);
glNormalPointer(GL_FLOAT, sizeof(Vertex), (void*)offsetof(Vertex, normal)); // normals
glClientActiveTexture(GL_TEXTURE0);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), (void*)offsetof(Vertex, texcoord)); // normals
Upvotes: 1