Constant vec3 array - no go

So I want to do something like this:


const vec3 COLOR_MASKS[ 8 ] = { vec3( 0.0, 0.0, 0.0 ),
                                vec3( 0.5, 0.5, 0.5 ),
                                vec3( 1.0, 0.5, 0.5 ),
                                vec3( 0.5, 1.0, 0.5 ),
                                vec3( 0.5, 0.5, 1.0 ),
                                vec3( 0.5, 1.0, 1.0 ),
                                vec3( 1.0, 0.5, 1.0 ),
                                vec3( 1.0, 1.0, 0.5 ) };

color = COLOR_MASKS[index];

for a shader debugging tool (not for performance) – index being an int computed in the shader.

But the compiler says no way:

frag.glsl: error C7516: OpenGL does not allow constant arrays
frag.glsl: error C7549: OpenGL does not allow C style initializers

So what’s the GLSL paradigm for this? I’d rather not have to do the silly/verbose/less readable:


if val == 0 then
  val2 = 123
else if val == 1 then
  val2 = 456
...

approach.

Thanks.

This compiles/works, but is crazy-verbose and the compiler won’t let me make the array constant:

  vec3 COLOR_MASKS[8];
  COLOR_MASKS[0] = vec3( 0.0, 0.0, 0.0 );
  COLOR_MASKS[1] = vec3( 0.5, 0.5, 0.5 );
  COLOR_MASKS[2] = vec3( 1.0, 0.5, 0.5 );
  COLOR_MASKS[3] = vec3( 0.5, 1.0, 0.5 );
  COLOR_MASKS[4] = vec3( 0.5, 0.5, 1.0 );
  COLOR_MASKS[5] = vec3( 0.5, 1.0, 1.0 );
  COLOR_MASKS[6] = vec3( 1.0, 0.5, 1.0 );
  COLOR_MASKS[7] = vec3( 1.0, 1.0, 0.5 );

color = COLOR_MASKS[index];

Is there no better way?

Array constructors in GLSL look like this:


float a[5] = float[](3.4, 4.2, 5.0, 5.2, 1.1);

Why would you want to make it constant, it seems like overkill in a shader.

I usually mark the array as an uniform:


uniform vec3 COLOR_MASKS[ 8 ] = { vec3( 0.0, 0.0, 0.0 ),
                                vec3( 0.5, 0.5, 0.5 ),
                                vec3( 1.0, 0.5, 0.5 ),
                                vec3( 0.5, 1.0, 0.5 ),
                                vec3( 0.5, 0.5, 1.0 ),
                                vec3( 0.5, 1.0, 1.0 ),
                                vec3( 1.0, 0.5, 1.0 ),
                                vec3( 1.0, 1.0, 0.5 ) };


I am unsure if this is a bad practice, or sub-performant.

I am unsure if this is a bad practice, or sub-performant.

It’s more like contrary to the spec. Array initialization isn’t supposed to work that way in GLSL; you’re supposed to use constructor syntax.

Thanks for the correction; I looked closer at the spec for this, and found the solution:


const vec3 MyArray[4]=vec3[4](
	vec3(1.5,34.4,3.2),
	vec3(1.6,34.1,1.2),
	vec3(18.981777,6.258294,-27.141813),
	vec3(1.0,3.0,1.0)
);

No curly brackets.

Edit:
And OUCH. Replacing one of my uniform-arrays with such a const vec4[] dropped framerate from 93fps to 2fps :S.
Removing the “const” makes it run at 8fps.
Replacing the “const” with “uniform” (again, no curly brackets) restores it to 93fps.

GTX275, 196.34 (beta), winxp.

Thanks, all!

@Alfonse, this works - thanks:


  vec3 COLOR_MASKS[8] = vec3[]( vec3( 0.0, 0.0, 0.0 ),
                                vec3( 0.5, 0.5, 0.5 ),
                                ... 
                              );

@zeoverlord:

I try to make whatever is constant const, so the compiler will fold it into the code when possible (even if it’s lame at dead code elimination). For instance, if I use a constant index to look into the above array, which I would make const, then only a stupid compiler isn’t going to generate the maximally efficient code there and just pretend that was a reference to that color specifically in-line in the code.

But alas, like switch statements originally, seems GLSL doesn’t believe in const arrays yet…

@Ilian:

Yeah, that works, but there are two disadvantages:
[ol][li] uniforms have to be at global scope (so you can’t define these convenience lookups inside the only function that uses them), and [*] because they’re uniform (i.e. parameters), then compiler cannot fold the array completely out of the code in the case of indexing with a constant[/ol][/li]And I too can confirm that unlike non-uniform arrays, seems the C array initializer syntax “can” be used for uniform arrays defined at the global scope (on NVidia at least). This is a bug I gather.

No dice here. That won’t compile, either in a function or at the global scope. The error is:

error C7516: OpenGL does not allow constant arrays

Wow. Weird. And on NVidia too, with recent GPU/drivers. Let me try some tests…

Ok, here on NVidia GTX285 / 190.32 (Linux), neither the GLSL array initializer or C initializer cases dropped my perf, but using the uniform forms seemed not to honor the initializers. Always got black.

error C7516: OpenGL does not allow constant arrays

IIRC, you need “#version 120” or higher for constant arrays. Try adding that to the top of your shader.

Thanks, but it’s there. Very first line.