Do I need to take care to pack vertex attributes together? - opengl

If I want to pass two nominally independent attribute arrays of floats to a draw call, can I happily have a GLSL in float variable for each of them, or do I need to ensure to pack them into an in vec2 or similar and use the various components to ensure not consuming unnecessary GL_MAX_VERTEX_ATTRIBS "slots"?
Or, in other words; GL_MAX_VERTEX_ATTRIBS specifies, according to the docs, "the maximum number of 4-component generic vertex attributes accessible to a vertex shader". Does an attribute that is less than 4 components always count as one attribute towards this limit?

Does an attribute that is less than 4 components always count as one attribute towards this limit?
Yes, that is exactly what it means.
Each vertex attribute is 4-component, if you write it as float in your shader that actually does not change anything. If you want to see this in action, try setting up a 1-component vertex attribute pointer and then declaring that attribute vec4 in your vertex shader -- GL will automatically assign the values 0.0, 0.0, 1.0 for y, z and w respectively.
If you are hitting the vertex attribute limit (minimum 16) because you're using a bunch of scalars, then you should consider packing your attributes into a vec4 instead for optimal utilization.
There is a minor exception to this rule I described above, for data types with more than 4-components (e.g. mat4). A vertex attribute declared mat4 has 16-components and consumes 4 sequential attribute locations.

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.

Are OpenGL indices and locations the same thing for uniforms and vertex attributes?

In the OpenGL Reference Pages, some functions are marked as using uniform locations, while other functions are marked as using uniform indices. Are these the same thing?
Similarly for vertex attributes, some functions are marked as using vertex attribute indices, while other functions are marked as using vertex attribute locations. Are these the same?
In your first case, the location for an Uniform is different from the index used for glGetActiveUniform().
For glGetActiveUniform() case, index is just a value between 0 and the value you get from glGetProgram( GL_ACTIVE_UNIFORMS,...) minus one. This API allows you to query any resources of the program, and you can iterate over all active uniforms with that method. The uniform locations may not start at 0, and may not be consecutive at all.
In your second example, glGetAttribLocation() and glEnableVertexAttribArray() both refer to the same index. The GL has a set of generic attributes, which are generally referenced by their indices, starting from 0. However, to make things a little bit more interesting, there is also glGetActiveAttrib() which is similiar to the glGetActiveUniform() one: here, the index refers just to the list of active attributes (in the range 0 to the value you get from glGetProgram( GL_ACTIVE_ATTRIBUTES,...) minus one, and not to the actual attribute index/location. Again, this API allows you to iterate over all attributes which are present (and active).

OpenGL instanced drawing how to deal with vertex input limitation

I'd like to implement instanced rendering to my opengl engine but I've just learned that the maximum number of inputs supported by vertex shader is only 16 for my GPU.
These are the following matrices I need to move to input:
uniform mat4 MVP;
uniform mat4 modelMatrix;
uniform mat3 normalMatrix;
uniform mat4 DepthBiasMVP;
If I understand correctly I will need an attribute for every column of each matrix, so I'll need 4+4+3+4 = 15 attribute space. 19 with the attributes that I already use ( pos, color, texCoord, normal ), and it will grow up to 20+ if I add tangents and other stuff.
Is there a way to deal with this or will I have to forget the instanced drawing ? Let's say I managed to get rid of one of these matrices (modelMatrix) and I have about 15 - 16 attributes, will it work on different GPU's ? the 16 limit is the minimum for all GPU's right ?
Note that 16 is the minimum amount of vertex attributes that your implementation actually has; most of the time more are allowed that you can query via:
glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &n).
Now, when trying to store all your data in instanced arrays you should try and organize what the data actually is that you want to differ per instance. Do you have a lot of instanced objects that only differ in location and/or orientation? Then you probably only need to set your uniform modelMatrix as an instanced array (which requires 4 vertex attributes, an acceptable value). Do you really need a different view and projection matrix for each instance? Probably not. The same holds for DepthBiasMVP.
The normalMatrix is required if you perform non-uniform scaling and if you plan to do that for each instance you also need to set a normalMatrix per instance. You could calculate those on the CPU beforehand and send them as vertex attributes costing you another 4 vertex attributes. Another option is to calculate normalMatrix in the vertex shader, but that this might slow your vertex shader down a little (perhaps an acceptable tradeoff?).
These should reduce the information you need per instance to just the modelMatrix and perhaps the normalMatrix, already reducing it by half. Maybe you only have a different position per instance? In that case even a simple vec4 will do.
Basically, try to think about what data you actually need to update per instance and you'll most likely be surprised as to how much data you actually need for each instance.
One can store the per-instance data in uniform arrays, uniform buffer objects or texture buffer objects and use the gl_InstanceID variable in GLSL to access the data in the buffer object. Uniform arrays might seem the easiest, but are most limited in size and hence are only applicable for a low number of instances. UBOs can be a bit bigger, but are also quite limited. TBOs on the other hand will allow you many megabytes of data, but you have to appropriately pack your data there. In your case, it seems that you only need float types, so a base format with 32 bit floats should suffice.

Multiple meshes in the same vertex buffer object?

I want to keep multiple different meshes in the same VBO, so I can draw them with glDrawElementsBaseVertex. How different can vertex specifications for different meshes be in such a VBO in order to be able to draw them like that?
To be more specific:
Can vertex arrays for different meshes have different layouts (interleaved (VNCVNCVNCVNC) vs batch(VVVVNNNNCCCC))?
Can vertices of different meshes have different numbers of attributes?
Can attributes at same shader locations have different sizes for different meshes (vec3, vec4, ...)?
Can attributes at same shader locations have different types for different meshes (GL_FLOAT, GL_HALF_FLOAT, ...)?
P.S.
When i say mesh I mean an array of vertices, where each vertex has some attributes (position, color, normal, uv, ...).
openGL doesn't care what is in each buffer, all it looks at is how the attributes are specified and if they happen to use the same buffer or even overlap then fine. It assumes you know what you are doing.
Yes, if you use a VAO for each mesh then the layout of each is stored in the VAO and binding the other will set the attributes correctly. This way you can define the offset from the start of the buffer so you don't need the glDraw*BaseVertex variants
Yes
not sure
yes they will be auto converted to the correct type as defined in the attributePtr call.
In addition to ratchet freak's answer, I'll only elaborate on point 3:
Yes, you can do that. If you set up your attribute pointers to specify more elements than your shader uses, the additional values are just never used.
If you do it the other way around and read more elements in the shader than are specified in your array, the missing
elements are automatically extened to build a vector of the form (0, 0, 0, 1), so the fourth component will be implicitely 1 and all other (unspecified) ones 0. This makes it possible to use the vectors directly as homogenous coordinates or RGBA colors in many cases.
In many shaders, one sees somehting like
in vec3 pos;
...
gl_Position = matrix * vec4(pos, 1.0);
This is actually not necessary, one could directly use:
in vec4 pos;
...
gl_Position = matrix * pos;
while still storing only 3 component vectors in the attribute array. As a side effect, one now has a shader which also can deal with full 4-component homogenous coordinates.

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!