Search code examples
openglglslshaderlwjgl

Why are Uniform variables not working in GLSL?


I am currently trying to create a Blur Shader for postprocessing purposes using LWJGL, but stumbled across a problem.

The Uniforms I want to change are resolution, radius and direction of the blur (horizontal or vertical, so I am able to use one Shader for both directions). I render the output to a FrameBuffer, which then gets rendered to the screen. But somehow, the Texture is just black. When I use constant values instead of uniforms, it works exactly as expected, so the problem must be the uniform variables.

This is the code of my fragment shader:

#version 330 core

out vec4 fragColor;

in vec2 coords;
in vec4 color;
in float samplerIndex;

uniform sampler2D samplers[32]; //Just an Array with ints from 0 to 31
uniform float radius;
uniform vec2 resolution; //Screen Resolution, or width & height of Framebuffer
uniform vec2 direction; //Either 1 or 0 for x and y

void main() {
    int index = int(samplerIndex);

    vec4 sum = vec4(0.0);

    float blurX = radius / resolution.x * direction.x;
    float blurY = radius / resolution.y * direction.y;

    sum += texture2D(samplers[index], vec2(coords.x - 4.0 * blurX, coords.y - 4.0 * blurY)) * 0.0162162162;
    sum += texture2D(samplers[index], vec2(coords.x - 3.0 * blurX, coords.y - 3.0 * blurY)) * 0.0540540541;
    sum += texture2D(samplers[index], vec2(coords.x - 2.0 * blurX, coords.y - 2.0 * blurY)) * 0.1216216216;
    sum += texture2D(samplers[index], vec2(coords.x - 1.0 * blurX, coords.y - 1.0 * blurY)) * 0.1945945946;
    sum += texture2D(samplers[index], vec2(coords.x, coords.y)) * 0.2270270270;
    sum += texture2D(samplers[index], vec2(coords.x + 1.0 * blurX, coords.y + 1.0 * blurY)) * 0.1945945946;
    sum += texture2D(samplers[index], vec2(coords.x + 2.0 * blurX, coords.y + 2.0 * blurY)) * 0.1216216216;
    sum += texture2D(samplers[index], vec2(coords.x + 3.0 * blurX, coords.y + 3.0 * blurY)) * 0.0540540541;
    sum += texture2D(samplers[index], vec2(coords.x + 4.0 * blurX, coords.y + 4.0 * blurY)) * 0.0162162162;

    fragColor = color * vec4(sum.rgb, 1.0);
}

This is how I render the FrameBuffer:

    public void render(boolean fixed) {
        model.setTextureID(Shader.getTextureID(texture));

        model.buffer(vertices);
        indices.put(0).put(1).put(2).put(2).put(3).put(0);

        vertices.flip();
        indices.flip();

        shader.bind();
        texture.bind();

        shader.setUniform1iv("samplers", Shader.SAMPLERS);
        shader.setUniform1f("radius", 10.0f);
        shader.setUniform2f("resolution", width, height);
        shader.setUniform2f("direction", horizontal, vertical);
        if(fixed) {
            shader.setUniformMatrix4f("camProjection", Camera.fixedProjection);
            shader.setUniformMatrix4f("camTranslation", Camera.fixedTranslation);
        } else {
            shader.setUniformMatrix4f("camProjection", Camera.projection);
            shader.setUniformMatrix4f("camTranslation", Camera.translation);
        }

        vao.bind();

        vbo.bind();
        vbo.uploadSubData(0, vertices);
        ibo.bind();
        ibo.uploadSubData(0, indices);

        GL11.glDrawElements(GL11.GL_TRIANGLES, Model.INDICES, GL11.GL_UNSIGNED_INT, 0);

        vao.unbind();

        texture.unbind();
        shader.unbind();

        vertices.clear();
        indices.clear();
    }

The sampler uniform works perfectly fine though, the problem only seems to affect the other three uniforms. I don't have much experience with OpenGL and GLSL, what am I missing?


Solution

  • Your shader code can't work at all, because of

    samplers[index]
    

    samplers is an array of sampler2D and index is set from the vertex shader input samplerIndex:

    int index = int(samplerIndex);
    

    See GLSL version 3.30, which you use (from OpenGL Shading Language 3.30 Specification - 4.1.7 Samplers ):

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

    See GLSL version 4.60 (most recent) (from OpenGL Shading Language 4.60 Specification - 4.1.7. Opaque Types):
    (This rule applies to all the versions since GLSL 4.00)

    When aggregated into arrays within a shader, these types can only be indexed with a dynamically uniform expression, or texture lookup will result in undefined values.

    Thus, neither in the GLSL version which you use, nor in the most recent version, array of samplers can be indexed by an vertex shader input (attribute).

    Since GLSL 4.00 it would be possible to index an array of samplers by an uniform, because indexing by a uniform variable is a dynamically uniform expression.


    I recommend to use sampler2DArray (see Sampler) rather than an array of sampler2D.
    When you use a sampler2DArray, then you don't need any indexing at all, because the "index" is encoded in the 3rd component of the texture coordinate at texture lookup (see texture).