1

I am required to Using VBO to draw the cube by loading wavefront object. by drawing the triangles. here is the object:

v -1.000000 -1.000000 1.000000
v -1.000000 1.000000 1.000000
v -1.000000 -1.000000 -1.000000
v -1.000000 1.000000 -1.000000
v 1.000000 -1.000000 1.000000
v 1.000000 1.000000 1.000000
v 1.000000 -1.000000 -1.000000
v 1.000000 1.000000 -1.000000
vn -1.0000 0.0000 0.0000
vn 0.0000 0.0000 -1.0000
vn 1.0000 0.0000 0.0000
vn 0.0000 0.0000 1.0000
vn 0.0000 -1.0000 0.0000
vn 0.0000 1.0000 0.0000
f 2//1 3//1 1//1
f 4//2 7//2 3//2
f 8//3 5//3 7//3
f 6//4 1//4 5//4
f 7//5 1//5 3//5
f 4//6 6//6 8//6
f 2//1 4//1 3//1
f 4//2 8//2 7//2
f 8//3 6//3 5//3
f 6//4 2//4 1//4
f 7//5 5//5 1//5
f 4//6 2//6 6//6  

I also have a cooler array filled by myself which equals to 3 times number of face which is 36 indices

float colours[] = {
    0.583f,  0.771f,  0.014f,
    0.609f,  0.115f,  0.436f,
    0.327f,  0.483f,  0.844f,
    0.822f,  0.569f,  0.201f,
    0.435f,  0.602f,  0.223f,
    0.310f,  0.747f,  0.185f,
    0.597f,  0.770f,  0.761f,
    0.559f,  0.436f,  0.730f,
    0.359f,  0.583f,  0.152f,
    0.483f,  0.596f,  0.789f,
    0.559f,  0.861f,  0.639f,
    0.195f,  0.548f,  0.859f,
    }

I store my vertices,normals,colours information into a array which is binding to VBO buffer:

 float* vbo = new float[78]

which is in the order of vertices|normals|colours which is 24indices|18indices|36indices, I have been test it works very well

I use another array to store the vertices indices information which is 36indices ,for example: f 2//1 3//1 1//1 I store as 2/3/1 in my array

 int *element = new int[36];

I have been test it works well ,I initial my vbo as follow:

 static void init(void){
 .......
Gluint vbo_id,index_id;

glGenBuffers(1,&vbo_id);
glGenBuffers(1,&index_id);
glBindBuffer(GL_ARRAY_BUFFER,vbo_id); 
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,index_id);

glBufferData(GL_ARRAY_BUFFER,sizeof(vbo),vbo,GL_STATIC_DRAW);
glBufferData(GL_ELEMENT_ARRAY_BUFFER,sizeof(element),element,GL_STATIC_DRAW); } 

and my drawing is here

 static void display(void){
  .......
 glBindBuffer(GL_ARRAY_BUFFER,vbo_id);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,index_id);
    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_COLOR_ARRAY);
    glEnableClientState(GL_NORMAL_ARRAY);
    glVertexPointer(3,GL_FLOAT,0,0);
    glNormalPointer(GL_FLOAT,0,(void*)(24*sizeof(float)));//binding 
    glColorPointer(3,GL_FLOAT,0,(void*)(42*sizeof(float)));

    for(int i=0;i<12;i++){

    glBegin(GL_TRIANGLES);
    glArrayElement(element[i]);
    glArrayElement(element[i+1]);
    glArrayElement(element[i+2]);
    glEnd();

    }
    /* have try this one too:
    glDrawElements(GL_TRIANGLES,3,GL_INT,0) */


    glDisableClientState(GL_COLOR_ARRAY);
    glDisableClientState(GL_VERTEX_ARRAY);
    glDisableClientState(GL_NORMAL_ARRAY);
    glBindBuffer(GL_ARRAY_BUFFER,0);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0);
    }

however there's nothing show on the screen. is my binding method correct, my instructor tells me when I draw with the indices , if I binding vertices and normals ,and colors correct , It will automatically matching by drawing with indices of vertices.

genpfault
  • 47,669
  • 9
  • 68
  • 119
ShaoyuPei
  • 199
  • 5

1 Answers1

1

The type of vbo is float*, so sizeof(vbo) is not the size of the array, where vbo points to, but it's the size of the pointer. See sizeof.
Note, the 3rd parameter of glBufferData has to be the size of the buffer in bytes.

The size of float* vbo = new float[78] is 78 * sizeof(float) or 78 * sizeof(*vbo)
and the size of int *element = new int[36] is 36 * sizeof(int) or 36 * sizeof(*element)
But sizeof(vbo) is the size of the pointer to the array or the same as sizeof(float*).

This means you have to change the code like this:

glBufferData(GL_ARRAY_BUFFER, 78*sizeof(float), vbo, GL_STATIC_DRAW);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, 36*sizeof(int), element, GL_STATIC_DRAW); 

The 2nd paramter of glDrawElements has to be the number of indices and the 3rd paramter has to be GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT, or GL_UNSIGNED_INT, dependent on the data type of the indices:

glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, NULL);

