Computer Graphics Asked by Archmede on January 13, 2021
Is it possible to have a dynamic array in a GLSL shader? For instance, what if I have something like this in my GLSL Shader:
uniform int size;
uniform SceneLights lights[size];
void main()
{
for(int i = 0; i < size; i++) {
/* Do Some Calculation */
}
}
And this would be my C++ file:
for (GLuint i = 0; i < pointLights.size(); i++) {
glUniform3f(glGetUniformLocation(shader, ("pointLights[" + std::to_string(i) + "].position").c_str()), lights[i].someValue);
}
I would like to do this because I have a file with the positions of all the light sources in my scene (this may vary for each scene) so I would like to have a dynamic array which will allow me to send different numbers of lights to my shader.
I don't think uniform arrays can be dynamically sized. In your case you should define the array as the maximum number of lights you will process and then use a uniform to control the number of iterations you do on this array. On the CPU side you can set a subset of the lights[] array according to the 'size' variable.
e.g.
#define MAX_LIGHTS 128
uniform int size;
uniform SceneLights lights[MAX_LIGHTS];
void main()
{
for(int i = 0; i < size; i++) {
/* Do Some Calculation */
}
}
I think (speculate) the likely reason for this is that it would be impossible to determine the location of a uniform if there are variable sized arrays in your uniform list which depend on the value of another uniform.. e.g.
uniform int arraySize; // offset 0
uniform int myArray[arraySize]; // offset 4
uniform int anotherVar; // offset ????
GLSL would not know were to place anotherVar, because it would need arraySize to be set with a value before it can compute the offset of 'anotherVar'. I suppose the compiler could be clever and re-arrange the order of uniforms to get around this, but this will fail again if you have 2 or more variable sized arrays..
Correct answer by PaulHK on January 13, 2021
I am suprised that it was only mentioned in comments but yes you can use variable length arrays through SSBO. Here is the excerpt from wiki:
On the host side:
int data[SOME_SIZE];
...
GLuint ssbo;
glGenBuffers(1, &ssbo);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo);
glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(data), data, GLenum usage); //sizeof(data) only works for statically sized C/C++ arrays.
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, ssbo);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0); // unbind
On the glsl side:
layout(std430, binding = 3) buffer layoutName
{
int data_SSBO[];
};
Note that it has to be the last element in an SSBO:
layout(std430, binding = 2) buffer anotherLayoutName
{
int some_int;
float fixed_array[42];
float variable_array[];
};
The only limitation is that you can use one variable array per SSBO. You can use multiple SSBO's in a shader though.
Answered by Kaan E. on January 13, 2021
You could add the variable as code when you upload the shader code.
char header[64];
sprintf (header, "const int size = %u;n", pointLights.size());
Then add the header (assuming your code is in char code[]
):
GLchar *source[2] = {(GLchar *)header, (GLchar *)code};
glShaderSource(shader, 2, (const GLchar **)source, NULL);
..
That way you can vary the size and add it to the shader on the fly. Bit of a hack, but it's the way I did it.
Answered by Graham on January 13, 2021
Get help from others!
Recent Answers
Recent Questions
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP