7

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;
    };
} 

2
  • 2
    Would it be possible to use sampler2DArray? See Sampler Commented Jan 27, 2019 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. Commented Jan 28, 2019 at 16:12

1 Answer 1

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.

Sign up to request clarification or add additional context in comments.

5 Comments

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 No, the index of an array of samplers can never depend on a varying (in) variable.
yes, that makes sense, but I'm using a flat int, which is invariant.
@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.
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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.