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?
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.
Related
https://www.khronos.org/opengl/wiki/Vertex_Shader says that "The vertex shader will be executed roughly once for every vertex in the stream."
If we are rendering a cube, vertex could refer to the 8 vertexes of the entire shape (meaning One). Or, it could refer to the 24 vertexes of the 6 squares with 4 corners each (meaning Two).
As I understand it, if a cube is being rendered, the 8 corners of the cube have to be converted into the coordinate system of the viewer. But also there are texture coordinates that have to be calculated based on the individual textures associate with each face of the cube.
So if "vertex" is intended by meaning One, then why are textures being supplied to a shader which is a per face concept? Or if "vertexes" are being fed to the shader by meaning two, does that mean that the coordinate transforms and projections are all being done redundantly? Or is something else going on? These guides seem to have an allergy to actually saying what is going on.
The page on Vertex Specification could be a bit more clear on this, but a vertex is just a single index in the set of vertex arrays as requested by a rendering operation.
That is, you render some number of vertices from your vertex arrays. You could be specifying these vertices as a range of indices from a given start index to an end index (glDrawArrays), or you could specify a set of indices in order to use (glDrawElements). Regardless of how you do it, you get one vertex for each datum specified by your rendering command. If you render 10 indices with indexed rendering, you get 10 vertices.
Each vertex is composed of data fetched from the active vertex arrays in the currently bound VAO. Given the index for that vertex, a value is fetched from each active array at that index. Each individual array feeds a vertex attribute, which is passed to the vertex shader.
A vertex shader operates on the attributes of a vertex (passed as in qualified variables).
The relationship between a "vertex" and your geometry's vertices is entirely up to you. Vertices usually include positions as part of their vertex attributes, but they usually also include other stuff. The only limitation is that the value fetched for each attribute of a particular vertex always uses the same vertex index.
How you live within those rules is up to you and your data.
Suppose we are drawing a cube in 3 ways: points, wireframe and shaded. The same 8 points are used for both drawing commands, but the points can just be drawn from the vbo, the wireframe is connecting pairs of points, and the shaded version needs triangles.
This can be achieved using two index arrays. For wireframe:
uint32_t lineIndices[] = {
0,1, 1,2, 2,3, 3,0,
4,5, 5,6, 6,7, 7,4,
0,4, 1,5, 2,6, 3,7
};
suppose these numbers are bound into an index array lbo. To draw the lines would be:
drawElements(GL_LINES, 24, GL_UNSIGNED_INT, BUFFER_OFFSET(0));
If instead I want to draw triangles, I need a different index.
If I have two indices, lbo and sbo, can both be in the same vao? Can I just bind the one that I want currently so it is used? If not, is it possible to share the same vbo across multiple vaos and have each index in a different vao?
Yes, you can put multiple sequences of indices within one index buffer.
The last argument of glDrawElements() (void* indices) is actually not a pointer to memory but rather a starting byte offset into your index buffer. You can draw a subset of your indices by simply specifying the byte offset of the first index you want to draw, and specifying the number of indices to draw with the count argument as usual.
For example, your index buffer could contain the 8 indices required to draw the cube as points, then the 24 indices required to draw the cube as lines, then the 36 indices required to draw the cube as triangles. If you want to draw the cube as lines, you could compute the byte offset of the first index (8 * sizeof(uint32_t)), and then simply call glDrawElements() as you have already, but passing this offset as the last argument.
Side note: the index buffer is usually abbreviated as EBO for "element buffer object," rather than IBO.
I have a beamforming program running on CUDA and i have to display the output of the beam in Opengl,I have to draw a rectangle in Opengl which is composed of an array of 24x12 small squares.I have to color each of these squares with a different color based on an output from a CUDA program doing the beamforming. I have been able to draw the reactangle using a VBO to which I pass an array containing the vertices of the squares and the color of each vertices using the following a structure. The overall summary of the problem that I am facing is that I am not able to assign the colors to each of the squares correctly. Some excerpts from the code :
struct attributes {
GLfloat coords[2]; //co-ordinates of the vertices
GLfloat color[3]; //color of the vertices
};
glGenBuffers(1, &vbo_romanis); // vbo_romanis is the VBO for drawing the frame
glBindBuffer(GL_ARRAY_BUFFER, vbo_romanis);
glBufferData(GL_ARRAY_BUFFER, sizeof(Vertices), Vertices, GL_STREAM_DRAW);
glShadeModel (GL_SMOOTH);
glUseProgram(program);
glEnableVertexAttribArray(attribute_coord);
glEnableVertexAttribArray(attribute_color);
glBindBuffer(GL_ARRAY_BUFFER, vbo_romanis);
glVertexAttribPointer(
attribute_coord2d, // attribute
2, // number of elements per vertex, here (x,y)
GL_FLOAT, // the type of each element
GL_FALSE, // take our values as-is
sizeof(struct attributes), // next coord2 appears every 5 floats
0 // offset of first element
);
glVertexAttribPointer(
attribute_color, // attribute
3, // number of elements per vertex, here (r,g,b)
GL_FLOAT, // the type of each element
GL_FALSE, // take our values as-is
sizeof(struct attributes), // stride
(GLvoid*) offsetof(struct attributes, color) // offset
);
/* Push each element in buffer_vertices to the vertex shader */
glDrawArrays(GL_QUADS, 0, 4*NUM_SQRS);
So I am facing 2 issues when i draw the array:
the colors not appearing as I want them to. From what I have read about Opengl, the color of the vertices once assigned cannot be changed. But since all the squares share vertices among them, the colors are probably messed up. If I give the same color to all the vertices,it works fine, but not when I want to draw all squares of different colors. So, if someone can point to how I can assign a different color to each of the squares that would really helpful.
How do I update the colors of the vertices for each frame, Do i need to redraw the entire frame or is there a way to just update the colors of the vertices only.
I am completely new to OpenGL programming and any help would be much appreciated.
It is not clear what your vertex data actually is, but this:
But since all the squares share vertices among them, the colors are
probably messed up.
implies to me that you are trying to use the following data for two adjacent squares (A-F being the vertices):
A---B---C
| | |
| | |
D---E---F
However, in OpenGL, a vertex is the set of all attributes, not just the postion. What you get here is that the colors will be smoothly interpolated between the squares. So technically, you need to duplicate the vertices B and E into B1/B2 and E1/E2, with B1,E1 beeing the color of the lieft square, and B2,E2 that of the right square, but the same coordiantes.
However, for your problem, there might be a shortcut, in form of flat shading by declaring your vaertex shader outputs as flat. Vertex shader outputs (varyings) are by default interpolated across the whole primitive. However, defining them as flat will prevent the interpolation. Instead, the value from just one vertex is used for the whole primitive. OpenGL uses the conecpt of the provoking vertex to define which vertex of a primitive will be the one defining the values for such flat outputs.
The command glProvokingVertex() might be used to specify the general rules for which vertex is to be selected, you can choose between the first and the last. If you cleverly construct your vertex data, you can get a vertex to be shared for both triangles of one square that will be the provoking vertex for both, so you can define the color for each "grid cell" with just the color of one corner vertex of the cell, and do not have any need for duplicating vertices.
As a side note: you have the commang glShadeModel(GL_SMOOTH); in your code. This is deprecated and also totally useless when you use the programmable pipeline, as your comments imply. However, conceptually, this is the exact opposite of the flat shading approach I'm suggesting here.
How do I update the colors of the vertices for each frame, Do i need
to redraw the entire frame or is there a way to just update the colors
of the vertices only.
OpenGL is not a scene graph library. It does not remember which objects you have drawn in the past and does not allow changing their attributes. OpenGL is a rendering API, so if you want something different to appear on the screen, you have to tell it to draw again. If you plan on updating the colors without changing the positions of the squares itself, you might be even better off using two non-interleaved VBOs to split color and position data. That way, you can have the positions statically in one buffer, and stream only the color updates in another.
As I understand it, glDrawArraysInstanced() will draw a VBO n times. glVertexAttribDivisor() using 1, so that each instance has a unique attribute in the shader. So far I can pass a different color for each instance, with vec4*instances, and each vertex in that instance will share that attribute, hence each instance of a triangle has a different color.
However, what I'm looking for is a type of divisor that will advance the attribute per vertex for each instance, and the best example would be a different color for each vertex in a triangle, for each instance. I would fill a VBO with 3*vec4*instances.
Eg. I want to draw 2 triangles using instancing:
color_vbo [] = {
vec4, vec4, vec4, // first triangle's vertex colors
vec4, vec4, vec4 // second triangle's vertex colors
}; // Imagine this is data in a VBO
glDrawArraysInstanced(GL_TRIANGLES, 0, 3(vertexes), 2(instances));
If I set the attribute divisor to 0, it will use the first 3 colors of the color_vbo everywhere, rather than advancing.
Effectively each vertex should get the attribute from the VBO as if it were:
color_attribute = color_vbo[(vertex_count * current_instance) + current_vertex];
I don't think what you're asking for is possible using vertex attribute divisors.
It is possible to do this sort of thing using a technique described in OpenGL Insights as "Programmable Vertex Pulling", where you read vertex data from a texture buffer using whatever calculation you like (using gl_VertexID and gl_InstanceID).
Another possibility would be to use three vertex attributes (each with a divisor of 1) to store the colours of each triangle point and use gl_VertexID to choose which of the attributes to use for any given vertex. Obviously this solution doesn't scale to having much more than three vertices per instance.
I'm currently programming a .obj loader in OpenGL. I store the vertex data in a VBO, then bind it using Vertex Attribs. Same for normals. Thing is, the normal data and vertex data aren't stored in the same order.
The indices I give to glDrawElements to render the mesh are used, I suppose, by OpenGL to get vertices in the vertex VBO and to get normals in the normals VBO.
Is there an opengl way, besides using glBegin/glVertex/glNormal/glEnd to tell glDrawElements to use an index for vertices and an other index for normals?
Thanks
There is no direct way to do this, although you could simulate it by indexing into a buffer texture (OpenGL 3.1 feature) inside a shader.
It is generally not advisable to do such a thing though. The OBJ format allows one normal to be referenced by several (in principle any number of) vertices at a time, so the usual thing to do is constructing a "complete" vertex including coordinates and normal and texcoords for each vertex (duplicating the respective data).
This ensures that
a) smooth shaded surfaces render correctly
b) hard edges render correctly
(the difference between the two being only several vertices sharing the same, identical normal)
You have to use the same index for position/normals/texture coords etc. It means that when loading the .obj, you must insert unique vertices and point your faces to them.
OpenGL treats a vertex as a single, long vector of
(position, normal, texcoord[0]…texcoord[n], attrib[0]…attrib[n])
and these long vectors are indexed. Your question falls into the same category like how to use shared vertices with multiple normals. And the canonical answer is, that those vertices are in fact not shared, because in the long term they are not identical.
So what you have to do is iterating over the index array of faces and construct the "long" vertices adding those into a (new) list with a uniquenes constraint; a (hash) map from the vertex → index serves this job. Something like this
next_uniq_index = 0
for f in faces:
for i in f.indices:
vpos = vertices[i.vertex]
norm = normals[i.normal]
texc = texcoords[i.texcoord]
vert = tuple(vpos, norm, texc)
key
if uniq_vertices.has_key(key):
uniq_faces_indices.append(uniq_vertices[key].index)
else:
uniq_vertices[key] = {vertex = key, index = next_uniq_index}
next_uniq_index = next_uniq_index + 1