Search code examples
c++openglbooleanglsluniform

GLSL ignoring uniform bool comparison in fragment shader?


I'm trying to compare a uniform bool (type_2d) in GLSL in order to output one of the two sampler types - sampler2D and samplerCube. This is purely utilised to differentiate between a cubemap (skybox, reflective cubemap data ect) and a sampler2d (albedo maps, normal maps ect).

I've tried comparing with an integer, float as well as a bool, however the framebuffer always resorts to a black screen.

Bearing in mind, the cubemap results works perfectly fine if I hard-code the bool value inside the "main" where for example "type_2d = false" without the uniform assignment, as opposed to parsing the uniform value from C++.

Here is the "GBuffer.f" code:

#version 420 core

layout(location = 0) out vec3 gPosition;    // Position texel colour
layout(location = 1) out vec3 gNormal;  // Normal texel colour
layout(location = 2) out vec4 gAlbedo;  // Albedo texel colour

in vec3 _texcoord;  
in vec3 _normal;
in vec3 _frag_pos;

uniform bool        type_2d;

uniform sampler2D   albedo;     // Albedo and specular map
uniform samplerCube cubemap;    // Skybox cubemap

vec4 final_colour;

void main()
{

    gPosition = _frag_pos;
    gNormal = normalize(_normal);

    if (type_2d)
    {
        final_colour.rgb = texture(albedo, _texcoord.st).rgb;
        final_colour.a = texture(albedo, _texcoord.st).a;   // Emission
    }
    else
    {
        final_colour.rgb = texture(cubemap, _texcoord).rgb;
        final_colour.a = texture(cubemap, _texcoord).a;
    }

    gAlbedo.rgba = final_colour;
}

Why do uniform bool comparisons never work in a fragment shader? I even managed to get the uniform value from GLSL and the parsing stage seems to work perfectly fine - it's almost as if GLSL refuses to use it for comparison, and thus returning a NULL texture sample creating a black screen effect. Any Ideas?


Solution

  • In OpenGL, a single texture unit has several binding targets for different texture types, like GL_TEXTURE_1D, GL_TEXTURE_2D, GL_TEXTURE_BUFFER, GL_TEXTURE_CUBE_MAP. So technically, you can bind more than one texture to a single unit.

    By default, GL_TEXTURE0 is the active texture unit, and all uniforms are initialized to 0, including sampler uniforms. So if you jsut glBindTexture() a 2D texture and a cube map, you end up with exactly that.

    However, albeit having bound several different texture types to a single unit at the same time is perfectly allowed in the GL, you can just sample from one specific texture target of each unit. OpenGL 4.6 core profile specification, Section "7.11 Samplers", page 155 explicitly states:

    It is not allowed to have variables of different sampler types pointing to the same texture image unit within a program object. This situation can only be detected at the next rendering command issued which triggers shader invocations, and an INVALID_OPERATION error will then be generated.

    So even if you use an uniform to switch between both paths, your program object technically has both sampler uniforms active, and without setting them to sample from different texture units, you're ending up in the forbidden zone.