I am trying to save the uniform locations of an array, to a std::map in my Shader class.
My vertex shader has an array uniforms to a mat4.
uniform mat4 bone_matrices[32];
In the following code the bone matrices name shows up as bone_matrices[0]. So I am only getting the location for the first array member. [I think the others are sequential.]
class Shader
{
...
private:
GLuint mi_program;
std::map<std::string, GLint> m_maplocations;
};
void Shader::mapLocations()
{
GLint numUniforms = 0;
const GLenum properties[5] = {GL_BLOCK_INDEX, GL_TYPE, GL_NAME_LENGTH, GL_LOCATION, GL_ARRAY_SIZE};
glGetProgramInterfaceiv(mi_program, GL_UNIFORM, GL_ACTIVE_RESOURCES, &numUniforms);
for(int unif = 0; unif < numUniforms; ++unif)
{
GLint values[5];
glGetProgramResourceiv(mi_program, GL_UNIFORM, unif, 5, properties, 5, NULL, values);
// Skip any uniforms that are in a block.
if(values[0] != -1)
continue;
std::string nameData;
nameData.resize(values[2]);
if(values[4] > 1)
{
// **have an array here**
}
glGetProgramResourceName(mi_program, GL_UNIFORM, unif, nameData.size(), NULL, &nameData[0]);
std::string name(nameData.begin(), nameData.end() - 1);
m_maplocations.insert(std::pair<std::string, GLint>(name, values[3]));
}
}
How can I iterate the bone_matrices array, get their names:
bone_matrices[0], bone_matrices[1],
...
and locations.
Thanks..
How can I iterate the bone_matrices array, get their names: bone_matrices[0], bone_matrices1, ... and locations.
There is one uniform: bone_matrices. This uniform is an array of basic types, so it is considered a single resource. Each array element has a location, but there is still only one uniform.
If you want to test if a uniform is arrayed, get the size of the uniform using the GL_ARRAY_SIZE property. If this value is greater than 1, then you can then query the location of each array element by a loop.
All that being said:
I am trying to save the uniform locations of an array, to a std::map in my Shader class.
Please don't do this. First, your std::map-based code will not be faster than glGetUniformLocation or glGetProgramResourceLocation. So if you're going to constantly query uniforms by string name, you may as well just use the existing API.
Second, since you're using program resources, a GL 4.3 feature, I have to assume you have access to explicit uniform locations. You should therefore assign uniforms to specific locations in your shader, then you don't have to query anything at all.
Even if you're writing a program that has to work with whatever the user gives you, it's still better for them to provide specific locations.
What I mean is this. Let's say you have an expectation that the user will provide an array of matrices called bone_matrices. So change your expectation to be that the user will provide an array of matrices at some particular uniform location X.
Yes, this means you have to partition out your uniform space. But it's a lot better than running through each shader to query its data. You don't have to have a map from a string to a location; you simply have the location where it expects it to be.
Related
I was wondering if I can index into a uniform buffer array with a value contained in the vertices I draw, like:
layout (location = 0) in vec3 position;
layout (location = 1) in flat int idx;
layout(binding = 0, std140) uniform uniformValues
{
float values[100];
};
void main()
{
values[idx];
}
My understanding is that this is not possible because
'in flat int idx'
Is most likely not a 'dynamically uniform expression', and according to the documentation cannot be used to index into a uniform buffer array:
There are places where GLSL requires the expression to be dynamically
uniform. All of the following must use a dynamically uniform
expression:
-The index to buffer-backed interface block arrays.
However I came across information from the same source regarding how to access an array of samplers holding texture handles for 'bindless textures', and it says (emphasis mine):
Sampler and image types used in default block uniform variables can be
populated from handles rather than the index of a binding point.
These types can also now be passed as Shader Stage inputs/outputs (using the flat interpolation qualifier where needed). They can be
used as Vertex Attributes, where they are treated as 64-bit integers
on the OpenGL side. And they can be used in Interface Blocks of all
kinds; buffer-backed interface blocks treat them as 64-bit integers.
It's saying, I believe, that instead of doing this:
layout (location = 0) in flat int textureBinding;
layout (binding = 0) uniform sampler2D textures[16];
void main()
{
textures[textureBinding];
}
You do this:
layout (location = 0) in flat int bindlessTextureHandle;
layout (binding = 0) uniform textureBuffer
{
sampler2D textures[200];
}
void main()
{
textures[bindlessTextureHandle];
}
'bindlessTextureHandle' isn't a 'dynamically uniform expression', how can it be used to index into uniform buffer?
All of the following must use a dynamically uniformexpression:
-The index to buffer-backed interface block arrays.
So why is it saying that you can index into 'interface blocks' of all kinds with values from vertex inputs?
Also are you allowed to index into:
'uniform sampler2D[16] textures;'
with a 'non-dynamically uniform expression'?
My understanding is that this is not possible because
in flat int idx
Is most likely not a 'dynamically uniform expression', and according
to the documentation cannot be used to index into a uniform buffer
array.
You are right that you need a dynamically uniform value to index into an uniform buffer array. However, this:
layout(binding = 0, std140) uniform uniformValues
{
float values[100];
};
is not a uniform buffer array. That is an array inside a single uniform buffer object, and you can index with non-uniform values into this array as you like. A uniform buffer array would be:
layout(binding = 0, std140) uniform myUBO
{
float value;
} myUBOArray[4];
The rest of your question gets even more obscure. You sometimes reference "The index to buffer-backed interface block arrays", which your code never uses. This is talking about SSBOs, which use interface blocks of the form layout(...) buffer foo {...}.
So why is it saying that you can index into 'interface blocks' of all kinds with values from vertex inputs?
Because that is how it is. You just need to understand that indexing into an array of interface blocks is not the same as indexing some other array (which might or might not be defined inside an interface block, doesn't matter).
Also are you allowed to index into:
uniform sampler2D[16] textures; with a 'non-dynamically uniform expression'?
No, not in standard GL.
The first thing about bindless textures is that this is not a core feature of any OpenGL version released to date (which is 4.6 at the time of writing this).It is only defined as an extension GL_ARB_bindless_textures which some modern GPUs and drivers expose, but the availability of that feature is quite far from being universal.
Second, the extension spec above explains: "Sampler and image handles passed to texture built-in functions must be dynamically uniform", so it still doesn't get you there. However, the extension GL_NV_gpu_shader5 removes that restriction. So on recent NVIDIA GPUs, you can get a non-dymically uniform index into an array of bindless texture samplers - but performance will still suffer by a significant amount if you do so.
There are a myriad of separate, overlapping issues here.
Indexing an array within a uniform block has never been limited to dynamically uniform expressions (generally, see below). Even in GL 3.x, you can index an array within a buffer-backed block with an arbitrary index.
However, you're not asking about a general array; you're asking about arrays of textures. Or to be more general, the entire sequence of operations leading to the computation of a sampler type through bindless textures.
That entire sequence must be dynamically uniform (unless you're on NVIDIA, which allows arbitrary expressions). It doesn't matter if you're indexing an SSBO array, using an input variable to pass a texture handle directly, or anything else. The value that leads to the acquisition of a sampler type must be dynamically uniform.
So why is it saying that you can index into 'interface blocks' of all kinds with values from vertex inputs?
Because you can.
A common misunderstanding of what "dynamically uniform" means is that it is a static property. That an expression by itself is either dynamically uniform or not. This is close to true, but it's not actually true.
Some expressions are dynamically uniform by their nature. You could call these "statically dynamically uniform" expressions. A constant expression is always dynamically uniform, for example.
However, being dynamically uniform is about the value of the expression. All invocations (within the rendering command) must result in the same value. An in variable for a shader stage can be dynamically uniform so long as it just so happens to always have the same value within the rendering command. For example, a VS could access a value from a uniform array using gl_DrawID (which is dynamically uniform), pass that as an in to the FS, and the FS can use that value as a sampler. Or to access an array of samplers. Or whatever. All FS invocations will get the same value within the draw command, so that value is dynamically uniform.
I am working on a 3D mesh I am storing in an array: each element of the array is a 4D point in homogeneous coordinates (x, y, z, w). I use OpenCL to do some calculations on these data, which later I want to visualise, therefore I set up an OpenCL/GL interop context. I have created a shared buffer between OpenCL and OpenGL by using the clCreateFromGLBuffer function on a GL_ARRAY_BUFFER:
...
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, size_of_data, data, GL_DYNAMIC_DRAW);
vbo_buff = clCreateFromGLBuffer(ctx, CL_MEM_READ_WRITE, vbo, &err);
...
In the vertex shader, I access data this way:
layout (location = 0) in vec4 data;
out VS_OUT
{
vec4 vertex;
} vs_out;
void main(void)
{
vs_out.vertex = data;
}
Then in the geometry shader I do something like this:
layout (points) in;
layout (triangle_strip, max_vertices = MAX_VERT) out;
in VS_OUT
{
vec4 vertex;
} gs_in[];
void main()
{
gl_Position = gs_in[0].vertex;
EmitVertex();
...etc...
}
This gives me the ability of generating geometry based on the position of each point the stored in the data array.
This way, the geometry I can generate is only based on the current point being processed by the geometry shader: e.g. I am able to construct a small cube (voxel) around each point.
Now I would like to be able to access to the position of other points in the data array within the geometry shader: e.g. I would like to be able to retrieve the coordinates of another point (indexed by another shared buffer of an arbitrary length) besides the one which is currently processed in order to draw a line connecting them.
The problem I have is that in the geometry shader gs_in[0].vertex gives me the position of each point but I don't know which one for at the time (which index?). Moreover I don't know how to access the position of other points besides that one at the same time.
In an hypothetical pseudo-code I would like to be able to do something like this:
point_A = gs_in[0].vertex[index_A];
point_B = gs_in[0].vertex[index_B];
draw_line_between_A_and_B(point_A, point_B);
It is not clear to me whether this is possible or not, or how to achieve this within a geometry shader. I would like to stick to this approach because the calculations I do in the OpenCL kernels implement a cellular automata, hence it is convenient for me to organise my code (neutrino) in terms of central nodes and related neighbours.
All suggestions are welcome.
Thanks.
but I don't know which one for at the time (which index?)
See gl_PrimitiveIDIn
I don't know how to access the position of other points besides that one at the same time.
You can bind same source buffer two times, as a vertex source and as GL_TEXTURE_BUFFER. If your OpenGL implementation supports it, you'll then be able to read from there.
Unlike Direct3D, in GL the support for the feature is optional, the spec says GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS can be zero.
"This gives me the ability of generating geometry based on the position of each point the stored in the data array."
No it does not. The input to the geometry shader are not all the vertex attributes in the buffer. Let me quote the Geometry Shader wiki page:
Geometry shaders take a primitive as input; each primitive is composed of some number of vertices, as defined by the input primitive type in the shader.
Primitives are a single point, line primitive or triangle primitive. For instance, If the primitive type is GL_POINTS, then the size of the input array is 1 and you can only access the vertex coordinate of the point, or if the primitive type is GL_TRIANGLES, the the size of the input array is 3 and you can only access the 3 vertex attributes (respectively corners) which form the triangle.
If you want to access more data, the you have to use a Shader Storage Buffer Object (or a texture).
I use oglplus - it's a c++ wrapper for OpenGL.
I have a problem with defining instanced data for my particle renderer - positions work fine but something goes wrong when I want to instance a bunch of ints from the same VBO.
I am going to skip some of the implementation details to not make this problem more complicated. Assume that I bind VAO and VBO before described operations.
I have an array of structs (called "Particle") that I upload like this:
glBufferData(GL_ARRAY_BUFFER, sizeof(Particle) * numInstances, newData, GL_DYNAMIC_DRAW);
Definition of the struct:
struct Particle
{
float3 position;
//some more attributes, 9 floats in total
//(...)
int fluidID;
};
I use a helper function to define the OpenGL attributes like this:
void addInstancedAttrib(const InstancedAttribDescriptor& attribDesc, GLSLProgram& program, int offset=0)
{
//binding and some implementation details
//(...)
oglplus::VertexArrayAttrib attrib(program, attribDesc.getName().c_str());
attrib.Pointer(attribDesc.getPerVertVals(), attribDesc.getType(), false, sizeof(Particle), (void*)offset);
attrib.Divisor(1);
attrib.Enable();
}
I add attributes for positions and fluidids like this:
InstancedAttribDescriptor posDesc(3, "InstanceTranslation", oglplus::DataType::Float);
this->instancedData.addInstancedAttrib(posDesc, this->program);
InstancedAttribDescriptor fluidDesc(1, "FluidID", oglplus::DataType::Int);
this->instancedData.addInstancedAttrib(fluidDesc, this->program, (int)offsetof(Particle,fluidID));
Vertex shader code:
uniform vec3 FluidColors[2];
in vec3 InstanceTranslation;
in vec3 VertexPosition;
in vec3 n;
in int FluidID;
out float lightIntensity;
out vec3 sphereColor;
void main()
{
//some typical MVP transformations
//(...)
sphereColor = FluidColors[FluidID];
gl_Position = projection * vertexPosEye;
}
This code as whole produces this output:
As you can see, the particles are arranged in the way I wanted them to be, which means that "InstanceTranslation" property is setup correctly. The group of the particles to the left have FluidID value of 0 and the ones to the right equal to 1. The second set of particles have proper positions but index improperly into FluidColors array.
What I know:
It's not a problem with the way I set up the FluidColors uniform. If I hard-code the color selection in the shader like this:
sphereColor = FluidID == 0? FluidColors[0] : FluidColors1;
I get:
OpenGL returns GL_NO_ERROR from glGetError so there's no problem with the enums/values I provide
It's not a problem with the offsetof macro. I tried using hard-coded values and they didn't work either.
It's not a compatibility issue with GLint, I use simple 32bit Ints (checked this with sizeof(int))
I need to use FluidID as a instanced attrib that indexes into the color array because otherwise, if I were to set the color for a particle group as a simple vec3 uniform, I'd have to batch the same particle types (with the same FluidID) together first which means sorting them and it'd be too costly of an operation.
To me, this seems to be an issue of how you set up the fluidID attribute pointer. Since you use the type int in the shader, you must use glVertexAttribIPointer() to set up the attribute pointer. Attributes you set up with the normal glVertexAttribPointer() function work only for float-based attribute types. They accept integer input, but the data will be converted to float when the shader accesses them.
In oglplus, you apparently have to use VertexArrayAttrib::IPointer() instead of VertexArrayAttrib::Pointer() if you want to work with integer attributes.
I defined a struct for light parameters which contains two vectors. The struct is defined in both C++ and GLSL in an analogous way (note: QVector3D encapsulates 3 floats, not doubles):
C++ host program:
struct LightParameters {
QVector3D pos;
QVector3D intensity;
};
Fragment Shader:
struct LightParameters {
vec3 pos;
vec3 intensity;
};
In the fragment shader, I also define the following uniforms. The numbers of lights is limited to 8, so the uniform array has a constant size (but only numLights are actually used):
const int maxLights = 8;
uniform int numLights;
uniform LightParameters lights[maxLights];
In the host program, I define the lights and pass them to the shader (QGLShaderProgram):
static const int maxLights = 8;
LightParameters lights[maxLights];
int numLights = 1;
lights[0].pos = {0, 1, 0};
lights[0].intensity = {1, 1, 1};
shaderProgram->bind();
shaderProgram->setUniformValue("numLights", numLights);
shaderProgram->setUniformValueArray("lights", reinterpret_cast<GLfloat*>(lights), maxLights, 6);
shaderProgram->release();
The 6 in the last parameter should indicate that each array element uses 6 GLfloats from the raw float array, aka "tuple size".
According to the Qt documentation, it should not be possible to use a tuple size of 6 (only 1, 2, 3, 4 are allowed). On the other side, QGLShaderProgram allows to pass in a matrix with up to 4x4 entries. GLSL also allows structs for uniforms which have more than 4 floats in them (according to this example).
This leads to the question:
How can I pass structs of floats / vectors as a uniform array using Qt? If it's not possible using Qt, I will call the GL function to do this, but I'm interested if Qt can do this for me conveniently.
Of course I tried the code above anyway. It results in all vectors in the struct being set to 0.
When I drop the second parameter in the struct and use a tuple size of 3, the code still does not work! However, when just using vec3 in the shader (still the struct with one QVector3D in the host program, tuple size = 3), it works.
So the problem seems to be that custom types are handled differently in the OpenGL host program API, but Qt doesn't seem to support it. I currently use two uniform arrays (one for the pos, one for the intensity) as a workaround.
Qt has nothing to do with this.
You cannot pass arrays of structs as though it were an array of values. If you have a uniform array whose type is not a basic type, then every array index and every member of that struct has a separate uniform location with a separate uniform name. Therefore, you must pass each member separately.
You must do this:
shaderProgram->setUniformValue("lights[0].pos", lights[0].pos);
shaderProgram->setUniformValue("lights[0].intensity", lights[0].intensity);
shaderProgram->setUniformValue("lights[1].pos", lights[1].pos);
shaderProgram->setUniformValue("lights[1].intensity", lights[1].intensity);
shaderProgram->setUniformValue("lights[2].pos", lights[2].pos);
shaderProgram->setUniformValue("lights[2].intensity", lights[2].intensity);
And so forth.
Or you could just use a proper uniform block and dispense with all of that.
I use a template function:
template<class T> void setUniformArrayValue(QOpenGLShaderProgram *program,
const QString& arrayName,
const QString& varName,
int index,
const T& value)
{
const char* name = QString("%1[%2].%3")
.arg(arrayName)
.arg(index)
.arg(varName)
.toStdString().c_str();
program->setUniformValue(name, value);
}
and in the program :
for (int i = 0; i < m_lights.size(); i++) {
setUniformArrayValue<QColor>(program, "lights", "ambient", i, m_lights[i].ambient());
...
}
I am trying to get the type of an uniform variable defined in a fragment shader:
uniform vec3 color;
uniform float zoom;
uniform int max;
void main() {
...
}
The glGetActiveUniformARB(program, index, maxLength, *length, *size, *type, *name) seems to be the right API function to use but I don't know how to determinate index from a variable name.
glGetUniformLocationARB returns the location of an uniform variable, that seems not to be the same as the index.
Well, the API kind-of assumes that if you know the name of the uniform, you also know the type (those 2 things are written next to each other in the code) so it does not allow a simple access to the type by name.
That said, you can iterate over all the active uniforms with glGetActiveUniformARB to find the one that interests you. Note also that this will only return valid data if the uniform is actually active (i.e. the GLSL compiler thought it was useful for the final computations).
(Typically, the expected usage is to iterate over all the uniforms, extract name and type, and then get their location from name to know how to update them at run-time. Not the other way around).
From the glGetActiveUniform man page:
The number of active uniform variables can be obtained by calling glGetProgram
with the value GL_ACTIVE_UNIFORMS. A value of 0 for index selects the first
active uniform variable. Permissible values for index range from 0 to the
number of active uniform variables minus 1.