Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using a different array for vertices and normals in glDrawElements (OpenGL/VBOs)

Tags:

opengl

vbo

I'm currently programming a .obj loader in OpenGL. I store the vertex data in a VBO, then bind it using Vertex Attribs. Same for normals. Thing is, the normal data and vertex data aren't stored in the same order.

The indices I give to glDrawElements to render the mesh are used, I suppose, by OpenGL to get vertices in the vertex VBO and to get normals in the normals VBO.

Is there an opengl way, besides using glBegin/glVertex/glNormal/glEnd to tell glDrawElements to use an index for vertices and an other index for normals? Thanks

like image 724
Tuxer Avatar asked Jun 28 '11 16:06

Tuxer


3 Answers

There is no direct way to do this, although you could simulate it by indexing into a buffer texture (OpenGL 3.1 feature) inside a shader.

It is generally not advisable to do such a thing though. The OBJ format allows one normal to be referenced by several (in principle any number of) vertices at a time, so the usual thing to do is constructing a "complete" vertex including coordinates and normal and texcoords for each vertex (duplicating the respective data).

This ensures that
a) smooth shaded surfaces render correctly
b) hard edges render correctly

(the difference between the two being only several vertices sharing the same, identical normal)

like image 132
Damon Avatar answered Oct 22 '22 16:10

Damon


You have to use the same index for position/normals/texture coords etc. It means that when loading the .obj, you must insert unique vertices and point your faces to them.

like image 2
SurvivalMachine Avatar answered Oct 22 '22 16:10

SurvivalMachine


OpenGL treats a vertex as a single, long vector of

(position, normal, texcoord[0]…texcoord[n], attrib[0]…attrib[n])

and these long vectors are indexed. Your question falls into the same category like how to use shared vertices with multiple normals. And the canonical answer is, that those vertices are in fact not shared, because in the long term they are not identical.

So what you have to do is iterating over the index array of faces and construct the "long" vertices adding those into a (new) list with a uniquenes constraint; a (hash) map from the vertex → index serves this job. Something like this

next_uniq_index = 0
for f in faces:
    for i in f.indices:
        vpos = vertices[i.vertex]
        norm = normals[i.normal]
        texc = texcoords[i.texcoord]
        vert = tuple(vpos, norm, texc)
        key
        if uniq_vertices.has_key(key):
             uniq_faces_indices.append(uniq_vertices[key].index)
        else:
             uniq_vertices[key] = {vertex = key, index = next_uniq_index}
             next_uniq_index = next_uniq_index + 1
like image 2
datenwolf Avatar answered Oct 22 '22 18:10

datenwolf