How to access Vertex Indices in Fragment Shader GLSL - opengl

I am drawing indexed GL_LINES with OpenGL. I need to access the indices in my fragment shader for both vertices. Thus I need to know the two indices my line consists of. I read about the built-in variable gl_VertexID which should not be that helpful here. As I already have stored my indices in some buffer I am trying to pass them as an attribute too.
Thus my code looks like the following:
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER,vertexBuffer);
glVertexAttribPointer(0,2,GL_FLOAT,GL_FALSE,0,(void*)0);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER,indexBuffer);
glVertexAttribPointer(1,2,GL_UNSIGNED_INT,GL_FALSE,0,(void*)0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,indexBuffer);
Using this seem to be the wrong way to go, right?
Furthermore I use the indices to write some information via image load store atomically. Unfortunatly fetching this image via glGetTexImage yields only zeros.
So either my index passing or my image writing/fetching seems to be wrong.
I would be glad for any help here.

For attributes that have integer types in the vertex shader, you need to use glVertexAttribIPointer() (note the additional I) instead of glVertexAttribPointer().
Since you only have one index per vertex, the second argument, which is the size, should be 1. The call will then look like this:
glVertexAttribIPointer(1, 1, GL_UNSIGNED_INT, 0, (void*)0);
What you're doing seems somewhat unusual, but I can't think of a reason why using the index array as a vertex attribute would be illegal.
I believe gl_VertexID is just a sequential id of the vertices produced by the draw command, which is not the same as the vertex index.

Related

Passing Array to Vertex Shader as Attribute

I am doing some LBS, and I need to use more than 4 weights, and indices (Let's say I need 60 float values, and 60 int values).
I am using GLSL version 1.30, so I cannot use Shader Storage Buffer Object. Since this weight, and index information will be different for each vertex, cannot use uniform, and I guess there is no way to define an array with a fixed size (for example float arr[16]) if you are not using uniform. Additionally, for attribute inputs, I can only use vec/mat 2,3 or 4.
So, do you have any idea how I can solve this problem?
A first approach would be to just pass them as normal vertex attributes. There is though a driver specific maximum number of vertex attributes.
A better approach, that should work with every driver and with an arbitrary amount of attributes (not infinite, but pretty many) is, to store the vertex attributes in a texture.
A simple setup would be to create a NxM texture, where N=#vertex_attributes and M=#vertices. Each vertex has then only one attribute, that indicates a line of the texture. In the vertex shader you can then read one line of the texture per vertex and have all your attributes.

Get element ID in vertex shader in OpenGL

I'm rendering a line that is composed of triangles in OpenGL.
Right now I have it working where:
Vertex buffer: {v0, v1, v2, v3}
Index buffer (triangle strip): {0, 1, 2, 3}
The top image is the raw data passed into the vertex shader and the bottom is the vertex shader output after applying an offset to v1 and v3 (using a vertex attribute).
My goal is to use one vertex per point on the line and generate the offset some other way. I was looking at gl_VertexID, but I want something more like an element ID. Here's my desired setup:
Vertex buffer: {v0, v2}
Index buffer (triangle strip): {0, 0, 1, 1}
and use an imaginary gl_ElementID % 2 to offset every other vertex.
I'm trying to avoid using geometry shaders or additional vertex attributes. Is there any way of doing this? I'm open to completely different ideas.
I can think of one way to avoid the geometry shader and still work with a compact representation: instanced rendering. Just draw many instances of one quad (as a triangle strip), and define the two positions as per-instance attributes via glVertexAttribDivisor().
Note that you don't need a "template quad" with 4 vertices at all. You just need conceptually two attributes, one for your start point, and one for your end point. (If you work in 2D, you can fuse that into one vec4, of course). In each vertex shader invocation, you will have access to both points, and can construct the final vertex position based on that and the value of gl_VertexID (which will only be in range 0 to 3). That way, you can get away with exactly that vertex array layout of two points per line segment you are aiming for, and still only need a single draw call and a vertex shader.
No, that is not possible, because each vertex is only processed once. So if you're referencing a vertex 10 times with an index buffer, the corresponding vertex shader is still only executed one time.
This is implemented in hardware with the Post Transform Cache.
In the absolute best case, you never have to process the same vertex
more than once.
The test for whether a vertex is the same as a previous one is
somewhat indirect. It would be impractical to test all of the
user-defined attributes for inequality. So instead, a different means
is used.
Two vertices are considered equal (within a single rendering command)
if the vertex's index and instance count are the same (gl_VertexID​
and gl_InstanceID​ in the shader). Since vertices for non-indexed
rendering are always increasing, it is not possible to use the post
transform cache with non-indexed rendering.
If the vertex is in the post transform cache, then that vertex data is
not necessarily even read from the input vertex arrays again. The
process skips the read and vertex shader execution steps, and simply
adds another copy of that vertex's post-transform data to the output
stream.
To solve your problem I would use a geometry shader with a line (or line strip) as input and a triangle strip as output. With this setup you could get rid of the index buffer, since it's only working on lines.

