I am passing an uniform array to geometry shader and want to index into it using a variable. I can use variable length array & index with fixed number (numeric constant) OR I can define a fixed length array & index using varible. However I can't index into variable length array using a variable.
Below is pseudo code for geometry shader with cases that work & case that doesn't work
This works:
uniform vec2 dimensions[2];
// some code which computes index which is an int
float dimX = dimensions[index].x;
This works:
uniform vec2 dimensions[];
// some code which computes index which is an int
float dimX = dimensions[0].x;
This doesn't work:
uniform vec2 dimensions[];
// some code which computes index which is an int
float dimX = dimensions[index].x;
Is it possible to do something like this?
Sadly, no this is not possible. You did not include the GLSL version you are targeting but did mention geometry shaders, so I have included the relevant part of the GLSL 1.5 spec. below:
GLSL Specification (Version 1.5) - 4.1.9 Arrays - pp. 25.
Variables of the same type can be aggregated into arrays by declaring a name followed by brackets ( [ ] ) enclosing an optional size. When an array size is specified in a declaration, it must be an integral constant expression (see Section 4.3.3 “Constant Expressions” ) greater than zero. If an array is indexed with an expression that is not an integral constant expression, or if an array is passed as an argument to a function, then its size must be declared before any such use.
While desktop GLSL is much more forgiving when it comes to indexing arrays with non-const expressions than GLSL ES, you still have to work within some limitations. The same way that texture lookups are often used to overcome non-const array indexing in OpenGL ES, you may be able to work around this by using a 1D texture lookup in your geometry shader. I have to wonder if you really need this functionality that badly though?
It is a good idea to define an upper limit to your uniform array anyway, because the GLSL spec. only requires an implementation provide 1024 uniform components (e.g. 1024 float, 256 vec4, 64 mat4 or some combination of each) in the geometry shader stage. If your array has a known maximum size at compile time you can avoid trouble later down the road associated with unknowingly exceeding this limitation.
UPDATE:
Since you mentioned GLSL 4.x, I would like to point out a newer feature in OpenGL known as Shader Storage Buffer Objects. Using SSBOs, it may be possible to use an array with dynamic length at run-time for your purposes. You can query the length of an SSBO using .length () in the shader, and handle range validation yourself. However, I think this is probably overkill but worth mentioning nevertheless.
Related
I want to pass my touch points to GPUImage (iOS)
The Point can be translate to float array, the length of the array is variable length.
But I must direct the length of array in shader.
Disclaimer: not a glsl expert
AFAIk you can't have variable length arrays like what you want. This is a GLSL limitation, not GPUImage so it's not a quick fix- the work you'll be doing will be with textures or glsl, not GPUImage.
Here's another stack overflow post about glsl: GLSL indexing into uniform array with variable length
There's two solutions that could work:
1) Limit the number of points. It's reasonable to limit touches but in practice may be hard to narrow them down if there's too many. You could pass these points in to a fixed length array or as individual constants (one for each point). If you really care about scalability with the number of points this isn't a great method because in your shader you'll have to do check each of these points and perform the relevant computation, which could be expensive when performed for the entire image (again, depending on your use case). If for each pixel you're checking a distance to point, this could be too expensive.
2) Input your points in a texture. You can either have 2 1D textures with the x&y coordinates and then treat them like an array (then go to option 1), or you can create a 2D texture, all 0, and set parts to 1 where there are touches. The 2D texture can have a lower resolution than the actual screen. This method could be a lot less work for the shader if you're doing something simple like turning finger touches black.
Your choice depends largely on what you're doing with the points in the shader.
working myself from step to step I am now trying to figure out more about multi lights in glsl. I read some tutorials so far but none seems to have THE answer for this.
Lets say I have such a struct for my lighting:
struct LightInfo
{
vec4 LightLocation;
vec3 DiffuseLightColor;
vec3 AmbientLightColor;
vec3 SpecularLightColor;
vec3 spotDirection;
float AmbientLightIntensity;
float SpecularLightIntensity;
float constantAttenuation;
float linearAttenuation;
float quadraticAttenuation;
float spotCutoff;
float spotExponent;
};
uniform LightInfo gLight;
my first idea would be to make it something like
uniform LightInfo gLight[NumLights];
but then I read a lot about that passing data that way to the shader wouldn't work, since it can't get the location of that. Now I have to admit that I didn't try it myself yet, but I found a couple of pages mentioning this, so it's probably not that wrong - or is this maybe just outdated information?
The other idea would be to make it just:
uniform[NumOfArgs]
and split it in the shader again, but if I take my example struct above I have an immense huge array very soon, and taking the information out of it with a for loop probably will be quite expensive too- and that only if I want to use a similar number of lights like the max of 8 when using gl_LightSource - while I wanted to avoid using that because of the advantage having an own struct with all information needed at once.
Of course not any light in question would require that many parameters, but any light COULD require them (and even if stripping it quite some it will grow very soon also).
Yet again I could use some qsort first to determine the closest lights, then limiting the maxlights to something like 3 (something which is also suggested on many places), but here again I have to say that I expect a bit more from nowadays glsl and modern hardware although there is no contradiction in using this as well, unrelated to the chosen solution.
So my question now, what's best practice here, what's really fast? Or should I stay with gl_LightSource and passing the additional information then via some uniform array? Although this doesn't seem to make more sense to me either.
The idea of a light struct is just fine. For forward rendering - passing all lights into the one shader which processes your actual geometry - an array is just fine.
You may have an array of structs as uniforms (uniform LightInfo gLight[NumLights], where NumLights is compile-time constatnt), but arrays are not so different to just declaring uniform LightInfo gLight0, gLight1....
You get the uniform location via the full name, eg:
glGetUniformLocation(program, "gLight[3].spotExponent")
Note that glGetActiveUniform will return just the string with element zero but the size will give the number of elements.
Uniform buffers will be important with lots of lights and attributes. You can store all the data for the structs on the GPU, so it doesn't get sent every time with individual calls to glUniform*. You can use glMapBuffer to modify parts of the buffer if the rest doesn't need changing.
Be very aware of how the structs and arrays get packed (it's not always intuitive)! Related issues occur in non-uniform/uniform block cases too.
See: Sub-section 2.15.3.1.2 - Standard Uniform Block Layout
To get the byte offset from the beginning of the block, use the GL_UNIFORM_OFFSET enum
See: Uniform Buffer Object
Elements are aligned to whopping big 16 byte boundaries (vec4 size). To make that struct more efficient, you should pair the vec3s with the floats.
You're right, if you have more lights than there are in the shader you'll have to chop and choose. Lights that are close are important, but you might also want to prioritize lights in the direction you're facing (those whose area of influence touches the viewing volume formed by the projection matrix) and bigger/brighter lights (eg. sun/directional).
Ultimately if you have too many lights this method ceases to work. Your next step is to swap to deferred shading, which brings with it a few more issues (eg. blending/transparency).
I'd like to be able to pass an arbitrary number of varying values per vertex from the vertex shader to the geometry shader. I know that OpenGL has no dynamic arrays, so the number should be specified at compile time. The whole thing should run on an Apple MacBook with a NVIDIA GeForce 9400M graphics card and a driver that only offers OpenGL 2.1, along with some extensions.
The problem here seems to be that the geometry shader takes its input in the form or an array with one element per vertex. As far as I can tell, there are no arrays of arrays available in my setup, and no arrays of interface blocks containing arrays either. So far, the best solution I could come up with is specifying a number of variables to pass this information, extracted from an array in the vertex shader and turned back into an array with a certain stride length in the geometry shader. That way, access to the values can still be performed using computed indices.
Is there a better, more elegant way?
From EXT_geometry_shader4 specification:
User-defined varying variables can be declared as arrays in the
vertex shader. This means that those, on input to the geometry shader,
must be declared as two-dimensional arrays. See sections 4.3.6 and 7.6 of
the OpenGL Shading Language Specification for more information.
For example, in the vertex shader, you may specify
varying vec2 value[2];
and in the geometry shader, this becomes a two-dimensional array, e.g. with triangles as input primitives
varying in vec2 value[3][2];
Note the counterintuitive order of array indices! Also beware that the array dimensions must be specified explicitly, using an integer constant. Using a non-constant integer variable or gl_VerticesIn yields a compiler error. Both remarks have been tested on the very MacBook Pro model mentioned in the question.
There are reasons why core OpenGL's geometry shaders don't work the way EXT_geometry_shader4 does. This is one of them. EXT_geometry_shader4 doesn't allow arrays of inputs because that would mean allowing arrays of arrays of values. And GLSL can't handle that (well, until recently, but that's only 2 months old).
Interface blocks can have arrays in them. Your problem is that GLSL 1.20 doesn't have interface blocks.
There's not much you can do besides use different variables and manually unroll all your loops. You could write a function that takes an integer value and conditionally returns one of the different values that correspond to that index, but that's about the best you're going to get with old-school GLSL.
I would like to leave OpenGL's lights and make my own.
I would like my shaders to allow for a variable number of lights.
Can we declare an array of uniforms in GLSL shaders?
If so, how would we set the values of those uniforms?
Yes this is possible. You declare uniform arrays similar to how you'd do it in C, e.g.
uniform float v[10];
Then you can set their values using glUniform{1,2,3,4}{f,i}v
GLfloat v[10] = {...};
glUniform1fv(glGetUniformLocation(program, "v"), 10, v);
Yes it is possible to declare an array of uniforms in GLSL shaders. Just google "glsl uniform array" for some examples (edit: or see datenwolf's example). There are however limitations on how many uniforms can be sent to different graphics cards (at least on older ones, I'm not sure about current ones (although I imagine there still would be)).
If you do decide to go down the route of uniforms, i would suggest using uniform buffers. According to http://www.opengl.org/wiki/Uniform_Buffer_Object, "Switching between uniform buffer bindings is typically faster than switching dozens of uniforms in a program".
If you have large numbers of lights and parameters, you could also send the data as float buffers.
I'm attempting to plot an iterative function in OpenGL ES. An array of ints is being updated with how often a given pixel is hit by the iterative function. I'd like to pass this density array to a fragment shader and use it to plot the result on a simple quad covering the whole screen.
My question is: can I pass this array directly to the shader as a uniform and generate pixels by using gl_FragCoord to look up the density for the given position
or
should I rather use the array to create a texture with one channel using GL_LUMINANCE and pass that to the shader?
You have a limited number of uniforms available, and the indexing might be troubling since not all GPUs support non-constant indexing. A 2D Nx1 texture doesn't have any of these issues but will return values into the [0, 1] range. You can scale back this values to obtain the original integer and use it.