6

I want to specify textures to be used when I render an array of sprites. So I put a texture index in their vertex data, and pass it as a flat value from my vertex shader to my fragment shader, but can't use it to index an array of samplers as expected because compiler sees it as "non-constant". Instead I have to resort to the disgusting code below. Can anyone explain what is going on here?

const int numTextures = 2;

uniform sampler2D textures[numTextures];

in vec2 uv;
flat in int tex;
out vec4 colour;

void main(void)
{
    // this caused the compiler error 
        /// "sampler arrays indexed with non-constant expressions"
    // colour = texture( textures[ tex ], uv );

    // hence this (ugh) ...
    switch ( tex ) 
    {
        case 0:
            colour = texture( textures[0], uv );
            break;
        case 1:
            colour = texture( textures[1], uv );
            break;
        default:
            colour = vec4( 0.3f, 0.3f, 0.3f, 1.0f );
            break;
    };
} 

genpfault
  • 51,148
  • 11
  • 85
  • 139
MarkL
  • 81
  • 2
  • 2
    Would it be possible to use `sampler2DArray`? See [Sampler](https://www.khronos.org/opengl/wiki/Sampler_(GLSL)) – Rabbid76 Jan 27 '19 at 13:19
  • using the mipmaps is a cool idea. I think for this applcation I will use large texture pages, maintain separate draw lists for each and switch the active texture inbetwween the draw element calls in my render func. – MarkL Jan 28 '19 at 16:12

1 Answers1

8

[...] but can't use it to index an array of samplers as expected because compiler sees it as "non-constant" [...]

In GLSL up to version 3.30 respectively GLSL ES up to version 3.00, the index of an array of texture samplers has to be a constant expression:

GLSL 3.30 Specification - 4.1.7 Samplers (page 21)
GLSL ES 3.00 Specification - 4.1.7.1 Samplers (page 29):

Samplers aggregated into arrays within a shader (using square brackets [ ]) can only be indexed with integral constant expressions [...]


In later version, the index to an array of samplers has to be "dynamically uniform". This means the index has to be the "same" for all fragments (e.g. a constant or a uniform variable).

GLSL 4.60 Specification - 4.1.11. Opaque Types (page 31)
GLSL ES 3.20 Specification - 4.1.11. Opaque Types (page 32)

When aggregated into arrays within a shader, opaque types can only be indexed with a dynamically uniform integral expression. [...]

[...] Sampler types (e.g. sampler2D) are opaque types [...]

GLSL 4.60 Specification - 3.8.2. Dynamically Uniform Expressions (page 20)
GLSL ES 3.20 Specification - 3.9.3. Dynamically Uniform Expressions (page 22)

A fragment-shader expression is dynamically uniform if all fragments evaluating it get the same resulting value.


A flat fragment shader input is invariant for a single primitive, but not for the entire mesh, not for all the primitives which are processed by a single "draw call" respectively it is not the same for an invocation group. A (flat) fragment shader input is not Dynamically uniform.

Rabbid76
  • 202,892
  • 27
  • 131
  • 174
  • thank you for such a detailed replay. I see that in the newer versions of GLSL I can do what I want. I should probably upgrade my laptop which has an un-upgradeable gpu supporting only GLSL 130. – MarkL Jan 28 '19 at 16:14
  • @MarkL No, the index of an array of samplers can never depend on a varying (`in`) variable. – Rabbid76 Jan 28 '19 at 16:32
  • yes, that makes sense, but I'm using a flat int, which is invariant. – MarkL Jan 29 '19 at 17:16
  • 2
    @MarkL No, it is invariant for a single primitive, but not for the entire mesh, not for all the primitives wich are processed by a single "draw call" respectively it is not the same for an invocation group. – Rabbid76 Jan 29 '19 at 18:14
  • OK I get it now .. I had assumed that the shaders were executed per primitive. Obvious nonsense now I come to think about it! Thanks for helping me out with this one. – MarkL Jan 31 '19 at 12:57