# OpenGL vertex data per index

Usually, vertex data is assigned to a particular vertex, like this:

[data]    [vertices]
[1.31] -> [1, 13, 5]
[84.3] -> [5, 8, 12]
[.095] -> [8, 3, 10]


Then, you would typically have an array saying which order to draw the vertices in:

[indices]
[   0   ]
[   2   ]
[   1   ]
[   2   ]


Using this, the first vertex would be drawn first, then the third vertex, then the second one, then the third one again. My question is if it is possible to assign vertex data to the index array rather than to the vertex array, like this:

[data]    [indices]
[1.31] -> [   0   ]
[84.3] -> [   2   ]
[.095] -> [   1   ]
[30.1] -> [   2   ]


So that when it draws each vertex from the index array, it uses that particular value.

Please note that I am dealing with a lot more vertices than are shown here. (17^3 to be precise) The examples I shown above wouldn't be useful by themselves, but it would make a significant difference in performance in my program if this was possible.

• What do you call "vertex data"? An attribute other than vertex position? A color? A texture? – Aracthor Sep 22 '15 at 14:50
• I am not sure what the proper terminology is, but I think it would be an attribute other than vertex position. I have been using glEnableVertexAttribArray() and glVertexAttribPointer() to create vertex attribute arrays. I can access them from the vertex shader using things like layout(location=1) in vec3 color and layout(location=2) in int attrib – Code Cube Sep 22 '15 at 15:12

No it is not.

The input to the shader pipeline expects a "stream" of vertices. So say you're using DRAW_TRIANGLES (or whatever it is) what actually happens is this:

1. Create 3 buffers (these are your varyings) of sufficient size
2. Fetch vertex (attributes) and put them in the input to the vertex shader
4. Transfer varyings output into the 1st buffer
5. Fetch vertex and put them in the input to the vertex shader
7. Transfer the varyings output to the 2nd buffer
8. Fetch vertex and put them in the input to the vertex shader
10. Transfer the varyings output to the 3rd buffer
11. Interpolate the varyings buffers over the resulting triangle and run the fragment shader for each "fragment" (pixel/sub-sampled pixel basically)

I've put the important bit, "fetch vertex" in bold because this could mean anything. OpenGL doesn't specify how this must actually be done (because of course it belongs to the implementation) but this is where indexed arrays come into play.

## Buffers, arrays and indexed arrays

Buffers:
The most primitive form of storage is a Buffer - this doesn't know what it stores, it is simply a chunk of bytes.

Arrays:
Next we have arrays, arrays are not actually blocks of memory. They contain 4 bits of information:

1. Which Buffer they are an array on. (a BufferId or Buffer* perhaps)
2. What data type they're supposed to be (eg 3 floats, 2 ints, 16 floats (for a 4x4 matrix)...)
3. An offset (call this o)
4. A step (call this s)

When you ask for the ith member of an array you actually get Buffer[si+o] - to - Buffer[si+o+sizeof(data type)] back. So if its floats, 4 bytes, you get these 4 bytes: Buffer[si+o], Buffer[si+o+1], Buffer[si+o+2] and Buffer[si+o+3] back

Indexed arrays:
This is an array of some integer data type (so it's a buffer + the array structure on top that returns numbers).

## Vertex streams

If you're using arrays, NOT indexed ones the fetch vertex step looks something like this:

For each attribute:
attribute.array[i]
i++;


Or

For each attribute:
attribute.buffer[attribute.array.step*i+attribute.array.offset]
i++;


With indexed arrays it does this:

For each attribute:
attribute.array[Index[i]]
i++;


Or

For each attribute:
attribute.buffer[attribute.array.step*Index[i]+attribute.array.offset]
i++;


In some sort of pseudo code.

As you can see indexes are not "complex" enough to do anything more than provide a lookup table mapping vertices to the data they're supposed to have.

## In the industry

Suppose you have vertex positions and normals, technically you can have buffers like this:

Buffer 1: xyzxyzxyz.....
Buffer 2: uvwuvwuvw.....


However this is bad because it means the implementation will (at some level) have to read something from buffer 1, then jump to buffer 2 and read some more, then back to buffer 1 and so forth and so forth. This is bad.

What you should do is something like:

Buffer 1: xyzuvwxyzuvwxyzuvw.....


This would just be a bigger step on the arrays. The implementation will likely optimise things like this so it just has to read it right away (with minimal transposing)

Indexing is bad as it can result in rather random reads at least with arrays it is predictable, so it is possible to do some hardware magic that can speedily read from multiple buffers, indexes however are not a simple ax+b formula, they can literally be random.

as such unless the cardinality (number) of indexes differs hugely from the length of the array implementations often unpack the indexed array.

That is to say if you have an index of 3 million but only 12 vertices, it'll use the index. If you have 15k index and 15k vertices it will not and it'll just unpack it.

## Final note

The usefulness of indexed arrays is limited by the fact that MOST of the time vertices in the same position will have different surface normals, consider for example a cube. Take any corner, that vertex will have 3 distinct normals. I think this is what you're trying to do. You've realised that they have the same position, but your data can still vary.

• Thank you for the detailed answer! I guess I will have to redo my code. My original algorithm was to have a pre-set grid of vertices, so I would only have to update the index array. That resulted in a lot of unused vertices, as well as vertices that required multiple values. – Code Cube Sep 22 '15 at 16:03
• No problem! Glad it helped, hope it makes sense. Not to sound like a whore but there is an up arrow you could click too @CodeCube ! – Alec Teal Sep 22 '15 at 16:05
• Wish I could, I only have 3 rep :P – Code Cube Sep 22 '15 at 16:44
• Oh right! Thanks for the tick @CodeCube and welcome! – Alec Teal Sep 22 '15 at 16:47