Simply generating a cubemap leads to a black screen

297 views Asked by At

Here is a a minimal example causing GL to render a black screen:

// ... all the usual GL init code etc. & GLAM includes

const int SHADOW_SIZE = 1024;
const int SWIDTH = 1200, SHEIGHT = 900;
unsigned int shadowMap, albedoSpec;

// Begin snip 1
glGenTextures(1, &shadowMap);
glBindTexture(GL_TEXTURE_CUBE_MAP, shadowMap);
for (unsigned int i = 0; i < 6; ++i)
    glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_DEPTH_COMPONENT, SHADOW_SIZE, SHADOW_SIZE, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
// End snip 1

glGenTextures(1, &gAlbedoSpec);
glBindTexture(GL_TEXTURE_2D, gAlbedoSpec);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, SWIDTH, SHEIGHT, 0, GL_RGBA, GL_FLOAT, NULL);


// ... some time later, in the draw loop
// The active shader is called `shader`

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, gAlbedoSpec);
// sets the `uniform sampler2D gAlbedoSpec` to use texture unit `0`
shader.setInt("gAlbedoSpec", 0);

// ... code which draws the scene using `shader`

Now, in my shader I have something like this:

uniform sampler2D gAlbedoSpec;
uniform samplerCube shadowMap;

// ... some code which uses gAlbedoSpec

if (valueWhichIsFalseInThisExample) {
    // ... some code which uses shadowMap
} 

If I remove the bit of code marked snip 1, then GL will render whatever I tell it to. Otherwise, the screen will be black without exception. To me it seems that the act of simply generating a cubemap has lead to GL to refuse to render. So, my question is, why does generating a cubemap lead GL to refuse to render anything to the screen?

(This is all the relevant code and does minimally reproduce the problem.)

1

There are 1 answers

2
AudioBubble On

When will OpenGL refuse to render?

Per the wiki, if both

  1. two different texture types (e.g. GL_TEXTURE_2D and GL_TEXTURE_CUBE) are bound to the same image unit (e.g. GL_TEXTURE0); and,
  2. two uniforms of different sampler types (e.g. sampler2D and samplerCube) are both set to use this image unit,

then no rendering will be performed (leading to a black screen).

Satisfying the first criterion

In creating a cubemap during instantiation of a point light, I was binding it to the active texture unit, which happened to be GL_TEXTURE0:

glGenTextures(1, &_shadowMap);
glBindTexture(GL_TEXTURE_CUBE_MAP, _shadowMap);

Later, when it came to rendering the gBuffer, I was binding the albedo/specular buffer also to GL_TEXTURE0, this time explicitly as:

// Load gBuffer textures
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, _gAlbedoSpec);

Thus criterion 1 of the above has now been fulfilled.

Satisfying the second criterion

I also set a relevant uniform for the fragment shader so that I could sample the albedo/specular buffer:

shader.setInt("gAlbedoSpec", 0);

In the shader, this uniform is defined as

uniform sampler2D gAlbedoSpec;

In the same shader, at some point I have something along the lines of

uniform samplerCube pointLightShadowMap

This never has a value explicitly set, since I disabled shadow-casting for the point light, but its default value is 0, and this is enough to fulfil criterion 2 of the above.

Conclusion and solution

Thus, I had accidentally managed to set up a situation where I caused OpenGL to refuse to render. It didn't matter that I never actually accessed the second uniform, simply having it set was enough to cause problems.

The best solution is probably to make sure that the cubemap is unbound once we are finished with it during point light instantiation:

glGenTextures(1, &_shadowMap);
glBindTexture(GL_TEXTURE_CUBE_MAP, _shadowMap);

// ... do what we need to do

glBindTexture(GL_TEXTURE_CUBE_MAP, 0);