glVertexAttribPointer clarification

Just want to make sure I understand this correctly (I'd ask on SO Chat, but it's dead in there!):
We've got a Vertex Array, which we make "current" by binding it
then we've got a Buffer, which we bind to a Target
then we fill that Target via glBufferData
which essentially populates whatever was bound to that target, i.e. our Buffer
and then we call glVertexAttribPointer which describes how the data is laid out -- the data being whatever is bound to GL_ARRAY_BUFFER
and this descriptor is saved to our original Vertex Array
(1) Is my understanding correct?
The documentation is a little sparse about how everything correlates.
(2) Is there some kind of default Vertex Array? Because I forgot/omitted glGenVertexArrays and glBindVertexArray and my program worked fine without it.
Edit: I missed a step... glEnableVertexAttribArray.
(3) Is the Vertex Attrib tied to the Vertex Array at the time glVertexAttribPointer is called, and then we can enable/disable that attrib via glEnableVertexAttribArray at any time, regardless of which Vertex Array is currently bound?
Or (3b) Is the Vertex Attrib tied to the Vertex Array at the time glEnableVertexAttribArray is called, and thus we can add the same Vertex Attrib to multiple Vertex Arrays by calling glEnableVertexAttribArray at different times, when different Vertex Arrays are bound?
Some of the terminology is a bit off:
A Vertex Array is just an array (typically a float[]) that contains vertex data. It doesn't need to be bound to anything. Not to be confused with a Vertex Array Object or VAO, which I will go over later
A Buffer Object, commonly referred to as a Vertex Buffer Object when storing vertices, or VBO for short, is what you're calling just a Buffer.
Nothing gets saved back to the vertex array, glVertexAttribPointer works exactly like glVertexPointer or glTexCoordPointer work, just instead of named attributes, you get to provide a number that specifies your own attribute. You pass this value as index. All your glVertexAttribPointer calls get queued up for the next time you call glDrawArrays or glDrawElements. If you have a VAO bound, the VAO will store the settings for all your attributes.
The main issue here is that you're confusing vertex attributes with VAOs. Vertex attributes are just the new way of defining vertices, texcoords, normals, etc. for drawing. VAOs store state. I'm first going to explain how drawing works with vertex attributes, then explain how you can cut down the number of method calls with VAOs:
You must enable an attribute before you can use it in a shader. For example, if you want to send vertices over to a shader, you're most likely going to send it as the first attribute, 0. So before you render, you need to enable it with glEnableVertexAttribArray(0);.
Now that an attribute is enabled, you need to define the data it's going to use. In order to do so you need to bind your VBO - glBindBuffer(GL_ARRAY_BUFFER, myBuffer);.
And now we can define the attribute - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);. In order of parameter: 0 is the attribute you're defining, 3 is the size of each vertex, GL_FLOAT is the type, GL_FALSE means to not normalize each vertex, the last 2 zeros mean that there's no stride or offset on the vertices.
Draw something with it - glDrawArrays(GL_TRIANGLES, 0, 6);
The next thing you draw may not use attribute 0 (realistically it will, but this is an example), so we can disable it - glDisableVertexAttribArray(0);
Wrap that in glUseProgram() calls and you have a rendering system that works with shaders properly. But let's say you have 5 different attributes, vertices, texcoords, normals, color, and lightmap coordinates. First of all, you would be making a single glVertexAttribPointer call for each of these attributes, and you'd have to enable all the attributes beforehand. Let's say you define the attributes 0-4 as I have them listed. You would enable all of them like so:
for (int i = 0; i < 5; i++)
glEnableVertexAttribArray(i);
And then you would have to bind different VBOs for each attribute (unless you store them all in one VBO and use offsets/stride), then you need to make 5 different glVertexAttribPointer calls, from glVertexAttribPointer(0,...); to glVertexAttribPointer(4,...); for vertices to lightmap coordinates respectively.
Hopefully that system alone makes sense. Now I'm going to move on to VAOs to explain how to use them to cut down on the number of method calls when doing this type of rendering. Note that using a VAO is not necessary.
A Vertex Array Object or VAO is used to store the state of all the glVertexAttribPointer calls and the VBOs that were targeted when each of the glVertexAttribPointer calls were made.
You generate one with a call to glGenVertexArrays. To store everything you need in a VAO, bind it with glBindVertexArray, then do a full draw call. All the draw bind calls get intercepted and stored by the VAO. You can unbind the VAO with glBindVertexArray(0);
Now when you want to draw the object, you don't need to re-call all the VBO binds or the glVertexAttribPointer calls, you just need to bind the VAO with glBindVertexArray then call glDrawArrays or glDrawElements and you'll be drawing the exact same thing as though you were making all those method calls. You probably want to unbind the VAO afterwards too.
Once you unbind the VAO, all the state returns to how it was before you bound the VAO. I'm not sure if any changes you make while the VAO is bound is kept, but that can easily be figured out with a test program. I guess you can think of glBindVertexArray(0); as binding to the "default" VAO...
Update: Someone brought to my attention the need for the actual draw call. As it turns out, you don't actually need to do a FULL draw call when setting up the VAO, just all the binding stuff. Don't know why I thought it was necessary earlier, but it's fixed now.
The terminology and sequence of APIs to be called is quite confusing indeed. What's even more confusing is how the various aspects - buffer, generic vertex attribute and shader attribute variable get associated. See OpenGL-Terminology for a pretty good explanation.
Further, the link OpenGL-VBO,shader,VAO shows a simple example with the necessary API calls. It's particularly good for those transitioning from immediate mode to the programmable pipeline.
Hope it helps.
Edit: As you can see from the comments below, people can make assumptions and jump to conclusions. The reality is that it's quite confusing for beginners.

