How can I specify per-face colors when using indexed vertex arrays in OpenGL 3.x?

People interested in whether to use array indices or not may find some utility in a diagram I created to graphically summarise the behaviour of the different OpenGL calls, so that you can see, for example, which ones draw contiguous blocks of vertex data, versus which ones 'skip around' using indices.

OpenGL draw calls.

I published this image under Creative Commons BY-SA, as noted at this source.


The actual answer first:
See Goz's answer. Keep 24 separate vertices.

Some nomenclature second:
A Vertex is a set of vertex attributes. Please keep that distinction in mind when reading the following:

You have a misconception that using deprecated APIs would help you solve the issue. This is not the case. OpenGL handles (and has always handled) each vertex as a unique set of attributes. If you read the original spec carefully, you'll notice that when doing:

glNormal()
glVertex()
glVertex()
glVertex()

The specification clearly states that glNormal sets the current normal state, and that glVertex provokes a new vertex, copying in passing all the current state, including the current normal state. That is, even though you passed only one Normal, the GL still sees 3.

The GL, therefore, does not have "per-face" attributes.

Also, you're mixing index arrays GL_ELEMENT_ARRAY_BUFFER, that are used from glDrawElements(..., pointer), where pointer is an offset inside the index array, and vertex attribute arrays GL_ARRAY_BUFFER, that are used from glVertexAttribPointer (and all the deprecated glVertexPointer/glNormalPointer...

Each index that is in the index buffer will be used as an index into each of the attributes, but you can only specify a single index for each vertex. So, setting GL_ELEMENT_ARRAY_BUFFER and then calling glVertexAttribPointer, does not do at all what you think it does. It either uses the last array you set to GL_ARRAY_BUFFER for defining vertex attributes, or if you did not keep one bound, is interpreting your offset as a pointer (and will likely crash).

What you were trying to do, setting an index array for each vertex attribute, is not supported by GL. Let me restate this: you only have 1 index array per draw.

Some additional tidbits for the history enclined:

glVertex is a bit of a misnomer. It specifies only the Vertex position. But, and this is what it gets its name from, it also provokes a vertex to be passed to the GL. For the API to be completely clean, you could have imagined having to do 2 calls:

// not valid code
glPosition(1,2,3); // specifies the current vertex position
glProvoke(); // pass the current vertex to GL

However, when GL was first specified, Position was always required, so fusing those 2 to provoke a vertex made sense (if only to reduce the API call count).

Fast forward to vertex_program_arb: Trying to get away from the fixed-function model while still remaining compatible meant that the special nature of glVertex had to be carried forward. This was achieved by making the vertex attribute 0 provoking, and a synonym to glVertex.

Fast forward to GL3.2: the Begin/End model is gone, and all this specification of what provokes a vertex can finally go away, along with the management of the current state. So can all the semantic APIs (the glVertex*, glNormal*...), since all inputs are just vertex attributes now.

Tags:

Opengl