PDA

View Full Version : DrawElementsInstanced stopping DrawingElements



Miniscoggs
12-22-2016, 02:43 PM
I have recently swapped development PCs and got my project up and running again however not everything is displaying as it was.

I have implimented DrawElementsInstanced for some particle effects but still use DrawElements for the majority of assets. This is done by swapping the OpenGL program between assets from one with shaders attached that support instancing to a program whose shaders do not. There is also a third program which supports DrawElements that I use for the HUD. If I call the DrawElementsInstanced then none of the assets called with DrawElements display, regardless of which program they are drawn with, leading me to believe the problem is not related to swapping the programs. If I comment out the code to DrawElementsInstanced then the other assets display as expected.

I am at a complete loss as to why this is the case, I can provide any code required but as I don't have a clue what the issue could be I'm currently unsure what code would be useful.

Miniscoggs
12-23-2016, 06:49 AM
I have done some further experimenting with my code and the problem seems to be when calling glVertexAttribDivisor

example usage:


glBindBuffer(GL_ARRAY_BUFFER, mPositionBuffer->getBuffer());
glVertexAttribPointer(mProgram->getInstancePositionLocation(), 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), NULL);
glVertexAttribDivisor(mProgram->getInstancePositionLocation(), 1);

The instance position location is got with glGetAttribLocation.

I have four attributes I set in this way (position, rotation, scale and alpha) and each one of these cause the error but I am still unsure as to why and what the solution is.

GClements
12-23-2016, 07:20 AM
I have done some further experimenting with my code and the problem seems to be when calling glVertexAttribDivisor
Note that the divisor is persistent; changing the attribute array with glVertexAttribPointer() won't reset the divisor to zero. The divisor needs to be zero for non-instanced rendering.

Consider using VAOs (these are mandatory for OpenGL 3+ core profile) so that you set all of the attribute array state with one call to glBindVertexArray() rather than needing multiple calls to glEnableVertexAttribArray(), glVertexAttribPointer() and glVertexAttribDivisor().

Miniscoggs
12-24-2016, 11:11 AM
Hi GClements,

Thank you very much for your help, Setting the divisor back to 0 after the DrawElementsInstanced call has worked.

I would like to use VAOs if that is what is mandatory for OpenGL 3+ however I am a little confused as to what exactly they are and how it is different to my current implementation, would you be able to direct me to a good explanatory resource?

GClements
12-24-2016, 02:14 PM
I would like to use VAOs if that is what is mandatory for OpenGL 3+ however I am a little confused as to what exactly they are and how it is different to my current implementation

In OpenGL 3.0 and later, all state related to vertex attribute arrays is stored in a VAO. The state stored for each attribute array includes the size, type, stride and normalised flag (from glVertexAttribPointer()), whether the array is enabled or disabled (glEnableVertexAttribArray() and glDisableVertexAttribArray()), the divisor (glVertexAttribDivisor()), and the buffer object (the buffer bound to GL_ARRAY_BUFFER at the time of the glVertexAttribPointer() call). In addition to the per-attribute state, the current GL_ELEMENT_ARRAY_BUFFER binding is also stored in a VAO.

Any OpenGL command which uses or modifies the above state reads or modifies the currently-bound VAO (glBindVertexArray()).

In the compatibility profile, there exists a default VAO with a name (handle) of zero. This is bound initially, and cannot be deleted; glBindVertexArray(0) will bind this VAO. Thus, in the compatibility profile it's possible to completely ignore the existence of VAOs and just operate as before. The fact that the attribute state is being stored in VAO zero rather than in the context itself is transparent.

In the core profile, there is no default VAO. You must create and bind a VAO before issuing any call which uses or modifies the above state, or an error will be generated. glBindVertexArray(0) results in no VAO being bound.

Typically, you'd create a VAO for each distinct combination of attribute array state, then initialise it by binding it then using the functions mentioned above. Each drawing command (or perhaps a group of drawing commands using the same data) would be be preceded by a glBindVertexArray() call to select the appropriate VAO.