Passing Array to Vertex Shader as Attribute - opengl

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.

Related

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.

Custom Vertex Attributes GLSL

I want to make a couple of vec4 vertex attributes in my shaders. I've done quite a bit of googling, but I can't seem to find consistent information for specifically what I want to do.
My goal here is to move skinning to the GPU, so I need a list of bones and weights per vertex, hence why I want to use vertex attributes. I have 2 arrays of floats that represent this data. Basically this:
weightsBuffer = new float[vSize*4];
indexesBuffer = new int[vSize*4];
The part that I can't consistently find is how to upload these and use them in the shader. To be clear, I don't want to upload all the position, normal and texture coordinate data, I'm already using display lists and have decided to keep using them for a few reasons that aren't relevant. How can I create the buffers and bind them properly so I can use them?
Thanks.
Binding your bone weights and indices is no different of a process than binding your position data. Assuming the data is generated properly in your buffers, you use glBindAttribLocation to bind the attribute index in your vertex stream to your shader variable, and glVertexAttribPointer to define your vertex array (and don't forget glEnableVertexAttribArray).
The exact code may vary, depending on whether you're using VAOs and VBOs (or just client buffers). If you want a more specific answer, you should provide your code and shader.

How do I efficiently handle a large number of per vertex attributes in OpenGL?

The number of per vertex attributes that I need to calculate my vertex shader output is bigger than GL_MAX_VERTEX_ATTRIBS. Is there an efficient way to e.g. point to a number of buffers using a uniform array of indices and to access the per vertex data this way?
This is a hardware limitation so the short answer is no.
If you consider workarounds for other ways, like using uniforms that also got limitations so that is a no way to go either.
One possible way I can think of which is rather hackish is to get the extra data from a texture. Since you can access textures from the vertex shader, but texture filtering is not supported ( you wont need it so it doesn't matter for you ).
With the newer OpenGLs its possible to store rather large amount of data in textures and access them without limitation even in the vertex shader, it seems to be one way to go.
Altho with this approach there is a problem you need to face, how do you know the current index, i.e. which vertex it is?
You can check out gl_VertexID built-in for that.
You could bypass the input assembler and bind the extra attributes in an SSBO or texture. Then you can use gl_VertexID in the vertex shader to get the value of index buffer entry you are currently rendering (eg: the index in the vertex data you need to read from)
So for example in a VS the following code is essentially identical (it may however have different performance characteristics depending on your hardware)
in vec3 myAttr;
void main() {
vec3 vertexValue = myAttr;
//etc
}
vs.
buffer myAttrBuffer {
vec3 myAttr[];
};
void main() {
vec3 vertexValue = myAttr[gl_VertexID];
//etc
}
The CPU-side binding code is different, but generally that's the concept. myAttr counts towards GL_MAX_VERTEX_ATTRIBS, but myAttrBuffer does not since it is loaded explicitly by the shader.
You could even use the same buffer object in both cases by binding with a different target.
If you can not absolutely limit yourself to GL_MAX_VERTEX_ATTRIBS attributes, I would advise using multi pass shaders. Redesign your code to work with data with half set of attributes in first pass, and the remaining in second pass.

OpenGL How Many VAOs

I am writing an OpenGL3+ application and have some confusion about the use of VAOs. Right now I just have one VAO, a normalised quad set around the origin. This single VAO contains 3 VBOs; one for positions, one for surface normals, and one GL_ELEMENT_ARRAY_BUFFER for indexing (so I can store just 4 vertices, rather than 6).
I have set up some helper methods to draw objects to the scene, such as drawCube() which takes position and rotation values and follows the procedure;
Bind the quad VAO.
Per cube face:
Create a model matrix that represents this face.
Upload the model matrix to the uniform mat4 model vertex shader variable.
Call glDrawElements() to draw the quad into the position for this face.
I have just set about the task of adding per-cube colors and realised that I can't add my color VBO to the single VAO as it will change with each cube, and this doesn't feel right.
I have just read the question; OpenGL VAO best practices, which tells me that my approach is wrong, and that I should use more VAOs to save the work of setting the whole scene up every time.
How many VAOs should be used? Clearly my approach of having 1 is not optimal, should there be a VAO for every static surface in the scene? What about ones that move?
I am writing to a uniform variable for each vertex, is that correct? I read that uniform shader variables should not change mid-frame, if I am able to write different values to my uniform variable, how do uniforms differ from simple in variables in a vertex shader?
Clearly my approach of having 1 is not optimal, should there be a VAO for every static surface in the scene?
Absolutely not. Switching VAOs is costly. If you allocate one VAO per object in your scene, you need to switch the VAO before rendering such objects. Scale that up to a few hundred or thousand objects currently visible and you get just as much VAO changes. The questions is, if you have multiple objects which share a common memory layout, i.e. sizes/types/normalization/strides of elements are the same, why would you want to define multiple VAOs that all store the same information? You control the offset where you want to start pulling vertex attributes from directly with a corresponding draw call.
For non-indexed geometry this is trivial, since you provide a first (or an array of offsets in the multi-draw case) argument to gl[Multi]DrawArrays*() which defines the offset into the associated ARRAY_BUFFER's data store.
For indexed geometry, and if you store indices for multiple objects in a single ELEMENT_ARRAY_BUFFER, you can use gl[Multi]DrawElementsBaseVertex to provide a constant offset for indices or manually offset your indices by adding a constant offset before uploading them to the buffer object.
Being able to provide offsets into a buffer store also implies that you can store multiple distinct objects in a single ARRAY_BUFFER and corresponding indices in a single ELEMENT_ARRAY_BUFFER. However, how large buffer objects should be depends on your hardware and vendors differ in their recommendations.
I am writing to a uniform variable for each vertex, is that correct? I read that uniform shader variables should not change mid-frame, if I am able to write different values to my uniform variable, how do uniforms differ from simple in variables in a vertex shader?
First of all, a uniforms and shader input/output variables declared as in/out differ in various instances:
input/output variables define an interface between shader stages, i.e. output variables in one shader stage are backed by a corresponding and equally named input variable in the following stage. A uniform is available in all stages if declared with the same name and is constant until changed by the application.
input variables inside a vertex shader are filled from an ARRAY_BUFFER. Uniforms inside a uniform block are backed a UNIFORM_BUFFER.
input variables can also be written directly using the glVertexAttrib*() family of functions. single uniforms are written using the glUniform*() family of functions.
the values of uniforms are program state. the values of input variables are not.
The semantic difference should also be obvious: uniforms, as their name suggests, are usually constant among a set of primitives, whereas input variables usually change per vertex or fragment (due to interpolation).
EDIT: To clarify and to factor in Nicol Bolas' remark: Uniforms cannot be changed by the application for a set of vertices submitted by a single draw call, neither can vertex attributes by calling glVertexAttrib*(). Vertex shader inputs backed by a buffer objects will change either once per vertex or at some specific rate set by glVertexAttribDivisor.
EDIT2: To clarify how a VAO can theoretically store multiple layouts, you can simply define multiple arrays with different indices but equal semantics. For instance,
glVertexAttribPointer(0, 4, ....);
and
glVertexAttribPointer(1, 3, ....);
could define two arrays with indices 0 and 1, component sized 3 and 4 and both refer to position attributes of vertices. However, depending on what you want to render, you can bind a hypothetical vertex shader input
// if you have GL_ARB_explicit_attrib_location or GL3.3 available, use explicit
// locations
/*layout(location = 0)*/ in vec4 Position;
or
/*layout(location = 1)*/ in vec3 Position;
to either index 0 or 1 explicitly or glBindAttribLocation() and still use the same VAO. AFAIK, the spec says nothing about what happens if an attribute is enabled but not sourced by the current shader but I suspect implementation to simply ignore the attribute in that case.
Whether you source the data for said attributes from the same or a different buffer object is another question but of course possible.
Personally I tend to use one VBO and VAO per layout, i.e. if my data is made up of an equal number of attributes with the same properties, I put them into a single VBO and a single VAO.
In general: You can experiment with this stuff a lot. Do it!

Substituting color with vertex attributes

I have a large set of vertices and currently use glColorPointer to specify their color. The problem is, that glColorPointer only accepts a size of 3 or 4 as its first parameter but the value of R, G and B for each vertex is identical.
Of course, I could use glVertexAttribPointer to specify each color value as an attribute of size one and duplicate it in a shader, but I'm looking for a way to do this in the fixed function pipeline.
Calling glColor1* is unfortunately out of the question given the amount of vertices (Yes, I tried it).
Any creative solution that squeezes the value into something else is also OK.
I think without shaders this won't be possible since, well, glColorPointer only accepts a size of 3 or 4, like you already found out (there should also be no glColor1, only glColor3 and glColor4).
You might trick glColorPointer to use your tightly packed array by specifying a size of 3 but a stride of 1 (ubyte) or 4 (float). But this will give you a color of (Ri, Ri+1, Ri+2) for vertex i and there is no way to adjust it to (Ri, Ri, Ri), since the color matrix is not applied to per-vertex colors but only to pixel images.
So without shaders you don't have much creativity left. What you could do is use a 1D texture of size 256, which contains all the grey colors from (0, 0, 0) to (255, 255, 255) in order. Then you can just use your per-vertex color as 1D texture coordinate into that texture. But I'm not sure if that would really buy you anything in either space or time.
The easy and straightforward way is to use vertex attributes and a shader to implement the unpacking of the attribute into the fragment color. This takes just a few lines of shader code and should be the preferred solution. The real difficulty here is the artificial restriction, not the problem space itself. Such cases should be handled by lifting the restriction.
You can store the color information in an 1D texture (with only one channel), then you can use a vertex shader which reads the proper color based on the gl_vertexID.