c++opengldevil

OpenGL 4.0 Cubemap issues


Been reading 'OpenGL 4.0 Shading Language Cookbook'. But I've run into a wall with the cubemap tutorial.

The issue is that model I'm drawing appears completely grey. As if it's not getting any data from the samplerCube texture.

All my code seems to be correct. I've looked at other tutorials and it's the same thing. Don't know if my Intel HD Graphics 4000 is responsible, but I have made certain that I do have the GL_ARB_texture_cube_map extension.

I'm using the DevIL library for loading images from file, which it seems to do just fine, but from what I can tell something is going wrong in transferring the data to OpenGL.

I'm posting the loading where I get the data from the files. All files are loading correctly as well. I'm also posting the drawing code, where I bind the texture to the pipeline. And I'm also posting my vertex and fragment shader just in case, but they do appear to be working as they should.

Any ideas?

Loading code

uint TARGETS[6] =
{
    GL_TEXTURE_CUBE_MAP_POSITIVE_X,
    GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
    GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
    GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
    GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
    GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
};
string EXTS[6] = 
{
    "posx",
    "negx",
    "posy",
    "negy",
    "posz",
    "negz"
};

// Create & bind cubemap texture
glGenTextures( 1, &cubemap );
glBindTexture( GL_TEXTURE_CUBE_MAP, cubemap );

for( int i = 0; i < 6; i++ )
{
    string file = "textures/cubemap_" + EXTS[i] + ".png";
    uint image = ilGenImage();

    // Load with DevIL
    ilBindImage( image );
    if( !ilLoadImage( file.c_str() ) )
    {
        cout << "ERROR: Failed to load image " << endl;
        return false;
    }

    // Fetch info from DevIL
    int width   = ilGetInteger( IL_IMAGE_WIDTH );
    int height  = ilGetInteger( IL_IMAGE_HEIGHT );
    uint format = ilGetInteger( IL_IMAGE_FORMAT );
    uint type   = ilGetInteger( IL_IMAGE_TYPE );

    // Send data to OpenGL  
    glTexImage2D(
        TARGETS[i],
        0,
        GL_RGBA,
        width,
        height,
        0,
        format,
        type,
        ilGetData() );

    // Error check
    if( !ErrorCheck("Failed to bind a side of the cubemap!") )
        return false;

    // Get rid of DevIL data
    ilDeleteImage( image );
}

// Parameters
glTexParameterf( GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glTexParameterf( GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glTexParameterf( GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
glTexParameterf( GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
glTexParameterf( GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE );

Draw code

    // Update
glfwPollEvents();
UpdateTime();

// Clear back buffer for new frame
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );


// Bind shader
shader->Bind();

// Cubemap
shader->SetUniform( "cubemapTexture", 0 );
glActiveTexture( GL_TEXTURE0 );
glBindTexture( GL_TEXTURE_CUBE_MAP, cubemap );

// Bind model
if( model->Bind() )
{
    static float angle = 0;
    angle += 25.0f * deltaTime;

    // Matrices
    mat4 world =
            translate( vec3( 0.0f, 0.0f, 0.0f) ) *
            rotateZ( angle * PI / 180 ) *
            rotateX( angle * PI / 180 ) *
            scale( vec3( 1.0f, 1.0f, 1.0f) );
    mat4 view = ViewMatrix(
            cameraPosition,
            cameraTarget,
            vec3( 0.0f,  0.0f,  1.0f) );
    mat4 proj = ProjectionMatrix(
            fov,
            (float)windowX,
            (float)windowY,
            nearPlane,
            farPlane );

    // Uniforms
    shader->SetUniform( "uWorld", world );
    shader->SetUniform( "uView", view );
    shader->SetUniform( "uProj", proj );

    shader->SetUniform( "materialColor", vec3( 0.5f, 0.5f, 0.5f ) );

    shader->SetUniform( "drawSkybox", false );
    shader->SetUniform( "world_cameraPosition", cameraPosition );
    shader->SetUniform( "reflectFactor", 0.5f );

    // Draw
    glDrawElements( GL_TRIANGLES, model->GetIndexCount(), GL_UNSIGNED_SHORT, NULL );
}

// Put the new image on the screen
glfwSwapBuffers( window );

Vertex Shader

#version 400

layout(location=0) in vec3 vertex_position;
layout(location=1) in vec3 vertex_normal;
layout(location=2) in vec4 vertex_tangent;
layout(location=3) in vec2 vertex_texCoords;

out vec2 texCoords;
out vec3 reflectDir;

uniform mat4 uWorld;
uniform mat4 uView;
uniform mat4 uProj;

uniform bool drawSkybox;
uniform vec3 world_cameraPosition;

void main()
{
    if( drawSkybox )
    {
        reflectDir = vertex_position;
    }
    else
    {
        vec3 world_pos = vec3( uWorld * vec4(vertex_position,1.0) );
        vec3 world_norm = vec3( uWorld * vec4(vertex_normal,0.0) );
        vec3 world_view = normalize( world_cameraPosition - world_pos );

        reflectDir = reflect( -world_view, world_norm );
    }

    gl_Position = uProj * uView * uWorld * vec4(vertex_position,1.0);
    texCoords = vertex_texCoords;
}

Fragment shader

#version 400

out vec4 fragColor;

in vec2 texCoords;
in vec3 reflectDir;

uniform samplerCube cubemapTexture;

uniform vec3 materialColor;
uniform bool drawSkybox;
uniform float reflectFactor;

void main()
{
    vec3 color = texture( cubemapTexture, reflectDir ).rgb;

    if( drawSkybox )
    {
        fragColor = vec4( color, 1.0 );
    }
    else
    {
        fragColor = vec4( mix( materialColor, color, reflectFactor ), 1.0 );
    }
}

Solution

  • Your cube map texture is not texture complete. All 6 sides need to be specified for a cube map texture to be complete. From the specs:

    Additionally, a cube map texture is cube complete if the following conditions all hold true: [..] The level_base arrays of each of the six texture images making up the cube map have identical, positive, and square dimensions.

    Your code does not specify an image for NEGATIVE_X:

    uint TARGETS[6] =
    {
        GL_TEXTURE_CUBE_MAP_POSITIVE_X,
        GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
        GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
        GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
        GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
        GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
    };
    

    Using this table, the image for NEGATIVE_Y is specified twice, but it's missing NEGATIVE_X. It should be:

    uint TARGETS[6] =
    {
        GL_TEXTURE_CUBE_MAP_POSITIVE_X,
        GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
        GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
        GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
        GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
        GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
    };
    

    Instead of enumerating the 6 targets, you can also use GL_TEXTURE_CUBE_MAP_POSITIVE_X + i for i in the range 0..5 to address the 6 targets.