Use one GL ELEMENT_ARRAY_BUFFER to reference each

2019-03-04 13:21发布

Question

OpenGL 4.4, C++11

Do I have the power to use indices in an element_array_buffer from 0 for each attribute, by setting vertex attributes to both the element_array_buffer, and array_buffer?

Data Layout

VAO      
 Buffer(array_buffer)      
   PositionFloat * n  
   TextureFloat  * n
   NormalFloat   * n
 Buffer(element_array_buffer)      
   PositionIndex * 1
   TextureIndex  * 1
   NormalIndex   * 1

Data Use

//gen
glBindVertexArray(VAO);

glBindBuffer(array_buffer, vbo);
glBufferData(array_buffer, size(vertices), data(vertices), access(vertices));
glVertexAttribPointer(POSITIONS, 3, float, offset(0));
glVertexAttribPointer(UVS,       2, float, offset(positions));
glVertexAttribPointer(NORMALS,   3, float, offset(normals));

glBindBuffer(element_array_buffer, ebo);
glBufferData(element_array_buffer, size(elements), data(elements), access(elements)); 
...?! /*Cannot set element attributes!  
If I could, I would set a strided, offset attribPointer for each attribute, 
so that if 0 appears in the NORMALS attribute, it will look up the first normal, 
and not the first element in the buffer. */

Problem

I write my indices such that I could reference the first vertex, UV, and Normal with 0/0/0. Is it possible to map this into the element_array_buffer and use it as such? Or is my solution to add nPositions to my texture indices, and nPositions+nTextures to my normal indices?

标签: c++ opengl-4
1条回答
放荡不羁爱自由
2楼-- · 2019-03-04 13:58

OpenGL does not support separate indices per vertex attribute. When using buffers for your vertex attributes, you need to create a vertex for each unique combination of vertex attributes.

The canonical example is a cube with positions and normals as vertex attributes. The cube has 8 corners, so it has eight different values for the position attribute. It has 6 sides, so it has 6 different values for the normal attribute. How many vertices does the cube have? In OpenGL, the answer is... 24.

There are at least two ways to derive why the number of vertices in this case is 24:

  • The cube has 6 sides. We can't share vertices between sides because they have different normals. Each side has 4 corners, so we need 4 vertices per side. 6 * 4 = 24.
  • The cube has 8 corners. At each of these 8 corners, 3 sides meet. Since these 3 sides have different normals, we need a different vertex for each of them. 8 * 3 = 24.

Now, since you specifically ask about OpenGL 4.4, there are other options that can be considered. For example, you could specify the value of your vertex attributes to be indices instead of coordinates. Since you can of course use multiple vertex attributes, you can have multiple indices for each vertex. Your vertex shader then gets these indices as the values of vertex attributes. It can then retrieve the actual attribute values from a different source. Possibilities for these sources include:

  • Uniform buffers.
  • Texture buffers.
  • Textures.

I'm not convinced that any of these would be as efficient as simply using vertex attributes in a more traditional way. But it could be worth trying if you want to explore all your options.

Instanced rendering is another method that can sometimes help to render different combinations of vertex attributes without enumerating all combinations. But this only really works if your geometry is repetitive. For example, if you wanted to render many cubes with a single draw call, and use a different color for each of them, instanced rendering would work perfectly.

查看更多
登录 后发表回答