*BaseVertex and gl_VertexID

I've skimmed through the specs and OpenGL forum but couldn't really make sense of this:
Are the *BaseVertex version of the drawing commands supposed to add to the GLSL variable gl_VertexID? As it works, gl_VertexID contains the index taken from the the bound ELEMENT_ARRAY_BUFFER before basevertex is added to it.
So, my question is: Is this the correct behavior? I would assume that gl_VertexID should contain the index used to fetch the vertex.
Yes this is the correct bahviour. The usage scenario of BaseVertex is, that you have to switch only this one value, instead of adjusting the buffer offsets into the vertex arrays with the gl*Pointer functions.
The idea is, that you can load the data from multiple meshes (model files) into a single VBO, without the need to adjust the indices.
Your assumption is right. gl_VertexID should include BaseVertex offset.
opengl wiki about GLSL built-in vars:
Note: gl_VertexID​ will have the base vertex applied to it.
about glDrawElementsBaseVertex:
The gl_VertexID​ passed to the Vertex Shader will be the index after being offset by basevertex​, not the index fetched from the buffer.
Unfortunately, some old drivers didn't implement it correctly.

openGL glDrawElements with interleaved buffers

Thus far i have only used glDrawArrays and would like to move over to using an index buffer and indexed triangles. I am drawing a somewhat complicated object with texture coords, normals and vertex coords. All this data is gathered into a single interleaved vertex buffer and drawn using calls similar to ( Assuming all the serup is done correctly ):
glVertexPointer( 3, GL_FLOAT, 22, (char*)m_vertexData );
glNormalPointer( GL_SHORT, 22, (char*)m_vertexData+(12) );
glTexCoordPointer( 2, GL_SHORT, 22, (char*)m_vertexData+(18) );
glDrawElements(GL_TRIANGLES, m_numTriangles, GL_UNSIGNED_SHORT, m_indexData );
Does this allow for m_indexData to also be interleaved with the indices of my normals and texture coords as well as the standard position index array? Or does it assume a single linear list of inidices that apply to the entire vertex format ( POS, NOR, TEX )? If the latter is true, how is it possible to render the same vertex with different texture coords or normals?
I guess this question could also be rephrased into: if i had 3 seperate indexed lists ( POS, NOR, TEX ) where the latter 2 cannot be rearranged to share the same index list as the first, what is the best way to render that.
You cannot have different indexes for the different lists. When you specify glArrayElement(3) then OpenGL is going to take the 3rd element of every list.
What you can do is play with the pointer you specify since essentially the place in the list which is eventually accessed is the pointer offset from the start of the list plus the index you specify. This is useful if you have a constant offset between the lists. if the lists are just a random permutation then this kind of play for every vertex is probably going to be as costy as just using plain old glVertex3fv(), glNormal3fv() and glTexCoord3fv()
I am having similar trouble attempting to do the same in Direct3D 9.0
For my OpenGL 3 implementation it was rather easy, and my source code is available online if it might help you any...
https://github.com/RobertBColton/enigma-dev/blob/master/ENIGMAsystem/SHELL/Graphics_Systems/OpenGL3/GL3model.cpp