Replacing a VBO in an existing VAO - performance

I have a VAO with VBOs for various vertex attributes: vertex positions, vertex normals, and the element array VBO (all STATIC_DRAW), such that rendering an instance simply requires:
glBindVertexArray(vao);
glDrawElements(GL_TRIANGLES, <count>, <type>, 0);
However, I want to draw multiple instances of an object (I'm restricted to the OS X GL 3.2 core profile BTW) with different vertex texture (s,t) coordinates for each instance. The texcoord VBOs use the STREAM_DRAW hint (although I might get away with DYNAMIC_DRAW).
Is it more efficient to bind the VAO, bind the current texcoord VBO, and set the attribute pointer via glVertexAttribPointer, finalize the VAO with glBindVertexArray(0) and draw the new instance with different texture coordinates? Or does the cost of updating a VAO make this a poor approach? What about updating the texcoord VBO with glBufferSubData in a bound VAO?
I'd really appreciate some feedback before benchmarking separate approaches, since the wrong choice will result in significant refactoring.

Simply create multiple VAO. vertex array objects are lightweight, and they are used to setup vertex arrays all at once...
A VBO can be bound to multiple VAO, making your life easier and faster.
If you want, at some point, another attribute configuration, throw away the old VAO and create a new one.

Related

uniforms or vertex attributes when drawing lots of quads?

I'm working on a minimalist 2D user interface toolkit and need to draw lots of rectangles. I have a rendering class which draws all the rectangles, using a loop, each time setting uniforms for rectangle properties such as fill, color, border width, draw color inverted or not, etc. and then calling glDrawArrays with GL_TRIANGLES. My fragment shader uses these uniform values. For drawing a rectangle with inverted color I use glBlendFunc.
I have one VAO/VBO per rectangle. Obviously this is inefficient and I want to use one VAO across all my rectangles, and draw the rectangles with a single draw call instead of looping through them and setting uniform values and calling glDrawArrays each time.
I guess I could put each pair of triangles in a VBO, or perhaps use a single VBO for all rectangles, but what do I do with the uniforms, should I use vertex attributes instead, and try to pass these to the fragment shader, even if the properties per rectangle remain the same across vertices?
Using a lot of draw calls is terrible for CPU load, so you are definitely going to want to batch as may rectangles as possible into a single draw.
If you batch into a single draw you can only use a single configuration of attribute streams, so all your rectangles in that batch need to be in the same set of VBOs and the same VAO layout.
It doesn't sound like you'll have a huge number of verts, so packing this into the attribute stream sounds as good as anything, but you could use a uniform array indexed by the instance ID (one instance per rectangle).

Three.js indexed BufferGeometry vs. InstancedBufferGeometry

I'm trying to learn more about performant geometries in THREE.js, and have come to understand that an indexed BufferGeometry and InstancedBufferGeometry are the two most performant geometry types.
My understanding so far is that in an indexed BufferGeometry, vertices that are re-used in a geometry are only added to the geometry once, and each instance of a given re-used vertex are referenced by their index position in the vertex array.
My understanding of the InstancedBufferGeometry is that this geometry allows one to create a "blueprint" of an object, send one copy of that object's vertices to a shader, then use custom attributes to modify each copy of the blueprint's position, rotation, scale, etc. [source]
I'd like to better understand: are there cases in which an indexed BufferGeometry will be more performant than the InstancedBufferGeometry.
Also, in the InstancedBufferGeometry, are there WebGL maximum parameters (such as maximum vertices per mesh) that one must consider so as to avoid making a mesh too large? How are the vertices in an InstancedBufferGeometry counted?
If anyone could help clarify the situations in which indexed BufferGeometry and InstancedBufferGeometry should be used, and the performance ceilings of InstancedBufferGeometry, I'd be very grateful.
[...] IndexedBufferGeometry and InstancedBufferGeometry are the two most performant geometry types.
Yes, BufferGeometries in general are the most performant way to deal with geometry-data as they store data in exactly the format that is used in the communication with the GPU via WebGL. Any plain Geometry is internally converted to a BufferGeometry before rendering.
You are also correct in your descriptions of the indexed and instanced geometries, but I'd like to note one more detail: In an indexed geometry, the instructions for the GPU how to assemble the triangles are separated from the vertex-data and presented to the GPU in a special index-attribute (as opposed to being an implied part of the vertices for non-indexed arrays).
I'd like to better understand: are there cases in which an IndexedBufferGeometry will be more performant than the InstancedBufferGeometry.
They do different things at different levels, so I don't think there are many use-cases where a choice between them makes much sense.
In fact, you can even create an instanced geometry based on a "blueprint"-geometry that has is an indexed BufferGeometry.
Let's dive a bit into the details to explain. An instanced geometry allows you to render multiple "clones" of the same "blueprint"-geometry in a single draw-call.
The first part of this, the creation of the blueprint, is identical to rendering a single geometry. For this, the attributes (positions, normals, uv-coordinates and possibly the index for an indexed geometry) need to be transferred to the GPU.
The special thing for instanced geometries are some extra attributes (in three.js InstancedBufferAttribute). These control how many times the geometry will be rendered and provide some instance-specific values. A typical use-case would be to have an additional vec3-attribute for the instance-position and a vec4-attribute for the quaternion per instance. But it really could be anything else as well.
In the vertex-shader, these special attributes look just like any other attribute and you need to manually apply the instance-specific updates per vertex. So instead of this:
attribute vec3 position;
void main() {
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
You would have something like this:
attribute vec3 position;
attribute vec3 instanceOffset; // this is the InstancedBufferAttribute
void main() {
gl_Position =
projectionMatrix
* modelViewMatrix
* vec4(position + instanceOffset, 1.0);
}
What you don't see here is that the vertex-shader in the instanced version will not only be called once per vertex of your geometry (as it is the case for regular rendering) but once per vertex and instance.
So there isn't actually any magic going on, instanced geometries are in fact nothing but a very efficient way to express duplication of entire geometries.
Also, in the InstancedBufferGeometry, are there WebGL maximum parameters (such as maximum vertices per mesh) that one must consider so as to avoid making a mesh too large?
I am not sure about that, but I didn't encounter any so far. If you are aware that rendering 1000 instances of an object with 1000 vertices will invoke the vertex-shader a million times that should help your judgement of performance implications.
If anyone could help clarify the situations in which IndexedBufferGeometry and InstancedBufferGeometry should be used, and the performance ceilings of InstancedBufferGeometry, I'd be very grateful.
You can (and maybe should) use indexed geometries for almost any kind of geometry. But they are not free of drawbacks:
when using indices, all attributes will get the same treatment. So for instance, you can't use per-face colors in indexed geometries (see Access to faces in BufferGeometry)
for point-clouds or geometries with little repeated vertices, they will do more harm than good (due to the extra amount of memory/bandwidth needed for the index)
most of the time though they will get a performance-benefit:
less memory/bandwidth required for vertex-data
GPUs can cache results of vertex-shaders and re-use them for repeated vertices (so, in an optimal case you'd end up with one VS-invocation per stored vertex, not per index)
For instanced geometries
if you have a larger number of somewhat similar objects where the differences can be expressed in just a few numbers, go for instanced geometries (simple case: render copies of the same object at different locations, complex case: render a forest by changing the tree's geometry based on some instance-attribute or render a crowd of people by changing the individual persons pose with an instance-attribute)
another thing I found quite inspiring: rendering of fat lines using instancing: use instancing to render a bunch of line-segments where each line-segment consists of 6 triangles (see https://github.com/mrdoob/three.js/blob/dev/examples/js/lines/LineSegmentsGeometry.js by #WestLangley)
Drawbacks:
as it is right now, there is no builtin-support for using regular materials together with instanced geometries. You have to write your shaders yourself. (to be precise: there is a way to do it, but it requires some intimate knowledge of how the three.js shaders work).

Array of texture identifiers to OpenGL DrawElements/DrawArrays?

An OpenGL ES sequence like this can be used to render multiple objects in one pass:
glVertexPointer(...params..., vertex_Array );
glTexCoordPointer(...params..., texture_Coordinates_Array );
glBindTexture(...params..., one_single_texture_ID );
glDrawArrays( GL_TRIANGLES, number_Triangles );
Here, the vertex array and texture coordinates array can refer to innumerable primitives that can be described in one step to OpenGL.
But do all these primitives' texture coordinates have to reference the one, single texture in the glBindTexture command?
It would be nice to pass in an array of texture identifiers:
glBindTexture(...params..., texture_identifier_array[] );
Here, there would be a texture ID in the array for every primitive shape described in the preceding calls. So, each shape's texture coordinates would pertain to the texture identified in "texture_identifier_array[]".
I can see one option is to place all textures of interest one one large texture that can be referenced as a single entity in the drawing calls. On my platform, this creates an intermediate step with a large bitmap that might cause memory issues.
It would be best for me to be able to pass an array of texture identifiers to the OpenGL ES drawing calls. Can this be done?
No, that's not possible. You could perhaps emulate it by using a texture array and giving your vertices a texture index. Then in the fragment shader you could look up the right texture with the index, but I doubt that ES supports texture arrays. And even then I don't know if this really works. Or if a texture atlas solution would be much more efficient.
If you want to render multiple versions of the same geometry (what I doubt), you're looking for instanced rendering, which also isn't supported by on ES devices, I think.
So the way to go at the moment will be a texture atlas (multiple textures in one) or just calling glDrawArrays multiple times.

OpenGL ES: glBufferSubData fills meshes into VBO/IBO, then glDrawElements renders only the first mesh instead of all of them

My problem seems to be really simple but I just can't get the reason behind it:
I have a vertex and an index buffer that get filled in with glBufferSubData. There are a couple of meshes that get filled in one-by-one into this big VBO and its corresponding IBO
Then I try to render those small meshes with glDrawElements one-by-one
Problem is, only first mesh gets rendered - and multiple times - in places where each of those different meshes should be!!!
Following info may be useful:
I create VBO this way
gl.glGenBuffers(1, buffers_, 0);
gl.glBindBuffer(GL11.GL_ARRAY_BUFFER, buffers_[0]);
gl.glBufferData(GL11.GL_ARRAY_BUFFER, sizeInBytes, null, GL11.GL_DYNAMIC_DRAW);
Then each mesh is filled into the VBO like this
gl.glBindBuffer(GL11.GL_ARRAY_BUFFER, name);
gl.glBufferSubData(GL11.GL_ARRAY_BUFFER, startOffsetInBytes, numBytesToCopy, nioBuffer);
And meshes are rendered in this fasion
bind VBO/IBO and set appropriate client states
then set vertex, normal, and texcoord "pointers" - they point at the beginning of VBO plus their offsets in vertex "structure"
and call gl.glDrawElements(GL10.GL_TRIANGLES, indicesNum, GL10.GL_UNSIGNED_SHORT, startIndexOffsetInBytes);
then finally, unbind VBO/IBO and disable client states
I debugged the code and I'm sure that sizeInBytes, startOffsetInBytes, numBytesToCopy and startIndexOffsetInBytes are correct values (in bytes:))) and indicesNum is the number of indices/vertices in the mesh (to render).
One suspicious place is setting vertex/normal/texcoord pointers - they get set only once - and set to the beginning of the VBO. Maybe I need to set them each time before calling glDrawElements?
:D Found that reason. Everything I described is correct indeed. Problem is in the way meshes are being added into the VBO/IBO - indices for each new mesh were restarted from 0!! So only the first mesh in VBO was getting rendered.

What's the difference between glClient*** gl***?

I'm learning GLES. There are many pair functions like glClientActiveTexture/glActiveTexture.
What's the difference between them? (Especially the case of glClientActiveTexture)
From the openGL documentation:
glActiveTexture glActiveTexture selects which texture unit subsequent texture state calls will affect.
glClientActiveTexture selects the vertex array client state parameters to be modified by glTexCoordPointer.
On one hand, glClientActiveTexture is used to control subsequent glTexCoordPointer calls (with vertex arrays). On the other hand glActiveTexture affects subsequent calls to glTexCoord calls (used by display lists or immediate mode (non existent in OpenGL ES (AFAIK)).
Adding to Kenji's answer, here's a bit more detail (and bearing in mind that not everything in OpenGL is available in ES).
Terminology
But first some quick terminology to try to prevent confusion between all the texturish things (oversimplified for the same reason).
Texture Unit: A set of texture targets (e.g. GL_TEXTURE_2D). It is activated via glActiveTexture
Texture Target: A binding point for a texture. It specifies a type of texture (e.g. 2D). It is set via glBindTexture.
Texture: A thing containing texels (image data, e.g. pixels) and parameters (e.g. wrap and filter mode) that comprise a texture image. It is identified by a key/name/ID, a new one of which you get via glGenTextures, and it is actually instantiated via (first call to) glBindTexture with its name.
Summary: A texture unit has texture targets that are bound to textures.
Texture Unit Activation
In order to have multitexturing with 2D textures (for example), wherein more than one 2D texture must be bound simultaneously for the draw, you use different texture units - bind one texture on one unit's 2D target, and bind the next on another unit's 2D target. glActiveTexture is used to specify which texture unit the subsequent call to glBindTexture will apply to, and glBindTexture is used to specify which texture is bound to which target on the active texture unit.
Since you have multiple textures, you're likely to also have multiple texcoords. Therefore you need some way to communicate to OpenGL/GLSL that one set of texcoords is for one texture/unit, and another set of texcoords is for another. Usually you can do this by just having multiple texcoord attributes in your vertex and corresponding shader. If you're using older rendering techniques that rely on pre-defined vertex attributes in the shader, then you have to do something different, which is where glClientActiveTexture comes in. The confusion happens because it takes an argument for a texture unit, but it does not have the same implications as glActiveTexture of activating a texture unit in the state machine, but rather it designates which pre-defined gl_MultiTexCoord attribute (in the shader) will source the texcoords described in the subsequent call to glTexCoordPointer.
In a nutshell, glActiveTexture is for texture changes, and glClientActiveTexture is for texcoord changes. Which API calls you use depends on which rendering technique you use:
glActiveTexture sets which texture unit will be affected by subsequent context state calls, such as glBindTexture. It does not affect glMultiTexCoord, glTexCoord, or glTexCoordPointer, because those have to do with texcoords, not textures.
glClientActiveTexture sets which texture unit subsequent vertex array state calls apply to, such as glTexCoordPointer. It does not affect glBindTexture, because that has to do with textures, not texcoords.
It also does not affect glMultiTexCoord which uses DSA to select a texture unit via its target parameter, nor does it affect glTexCoord, which targets texture unit 0 (GL_TEXTURE0). This pretty much just leaves glTexCoordPointer as the thing it affects, and glTexCoordPointer is deprecated in favor of glVertexAttribPointer, which doesn't need glClientActiveTexture. As you can see, glClientActiveTexture isn't the most useful, and is thusly deprecated along with the related glWhateverPointer calls.
You'll use glActiveTexture + glBindTexture with all techniques to bind each texture on a specific texture unit. You'll additionally use glClientActiveTexture + glTexCoordPointer when you're using DrawArrays/DrawElements without glVertexAttribPointer.
Multitexturing Examples
As OpenGL has evolved over the years, there are many ways in which to implement multitextured draws. Here are some of the most common:
Use immediate mode (glBegin/glEnd pairs) with GLSL shaders targeted for version 130 or older, and use glMultiTexCoord calls to specify the texcoords.
Use glBindVertexArray and glBindBuffer + glDrawArrays/glDrawElements to specify vertex data, and calls to glVertexPointer, glNormalPointer, glTexCoordPointer, etc., to specify vertex attributes during the draw routine.
Use glBindVertexArray + glDrawArrays/glDrawElements to specify vertex data, with calls to glVertexAttribPointer to specify vertex attributes during the init routine.
Here are some examples of the API flow for multitexturing with two 2D textures using each of these techniques (trimmed for brevity):
Using immediate mode:
init
draw
shutdown
vertex shader
fragment shader
Using DrawElements but not VertexAttribPointer:
init
draw
shutdown
vertex shader (same as immediate mode)
fragment shader (same as immediate mode)
Using DrawElements and VertexAttribPointer:
init
draw
shutdown
vertex shader
fragment shader
Misc. Notes
glMultiTexCoord populates unused coords as 0,0,0,1.
e.g. glMultiTexCoord2f == s,t,0,1
Always use GL_TEXTURE0 + i, not just i.
When using GL_TEXTURE0 + i, i must be within 0 - GL_MAX_TEXTURE_COORDS-1.
GL_MAX_TEXTURE_COORDS is implementation-dependent, but must be at least two, and is at least 80 as of OpenGL 4.0.
glMultiTexCoord is supported on OpenGL 1.3+, or with ARB_multitexture
Do not call glActiveTexture or glBindTexture between glBegin and glEnd. Rather, bind all needed textures to all needed texture units before the draw call.

Resources