How to use UV Indices in OpenGL 4.4?

Hello everybody, I know this question have been asked quite a few times now, but so far I haven’t found a proper answer.

I have a program where I load a mesh from a wavefront (.obj) file exported from blender. So far my program can render the mesh, including texture, but the texture is not rendered correctly because I was attempting to pass the UV coordinates to OpenGL using GL_ARRAY_BUFFER. My program’s logic is somehow correct; as long as I have the same number of UV coordinates as I have vertices and both the vertices and the UV arrays are ordered so that they can both be accessed by the same index, the texture will be rendered correctly. But it is unlikely that these 2 conditions will meet for most cases. Most of the times, I have a different number of UV coordinates than I have vertices and I have no idea of how blender organizes the vertices but they are definitely not in the same order as the UV coordinates.

So far I have an array of vertices, an array of UV coordinates and 2 array of indices, one for the vertices and another for the UV coordinates. Is there some way I can give OpenGL the UV coordinates and their indices in the same fashion as I do with the vertices when doing indexed drawing (using one buffer for the UV coordinates, and another for the UV indices)?

That doesn’t really make sense…why would you need more or less UV coordinates than vertices? UV coordinates simply represent that vertex’s position in a texture. If you use a library like Assimp, it will handle importing all the data from the file, and all you need to do is dump that data into buffers.

I have a different number of UV coordinates than vertices because the UV coordinates can be generated differently depending on the model. For example, take a cube, in a worst case scenario, it will have 24 UV coordinates, 8 vertices and 36 vertex indices. That same cube, in a best case scenario, can then have 4 UV coordinates, 8 vertices and 36 vertex indices. My problem is the result of how I am passing the information to OpenGL. Here is how I do it:

  1. first, I create a GL_ELEMENT_BUFFER where I store all the vertex indices
  2. then, I create a GL_ARRAY_BUFFER, where I store the vertices AND the UV coordinates using glBufferSubData()
  3. after that, I configure the array buffer layout using glVertexAttribPointer() and I tell him that the array buffer has both the vertex position and the UV coordinate for each vertex
  4. finally, I call glDrawElements() to do indexed drawing

Since I am associating each vertex with one UV coordinate, but I am also indexing the vertices, unless I have the same number of vertices than UV coordinates and they are also stored in the same order so that the correct UV coordinate can be accessed using the vertex index, the texture won’t be displayed correctly.

As I said before, I may have a way to work around this problem, because I have an array of UV indices and an array of UV coordinates, but I don’t know how to pass this data to OpenGL -I don’t know if I can index UV coordinates in OpenGL-.

Also I would like add that since I am learning OpenGL, I would prefer to do everything myself before using a library. So I think I’ll pass on using Assimp for now, but thanks for the link, it will be useful later.

Unfortunately, that is simply not how index buffers and glDrawElements() work. Each vertex must be redefined for each time you need a different UV coord. That simple. You’ll need to use 24 vertices if you need 24 UV coords, because you can only have one index buffer that indexes all of your vertex attribute arrays.

I wouldn’t say model loading is much a part of learning OpenGL. Why worry about how to parse a specific file format when there are great libraries like Assimp out there that can do all that work for you? You can learn OpenGL using an import library, then learn the nitty-gritty of loading model files later on once you are proficient in OpenGL.

Also, the .obj format is quite limited, if you still insist on parsing files on your own you might want to look into another open format like Collada.

As I said before, I may have a way to work around this problem, because I have an array of UV indices and an array of UV coordinates, but I don’t know how to pass this data to OpenGL -I don’t know if I can index UV coordinates in OpenGL-.

The only way I know of doing this in unextended GL is to use a geometry shader in conjuntion with a texture buffer object containing the UV coords. It requires that your model be all triangles, or tessellated to triangles. Then you build the uv TBO so that contains the vertices in the order of the tessellated triangles. For your cube example, this means you’d have 8 points, 12 triangles, and 36 vertices. The geometry shader then uses a texelFetch() on the TBO with the coord set to gl_PrimitiveIdIn*3 + vert_num.

The downside is the added complexity and the geometry shader overhead. While it saves memory as the model gets bigger, the geometry shader incurs a larger performance penalty as well. For this reason it’s often better to promote the positions to match the uv vertices, unless the model is constantly deforming and the point promotion becomes a bottleneck.

Index buffer objects (IBOs) can only have one set of indices for rendering. Since you’re trying to render an .obj file, you typically need three sets of indices: position, normals, and texture coordinates. These correspond to the numbers after the “f” in the .obj file. For example, f 1/2/3 2/5/6 3/4/8 is a triangle that has different indices for each of the attributes. It’s up to you to re-sort/enlarge or interleave the array buffers so that they all use the same set of indices. For example, you want something that ends up looking like this: f 1/1/1 2/2/2 3/3/3. This allows you to use a single IBO for addressing the mesh data.

OpenGL has nothing to do with this task and that is why people here will recommend using a library like Assimp. There’s many places to go wrong when loading an .obj from scratch. For example, .obj indices start at 1 rather than 0 and it’s up to you to fix that before rendering. Personally, I’d rather spend my time learning OpenGL rather than parsing/sorting a particular kind of text file. (I already learned how to parse text files when I started programming.)