raaj
raaj

Reputation: 3311

Can't make OpenGL Buffer Array work - glVertex works

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

enter image description here

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

enter image description here

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

enter image description here

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

enter image description here

Upvotes: 0

Views: 148

Answers (2)

Rabbid76
Rabbid76

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

Nicol Bolas
Nicol Bolas

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

Related Questions