Note, you should prefer to use unsigned int * instead of int* for the data type of the index array (element).


Your assumption is wrong. You can't mix 24 vertex coordinates, 18 normal vectors and 36 colors, with differnt arrays of indices, directly in one Vertex Array Object.

The vertex attributes for each vertex position form a set of data. This means you have to create tuples of vertex coordinate, normal vector and color.

See further Rendering meshes with multiple indices

I recommend to use std::vector and to do it somehow like this:

#include <vector>

// 8  vertex coordiantes: 8 * 3 float 
std::vector<float> v{
  -1.0f, -1.0f,  1.0f,
  -1.0f,  1.0f,  1.0f,
  -1.0f, -1.0f, -1.0f,
  -1.0f,  1.0f, -1.0f,
   1.0f, -1.0f,  1.0f,
   1.0f,  1.0f,  1.0f,
   1.0f, -1.0f, -1.0f,
   1.0f,  1.0f, -1.0f };

// 6  normal vectors: 6 * 3 float
std::vector<float> nv{
   -1.0f,  0.0f,  0.0f,
    0.0f,  0.0f, -1.0f,
    1.0f,  0.0f,  0.0f,
    0.0f,  0.0f,  1.0f,
    0.0f, -1.0f,  0.0f,
    0.0f,  1.0f,  0.0f };

// 12 colors coordiantes: 12 * 3 float 
std::vector<float> c{
    0.583f,  0.771f,  0.014f,
    0.609f,  0.115f,  0.436f,
    0.327f,  0.483f,  0.844f,
    0.822f,  0.569f,  0.201f,
    0.435f,  0.602f,  0.223f,
    0.310f,  0.747f,  0.185f,
    0.597f,  0.770f,  0.761f,
    0.559f,  0.436f,  0.730f,
    0.359f,  0.583f,  0.152f,
    0.483f,  0.596f,  0.789f,
    0.559f,  0.861f,  0.639f,
    0.195f,  0.548f,  0.859f };

// 12 faces 3*2 indices/face: 12 * 3 * 2 unsigned int 
std::vector<unsigned int> indices{
    2, 1,    3, 1,    1, 1,
    4, 2,    7, 2,    3, 2,
    8, 3,    5, 3,    7, 3,
    6, 4,    1, 4,    5, 4,
    7, 5,    1, 5,    3, 5,
    4, 6,    6, 6,    8, 6,
    2, 1,    4, 1,    3, 1,
    4, 2,    8, 2,    7, 2,
    8, 3,    6, 3,    5, 3,
    6, 4,    2, 4,    1, 4,
    7, 5,    5, 5,    1, 5,
    4, 6,    2, 6,    6, 6 };

Create the vertex array data

// final vertex attributes 12 * 3 *(3 + 3 + 3) floats
// x0 y0 z0    nvx0 nvy0 nvz0    cr0 cg0 cb0
// x1 y1 z1    nvx1 nvy1 nvz1    cr1 cg1 cb1
std::vector<float> va; 

const unsigned int no_of_faces = 12;
for (unsigned int f=0; f<no_of_faces; ++f )
{
    for (unsigned int t=0; t<3; ++t )
    {
        unsigned int vi = indices[(f*3+t)*2]-1;   // vertex index
        unsigned int ni = indices[(f*3+t)*2+1]-1; // normal vector index
        unsigned int ci = f;                      // color index

        va.insert(va.end(), v.begin()  + vi*3, v.begin()  + vi*3+3); // insert vertex coordinate
        va.insert(va.end(), nv.begin() + ni*3, nv.begin() + ni*3+3); // insert normal vector
        va.insert(va.end(), c.begin()  + ci*3, c.begin()  + ci*3+3); // insert color
    }
}

Create the Vertex Buffer Object:

GLuint vbo;
glGenBuffers( 1, &vbo );
glBindBuffer( GL_ARRAY_BUFFER, vbo );
glBufferData( GL_ARRAY_BUFFER, va.size()*sizeof(*va.data()), va.data(), GL_STATIC_DRAW );

Define the an arrays of generic vertex attribute data:

glVertexPointer( 3, GL_FLOAT, 9*sizeof(*va.data()), 0 );
glEnableClientState( GL_VERTEX_ARRAY );
glNormalPointer( GL_FLOAT, 9*sizeof(*va.data()), (void*)(3*sizeof(*va.data())) ); 
glEnableClientState( GL_NORMAL_ARRAY );
glColorPointer( 3, GL_FLOAT, 9*sizeof(*va.data()), (void*)(6*sizeof(*va.data())) ); 
glEnableClientState( GL_COLOR_ARRAY );
glBindBuffer( GL_ARRAY_BUFFER, 0 );

Draw the array:

glDrawArrays( GL_TRIANGLES, 0, 36 );

Preview:

cube

Rabbid76
  • 142,694
  • 23
  • 71
  • 112
  • Hi,I follow your instruction, but it crashes ,it should use sizeof(*float) or sizeof(*va.data())? and it should be glDrawArrays( GL_TRIANGLES, 0, 12 )? ;I test va has the right output., – ShaoyuPei May 19 '18 at 21:33