2

On general my question is how can I provide 2 indices for the vbo. One for the vertices and one for the normals? I got the next Obj file:

mtllib cube.mtl

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 -0.999999
v 0.999999 1.000000 1.000001
v -1.000000 1.000000 1.000000
v -1.000000 1.000000 -1.000000
vn 0.000000 -1.000000 0.000000
vn 0.000000 1.000000 0.000000
vn 1.000000 0.000000 0.000000
vn -0.000000 -0.000000 1.000000
vn -1.000000 -0.000000 -0.000000
vn 0.000000 0.000000 -1.000000

usemtl Material
f 1//1 2//1 3//1 4//1
f 5//2 8//2 7//2 6//2
f 1//3 5//3 6//3 2//3
f 2//4 6//4 7//4 3//4
f 3//5 7//5 8//5 4//5
f 5//6 1//6 4//6 8//6

As you can see there are 8 vertices and 6 normals. On the faces lines the file connects each vertex to the next vertex by indices and connects the normals too by different indices.

I am trying to draw with cube model with vbo. I have written the following code:

float vertex[] = {1, -1, -1, 
              1, -1, 1,
             -1, -1, 1,
             -1, -1, -1,
              1, 1, -1,
              1, 1, 1,
             -1, 1, 1,
              -1, 1, -1};
float normals[] = {0, -1, 0,
                   0, 1, 0,
                   1, 0, 0,
                   0, 0, 1,
                   -1, 0, 0,
                   0, 0, -1};
int index[] = {0, 1, 2, 3,
               4, 7, 6, 5,
               0, 4, 5, 1,
               1, 5, 6, 2,
               2, 6, 7, 3,
               4, 0, 3, 8};




GLuint buffer, ind;
int offset = 0;

void vboInit()
{
    glGenBuffers(1, &buffer);
    glBindBuffer(GL_ARRAY_BUFFER, buffer);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertex) + sizeof(normals), 0, GL_STATIC_DRAW);
    glBufferSubData(GL_ARRAY_BUFFER, offset, sizeof(vertex), vertex);       offset+= sizeof(vertex);
    glBufferSubData(GL_ARRAY_BUFFER, offset, sizeof(normals), normals);     offset+= sizeof(normals);


    glGenBuffers(1, &ind);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ind);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(index), index, GL_STATIC_DRAW);
}

void vboDraw()
{
    glBindBuffer(GL_ARRAY_BUFFER, buffer);  
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ind); 
    glNormalPointer(GL_FLOAT, 0, (GLvoid*)(sizeof(vertex)));
    glVertexPointer(3, GL_FLOAT, 0, 0);

    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_NORMAL_ARRAY);
    for (int i = 0; i < 6; i++)
        glDrawElements(GL_TRIANGLE_FAN, 4 + i*4, GL_UNSIGNED_INT, (GLvoid*)(i*4));
    glDisableClientState(GL_NORMAL_ARRAY);
    glDisableClientState(GL_VERTEX_ARRAY);


    glBindBuffer(GL_ARRAY_BUFFER, NULL);        
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, NULL);    
}

This code uses the indices of the vertices for the normals. Therefore the normals does not loading well and I need different indices to the normals. The question is how can I provide 2 indices for the vbo. One for the vertices and one for the normals?

UdiM
  • 480
  • 3
  • 19
  • 1
    Not sure if your question should be marked as an exact duplicated, but I answered very similar questions before. These two answers should cover what you're looking for: http://stackoverflow.com/questions/23710829/why-is-my-obj-parser-rendering-meshes-like-this/23713424#23713424, http://stackoverflow.com/questions/23349080/opengl-index-buffers-difficulties/23356738#23356738. – Reto Koradi Jun 19 '14 at 14:49

1 Answers1

0

Short answer it that you can't. But if you want long one:

DrawElements takes indices arrays of vertices. Vertex is not a position; it is assembly of all attributes at once. When you fetching vertex by index, you must take it from the very same index from every attribute array. Good side of indices is that they enables usage of post-TNL cache (however, utilisation of cache depends upon actual indices values) and reduces memory usage.

If your data saved in OBJ-like layout where attribute arrays indexed in independent way, you have to convert your arrays to more friendly representation. Simple approach would be:

  • Allocate big array[s] so it can hold all vertex data even without indices.
  • For each triangle, fetch data to new arrays using your independent indices. As the result, your vertices are now don't have independent attributes indices - but they don't have indices at all! You already could draw though - with DrawArrays().
  • If you want indices, now you can recreate them. Remove duplicates from new vertices arrays (duplicates have entire vertices equal, not only positions), and for each triangle find index of vertex in new array.
keltar
  • 17,711
  • 2
  • 37
  • 42
  • What do you mean by duplicates? – UdiM Jun 19 '14 at 12:03
  • 1
    If all attributes for specific vertex matches with other vertex, then one of vertices is duplicate and may be removed. – keltar Jun 19 '14 at 12:38
  • While you're suggested approach works, it seems very inefficient to remove duplicates by comparing the actual vertex data. See here for a more efficient approach: http://stackoverflow.com/questions/23349080/opengl-index-buffers-difficulties/23356738#23356738. – Reto Koradi Jun 19 '14 at 14:51
  • @RetoKoradi I doubt STL map would beat plain array sorted by hashed vertex data on large dataset, because sort performed only once, while map performs rebalansing on every insert; but this surely shouldn't be performed on every load of massive data, just an offline conversion. But anyway, you still need some distinctive data for *each* vertex attribute, not just position and normal (e.g. texture coordinates, whatever); it isn't really matter if it is actual attribute data or index. – keltar Jun 19 '14 at 15:04
  • If you really care about the ultimate performance, you could most likely do better than an STL map for the data structure. That was just an example of how the pseudo-code could easily be implemented. In any case, I would be curious to hear how your solution compares. Can you try the minicooper.obj file from http://people.sc.fsu.edu/~jburkardt/data/obj/obj.html? It has 44k vertices, 44k normals, 3k sets of texture coordinates, and 80k faces. It takes 0.2 seconds to load and build VBOs with indexed OpenGL geometry on my MacBook Pro. – Reto Koradi Jun 20 '14 at 07:46
  • ... The code I use is not really optimized. More a sample implementation. I haven't profiled it, but I suspect that a large part of the time spent is for reading the file, and parsing the numbers. Still, 0.2 seconds for a moderately large model does not seem too unreasonable. – Reto Koradi Jun 20 '14 at 07:48
  • @RetoKoradi whyyyy... If most of the time is disk data reading and parsing, and *this* code surely isn't the same, and hardware isn't the same - why on earth would you like to measure your approach against mine? Without code, it makes no sense. Worse, model you've suggested have no separate normals - quick look says me that position and normal index is always the same. Besides, I never said how it is implemented - only that it is some deduplication. – keltar Jun 20 '14 at 08:48
  • @RetoKoradi you claimed that it is slow - although I would stand that it is more correct, especially when indices isn't really good (say I don't trust software that have generated data file) - e.g. different verttices may have different indices, but actual numbers are the same; while without actual measurements it is impossible to say what is slower, I agree that it *could* be slower, although STL isn't looking too promising, so I have my doubts. But then you say that performance isn't really matter (and I agree). So what was the point? – keltar Jun 20 '14 at 08:51