OpenGL and CubeMaps, all I get is a black cube

Hi, I’m currently trying to figure out how to use cubemaps in combination with textures but I’m struggling somehow and after spending the whole afternoon on this stuff I’m getting out of ideas now.

All I get is a black cube. If I change the fragment shader to some colors the cube is colored too, so my hint is that something seems to be wrong with the samplerCube.

My vertex shader code looks like this:


#version 330 core
layout(location=0) in vec3 posAttr;
out vec3 texCoord;

uniform highp mat4 matrix;

void main() {
    texCoord = posAttr;
    gl_Position = matrix * vec4(posAttr.xyz, 1.0);
}

My fragment shader code looks like this:


#version 330 core

// I need the following line to convince QT that the command texture is known
// If I compile the code without this it also works but the IDE is complaining otherwise
#define texture2D texture

in vec3 texCoord;
out vec4 aColor;
uniform samplerCube skyBoxSampler;

void main() {
     vec4 frag = texture(skyBoxSampler, -texCoord);
     aColor = vec4(frag.xyz, 1.0);
}

I create the texture stuff with the following code:


glActiveTexture(GL_TEXTURE0);

    GLuint textureId;

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

    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);


    int width,height;
    unsigned char* image;
    for(GLuint i = 0; i < 6; i++)
    {
        QImage img(paths[i]);
        int width = img.width();
        int height = img.height();
        int bpp = img.depth();

        glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGBA, width, height, 0, format, GL_UNSIGNED_BYTE, img.bits());
    }


   // glGenSamplers(1, &samplerId);

    glBindTexture(GL_TEXTURE_CUBE_MAP, 0);

And finally this is my rendering code:


glDepthMask(GL_FALSE);

    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);

    glBindVertexArray(uiVAO);
    glUseProgram(this->shaderProgramId);

    glClearColor(0.0f, 0.0f, 0.4f, 0.0f);
    glUniformMatrix4fv(this->matrixUniformId, 1, GL_FALSE,  glm::value_ptr(modelViewMatrix));

    int iSamplerLoc = glGetUniformLocation(shaderProgramId, "skyBoxSampler");
    glUniform1i(iSamplerLoc, 0);

    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_CUBE_MAP, textureId);

    // glBindSampler(0, samplerId);

    glDrawArrays(GL_TRIANGLES, 0, vVertexData.size());


    glUseProgram(0);
    glBindVertexArray(0);


    glDisable(GL_PROGRAM_POINT_SIZE);
    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);

    glDepthMask(GL_TRUE);

Several questions that arose during implementing this stuff:

  • Do I have to generate a sampler like I do for 2D textures? I left it out as I did not see this in example code which I could find online in different places
  • How do texture units work? As far as I understood several textures can be assigned to one texture unit is this correct? I would identify them by adding a number to the corresponding unit like GL_TEXTURE0+index
  • For what purpose are samplers used? Why are they used in combination with textures?

did you check for any errors?
https://www.opengl.org/wiki/OpenGL_Error

do all of your 6 faces have the same resolution? (like 256 x 256)
do all of your 6 faces have a power-of-two resolution? (like 256 x 256)

here i have made 2 examples for cubemap / skybox:
https://sites.google.com/site/john87connor/home/tutorial-09-5-cube-map
https://sites.google.com/site/john87connor/home/tutorial-09-5-2-example-sky-box

here is another example in the opengl wiki: (just ignore the framebuffer stuff)
https://www.opengl.org/wiki/Framebuffer_Object_Extension_Examples#Quick_example.2C_render_to_texture_.28Cubemap.29

yes, I checked that

yes, I get no errors

yes

I will have now a look at your code. Downsizing is a little bit problematic. Probably I will build up something from scratch to see what is essential so that things are working.

Question: From the code that I’ve posted above does everything look ok?

I’ve gone through your first code example link.

I had several problems getting it to run on OSX

First of all OS X does not support a compatibility profile which is backwards compatible if you want to use OpenGL 3.2 functions and above.

Second is your program example crashed as my GPU only supports functions up to OpenGL 3.3.

Is there any substitute for the function


glBindTextureUnit(texture_unit, texture);

I thought I can substitute it with this one:


glActiveTexture(GL_TEXTURE0+1); // for texture unit
glBindTexture(GL_TEXTURE_CUBE_MAP, texture);

but I ended up getting just a grey screen.

I also tried putting the stuff in the rendering loop but that didn’t help either…

Also the in’s and outs in the shaders had to be changed in the shading language for ogl 3.3
Is it necessary to have this notation or wouldn’t it be better for backwards compatibility to have the layout before the in’s and out’s

In the meantime I took this code part:


// setup texture
    unsigned int width = 1, height = 1;
    unsigned char xpos[] = { 0xFF, 0x00, 0x00, 0xFF };    // red
    unsigned char xneg[] = { 0x00, 0xFF, 0xFF, 0xFF };    // cyan
    unsigned char ypos[] = { 0x00, 0xFF, 0x00, 0xFF };    // green
    unsigned char yneg[] = { 0xFF, 0x00, 0xFF, 0xFF };    // magenta
    unsigned char zpos[] = { 0x00, 0x00, 0xFF, 0xFF };    // blue
    unsigned char zneg[] = { 0xFF, 0xFF, 0x00, 0xFF };    // yellow
    glBindTexture(GL_TEXTURE_CUBE_MAP, texture);
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + 0, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, xpos);
    glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + 1, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, xneg);
    glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + 2, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, ypos);
    glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + 3, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, yneg);
    glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + 4, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, zpos);
    glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + 5, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, zneg);
    glBindTexture(GL_TEXTURE_CUBE_MAP, 0);

and put it in my project. Just to see whether I have a problem with the picture formats or not. It turned out that the pictures are not the issue and that the colors are just not forwarded to the fragment shader for some stupid reason

I haven’t dug through your code yet, but here’s a working program from deadc0de that renders into and does lookups from a cube map for the purposes of casting point light-source shadows:


// From:
//   http://www.opengl.org/discussion_boards/showthread.php/174093-GLSL-cube-shadows-projecting?p=1219162&viewfull=1#post1219162
// By: 
//   deadc0de

// Example Depth Cube Map Shadowing

#include <math.h>
#include <stdlib.h>

#define GL_GLEXT_PROTOTYPES
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>


#define WINDOW_SIZE     (512)
#define WINDOW_NEAR     (1.0)
#define WINDOW_FAR      (100.0)

#define SHADOW_SIZE     (256)
#define SHADOW_NEAR     (1.0)
#define SHADOW_FAR      (10.0)

static float camera_position[3] = { -8.0f, 8.0f, -8.0f };
static float camera_view_matrix[16];
static float camera_view_matrix_inv[16];
static float camera_projection_matrix[16];

const float deg_per_frame = 0.1f;
static float light_distance = 5.0f;
static float light_inclination = 45.0f * (M_PI / 180.0f);
static float light_azimuth = 0.0f;

static float light_position_ws[3];
static float light_position_cs[3];
static float light_view_matrix[16];
static float light_face_matrix[6][16];
static float light_projection_matrix[16];

static GLuint tex_depth_cube;

static GLuint program_shadow;
static GLuint shader_shadow_vs;

static GLuint program_render;
static GLuint shader_render_vs;
static GLuint shader_render_fs;

static GLuint framebuffer_shadow;

static const char *shader_shadow_vs_source =
    "#version 120
"
    "#extension GL_EXT_gpu_shader4 : require
"
    "void main()
"
    "{
"
    "    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
"
    "}
"
;
static const char *shader_render_vs_source =
    "#version 120
"
    "#extension GL_EXT_gpu_shader4 : require
"
    "varying vec4 position_cs;
"
    "varying vec3 normal_cs;
"
    "varying vec3 color;
"
    "void main()
"
    "{
"
    "    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
"
    "    position_cs = gl_ModelViewMatrix * gl_Vertex;
"
    "    normal_cs = gl_NormalMatrix * gl_Normal;
"
    "    color = gl_Color.rgb;
"
    "}
"
;
static const char *shader_render_fs_source =
    "#version 120
"
    "#extension GL_EXT_gpu_shader4 : require
"
    "varying vec4 position_cs;
"
    "varying vec3 normal_cs;
"
    "varying vec3 color;
"
    "uniform mat4x4 camera_view_matrix_inv;
"
    "uniform mat4x4 light_view_matrix;
"
    "uniform mat4x4 light_projection_matrix;
"
    "uniform samplerCubeShadow shadow;
"
    "uniform vec3 light_position;
"
    "void main()
"
    "{
"
    "    vec4 position_ls = light_view_matrix * camera_view_matrix_inv * position_cs;
"
    
    // shadow map test
    "    vec4 abs_position = abs(position_ls);
"
    "    float fs_z = -max(abs_position.x, max(abs_position.y, abs_position.z));
"
    "    vec4 clip = light_projection_matrix * vec4(0.0, 0.0, fs_z, 1.0);
"
    "    float depth = (clip.z / clip.w) * 0.5 + 0.5;
"
    "    vec4 result = shadowCube(shadow, vec4(position_ls.xyz, depth));
"
    
    "    vec3 lvector = light_position - position_cs.xyz;
"
    "    float ldistance = length(lvector);
"
    "    float lintensity = max(dot(normal_cs, normalize(lvector)), 0.0) * 10.0;
"
    "    lintensity /= ldistance * ldistance;
"
    "    lintensity /= lintensity + 0.5;
"
    "    vec3 diffuse = lintensity * result.xyz * color;
"
    "    gl_FragColor = vec4(diffuse,1);
"
    "}
"
;

static void
app_init()
{
    glEnable(GL_CULL_FACE);
    glEnable(GL_DEPTH_TEST);
    
    // create camera matrix
    glLoadIdentity();
    gluLookAt(camera_position[0], camera_position[1], camera_position[2], 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
    glGetFloatv(GL_MODELVIEW_MATRIX, camera_view_matrix);
    
    // create camera inverse matrix
    camera_view_matrix_inv[ 0] = camera_view_matrix[ 0];
    camera_view_matrix_inv[ 1] = camera_view_matrix[ 4];
    camera_view_matrix_inv[ 2] = camera_view_matrix[ 8];
    camera_view_matrix_inv[ 4] = camera_view_matrix[ 1];
    camera_view_matrix_inv[ 5] = camera_view_matrix[ 5];
    camera_view_matrix_inv[ 6] = camera_view_matrix[ 9];
    camera_view_matrix_inv[ 8] = camera_view_matrix[ 2];
    camera_view_matrix_inv[ 9] = camera_view_matrix[ 6];
    camera_view_matrix_inv[10] = camera_view_matrix[10];
    camera_view_matrix_inv[12] = camera_position[0];
    camera_view_matrix_inv[13] = camera_position[1];
    camera_view_matrix_inv[14] = camera_position[2];
    camera_view_matrix_inv[ 3] = 0.0f;
    camera_view_matrix_inv[ 7] = 0.0f;
    camera_view_matrix_inv[11] = 0.0f;
    camera_view_matrix_inv[15] = 1.0f;
    
    // create light face matrices
    glLoadIdentity(); gluLookAt(0.0, 0.0, 0.0,  1.0, 0.0, 0.0,  0.0,-1.0, 0.0); // +X
    glGetFloatv(GL_MODELVIEW_MATRIX, light_face_matrix[0]);
    glLoadIdentity(); gluLookAt(0.0, 0.0, 0.0, -1.0, 0.0, 0.0,  0.0,-1.0, 0.0); // -X
    glGetFloatv(GL_MODELVIEW_MATRIX, light_face_matrix[1]);
    glLoadIdentity(); gluLookAt(0.0, 0.0, 0.0,  0.0, 1.0, 0.0,  0.0, 0.0, 1.0); // +Y
    glGetFloatv(GL_MODELVIEW_MATRIX, light_face_matrix[2]);
    glLoadIdentity(); gluLookAt(0.0, 0.0, 0.0,  0.0,-1.0, 0.0,  0.0, 0.0,-1.0); // -Y
    glGetFloatv(GL_MODELVIEW_MATRIX, light_face_matrix[3]);
    glLoadIdentity(); gluLookAt(0.0, 0.0, 0.0,  0.0, 0.0, 1.0,  0.0,-1.0, 0.0); // +Z
    glGetFloatv(GL_MODELVIEW_MATRIX, light_face_matrix[4]);
    glLoadIdentity(); gluLookAt(0.0, 0.0, 0.0,  0.0, 0.0,-1.0,  0.0,-1.0, 0.0); // -Z
    glGetFloatv(GL_MODELVIEW_MATRIX, light_face_matrix[5]);
    
    // create light projection matrix
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(90.0, 1.0, SHADOW_NEAR, SHADOW_FAR);
    glGetFloatv(GL_PROJECTION_MATRIX, light_projection_matrix);
    glMatrixMode(GL_MODELVIEW);
    
    // create depth cube map
    glGenTextures(1, &tex_depth_cube);
    glBindTexture(GL_TEXTURE_CUBE_MAP, tex_depth_cube);
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_DEPTH_TEXTURE_MODE, GL_LUMINANCE);
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
    for (size_t 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, 0);
    }
    glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
    
    // create shadow shader
    shader_shadow_vs = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(shader_shadow_vs, 1, &shader_shadow_vs_source, NULL);
    glCompileShader(shader_shadow_vs);
    
    // create shadow program
    program_shadow = glCreateProgram();
    glAttachShader(program_shadow, shader_shadow_vs);
    glLinkProgram(program_shadow);
    
    // create render shader
    shader_render_vs = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(shader_render_vs, 1, &shader_render_vs_source, NULL);
    glCompileShader(shader_render_vs);
    shader_render_fs = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(shader_render_fs, 1, &shader_render_fs_source, NULL);
    glCompileShader(shader_render_fs);
    
    // create render program
    program_render = glCreateProgram();
    glAttachShader(program_render, shader_render_vs);
    glAttachShader(program_render, shader_render_fs);
    glLinkProgram(program_render);
    
    // create shadow framebuffer
    glGenFramebuffersEXT(1, &framebuffer_shadow);
}

static void
draw_shadow_casters()
{
    glColor3ub(255,0,0);
    glPushMatrix();
        glTranslated(-1.0, 0.0,-1.0);
        glutSolidSphere(1.0, 20, 10);
    glPopMatrix();
    
    glColor3ub(0,255,0);
    glPushMatrix();
        glTranslated( 1.0, 0.0, 1.0);
        glutSolidCube(2.0);
    glPopMatrix();
    
    glColor3ub(0,0,255);
    glPushMatrix();
        glTranslated( 1.0, 0.0,-1.0);
        glutSolidIcosahedron();
    glPopMatrix();
    
    glColor3ub(255,0,255);
    glPushMatrix();
        glTranslated(-1.0, 0.0, 1.0);
        glutSolidOctahedron();
    glPopMatrix();
}

static void
draw_scene()
{
    draw_shadow_casters();
    
    glColor3ub(255, 255, 255);
    glNormal3f(0.0f, 1.0f, 0.0f);
    glBegin(GL_QUADS);
        glVertex3i( 10, -1,-10);
        glVertex3i(-10, -1,-10);
        glVertex3i(-10, -1, 10);
        glVertex3i( 10, -1, 10);
    glEnd();
}

static void
app_update()
{
    // rotate the light about the Y-axis
    light_azimuth = fmodf(light_azimuth + (deg_per_frame * M_PI / 180.0f), 2.0f * M_PI);
    
    // update the world space light position
    light_position_ws[0] = light_distance * sinf(light_inclination) * cosf(light_azimuth);
    light_position_ws[1] = light_distance * cosf(light_inclination);
    light_position_ws[2] = light_distance * sinf(light_inclination) * sinf(light_azimuth);
    
    // create the light view matrix (construct this as you would a camera matrix)
    glLoadIdentity();
    glTranslatef(-light_position_ws[0], -light_position_ws[1], -light_position_ws[2]);
    glGetFloatv(GL_MODELVIEW_MATRIX, light_view_matrix);
    
    // transform world space light position to camera space
    light_position_cs[0] =
        camera_view_matrix[ 0] * light_position_ws[0] +
        camera_view_matrix[ 4] * light_position_ws[1] +
        camera_view_matrix[ 8] * light_position_ws[2] +
        camera_view_matrix[12];
    light_position_cs[1] =
        camera_view_matrix[ 1] * light_position_ws[0] +
        camera_view_matrix[ 5] * light_position_ws[1] +
        camera_view_matrix[ 9] * light_position_ws[2] +
        camera_view_matrix[13];
    light_position_cs[2] =
        camera_view_matrix[ 2] * light_position_ws[0] +
        camera_view_matrix[ 6] * light_position_ws[1] +
        camera_view_matrix[10] * light_position_ws[2] +
        camera_view_matrix[14];
}

static void
app_display()
{
    app_update();
    
    ////////////////////////////////////////////////////////////////////////////
    // RENDER DEPTH CUBE MAP
    
    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, framebuffer_shadow);
    glDrawBuffer(GL_NONE);
    glReadBuffer(GL_NONE);
    glViewport(0, 0, SHADOW_SIZE, SHADOW_SIZE);
    
    glCullFace(GL_FRONT);
    
    glMatrixMode(GL_PROJECTION);
    glLoadMatrixf(light_projection_matrix);
    glMatrixMode(GL_MODELVIEW);
    
    for (size_t i = 0; i < 6; ++i) {
        glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, tex_depth_cube, 0);
        
        glClear(GL_DEPTH_BUFFER_BIT);
        
        glLoadMatrixf(light_face_matrix[i]);
        glMultMatrixf(light_view_matrix);
        
        glUseProgram(program_shadow);
        
        draw_shadow_casters();
    }
    
    ////////////////////////////////////////////////////////////////////////////
    // RENDER SCENE
    
    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
    glDrawBuffer(GL_BACK);
    glReadBuffer(GL_BACK);
    glViewport(0, 0, WINDOW_SIZE, WINDOW_SIZE);
    
    glCullFace(GL_BACK);
    
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(45.0, 1.0, WINDOW_NEAR, WINDOW_FAR);
    glMatrixMode(GL_MODELVIEW);
    
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

    glLoadMatrixf(camera_view_matrix);
    
    glUseProgram(program_render);
    glUniform1i(glGetUniformLocation(program_render, "shadow"), 0);
    glUniform3fv(glGetUniformLocation(program_render, "light_position"), 1, light_position_cs);
    glUniformMatrix4fv(glGetUniformLocation(program_render, "camera_view_matrix_inv"), 1, GL_FALSE, camera_view_matrix_inv);
    glUniformMatrix4fv(glGetUniformLocation(program_render, "light_view_matrix"), 1, GL_FALSE, light_view_matrix);
    glUniformMatrix4fv(glGetUniformLocation(program_render, "light_projection_matrix"), 1, GL_FALSE, light_projection_matrix);
    
    glEnable(GL_TEXTURE_CUBE_MAP);
    glBindTexture(GL_TEXTURE_CUBE_MAP, tex_depth_cube);
    
    draw_scene();
    
    glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
    glDisable(GL_TEXTURE_CUBE_MAP);
    
    glUseProgram(0);
    glPushMatrix();
        glTranslatef(light_position_ws[0], light_position_ws[1], light_position_ws[2]);
        glColor3ub(255,255,0);
        glutSolidSphere(0.1, 10, 5);
    glPopMatrix();
    
    glutSwapBuffers();
}

static void
app_idle()
{
    glutPostRedisplay();
}

int
main(int argc, char *argv[])
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_RGBA | GLUT_ALPHA | GLUT_STENCIL | GLUT_DOUBLE);
    glutInitWindowSize(WINDOW_SIZE, WINDOW_SIZE);
    glutInitWindowPosition(-1, -1);
    glutCreateWindow("example");
    
    glutDisplayFunc(app_display);
    glutIdleFunc(app_idle);
    
    app_init();

    glutMainLoop();
    
    return (0);
}

If you’re on Linux, compile/link it like this:


g++ -o point_shadows point_shadows.cxx -lglut -lGLU -lGL

Note that it uses GLSL 1.2, so it’ll require a few minor tweaks if you want to target a later version.

In your “rendering code” snippet, does glGetUniformLocation() return a value >= 0? It should. But I ask because if it returns -1, then the glUniform1i() call will be a no-op and you’ll get no GL error to signify that the set call was ignored.

(This is unlikely to be it though because the default value of this uniform should be 0, and you should be getting a valid uniform location anyway.)

Other than that, nothing jumps out to me as being incorrect in code snippets.

I’d suggest either 1) posting a stand-alone GLUT test program which illustrates the problem, or 2) taking a working cube map sample and gradually transforming into the code you’re using to see when it breaks.

No.

Since you’ve set your texture parameters on your cube map texture object, you might make sure that you don’t have a sampler object bound to your texture unit while you’re trying to do the cubemap sampling, just to be safe (bind sampler object 0 to unbind whatever’s active).

How do texture units work? As far as I understood several textures can be assigned to one texture unit is this correct? I would identify them by adding a number to the corresponding unit like GL_TEXTURE0+index

Think of them as pieces of hardware which can sample from a specific texture.

Texture units are indexed up from 0.

Your glActiveTexture(GL_TEXTURE0+index) before glBindTexture() is what is selecting which texture unit to bind it to.

The 0 you’re setting on the skyBoxSampler uniform is telling the shader to sample from texture unit 0 when you sample from skyBoxSampler.

  • For what purpose are samplers used? Why are they used in combination with textures?

Sampler “uniforms” (e.g. skyBoxSampler) are basically handles for texture units in the shader.

Sampler “objects” are something different (see the wiki links below). They’re basically ways to keep track texture sampling parameters (aka texture parameters) separate from the texture object:

(This is unlikely to be it though because the default value of this uniform should be 0, and you should be getting a valid uniform location anyway.)

I checked the result value. It’s 4. Seems to be ok to me. What might also be a source of a troublemaker is the remaining code maybe. I generate a heightmap and assign a 2D texture to it. Therefore I have a separate program, other shaders and another texture and the sampler of course. To be on the safe side I commented this out and it still makes no difference. I’m going through the sample code that you’ve posted now and see if I can get the bare metal stuff running to find out what is essential.

I’d suggest either 1) posting a stand-alone GLUT test program which illustrates the problem, or 2) taking a working cube map sample and gradually transforming into the code you’re using to see when it breaks.

I think I have to do the second solution. I’d like to do the first one but the issue is I’m using the OSX environment and there are a couple of things which need to be made portable before everyone could run it up. The fact that the QT Environment is mixed in is not necessarily making the stuff easier. Nevertheless I have the code fully available on Github.

you’ve said that the color is your problem and you are getting a black cube on screen, correct?

go a few steps back, replace in your fragmentshader:
aColor = vec4(frag.xyz, 1.0);

with:
aColor = vec4(1, 0, 0, 1); // red

-> you should get a red cube now

checking the sampler:

then try to use a simple 2D texture, like this:

// setup texture
glBindTexture(GL_TEXTURE_2D, texture);
// set necessary texture parameters
glTexParameteri(GL_TEXTURE_2D,        GL_TEXTURE_WRAP_S,            GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D,        GL_TEXTURE_WRAP_T,            GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D,        GL_TEXTURE_MIN_FILTER,        GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,        GL_TEXTURE_MAG_FILTER,    GL_LINEAR);
// allocate memory and set texture data
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
glBindTexture(GL_TEXTURE_2D, 0);

use 1 x 1 for width and height
use {0x00, 0xFF, 0x00, 0xFF} as data (green)
bind it to a certain texture unit (lets say 5) and set the sampler value to the same value (5)

glActiveTexture(GL_TEXTURE0 + 5);
glBindTexture(GL_TEXTURE_2D, texture);

use simply vec2(0, 0) as texcoords in your fragmentshader (that would means the upper left texel)

–> now you should get a green cube

checking the coordinates:

try displaying the vec3 texcoords (the posattrib value you pass from your vertexshader) as color

-> are you getting a color gradient that smoothly changes? if yes, thats OK

an important note:

your program object has to be activated at the time you call:
glUniform1i(location, value);

that means you have to call:
glUseProgram(program);
BEFORE the command above!

or if you can use direct-state-access function calls:
https://www.opengl.org/wiki/Direct_State_Access

then you could skip activating the program before setting the uniform value by calling:
glProgramUniform1i(program, location, value);

you’ve said that the color is your problem and you are getting a black cube on screen, correct?

yes

go a few steps back, replace in your fragmentshader:
aColor = vec4(frag.xyz, 1.0);

with:
aColor = vec4(1, 0, 0, 1); // red

-> you should get a red cube now

works

checking the sampler:

then try to use a simple 2D texture, like this:

// setup texture
glBindTexture(GL_TEXTURE_2D, texture);
// set necessary texture parameters
glTexParameteri(GL_TEXTURE_2D,        GL_TEXTURE_WRAP_S,            GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D,        GL_TEXTURE_WRAP_T,            GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D,        GL_TEXTURE_MIN_FILTER,        GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,        GL_TEXTURE_MAG_FILTER,    GL_LINEAR);
// allocate memory and set texture data
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
glBindTexture(GL_TEXTURE_2D, 0);

use 1 x 1 for width and height
use {0x00, 0xFF, 0x00, 0xFF} as data (green)
bind it to a certain texture unit (lets say 5) and set the sampler value to the same value (5)

glActiveTexture(GL_TEXTURE0 + 5);
glBindTexture(GL_TEXTURE_2D, texture);

use simply vec2(0, 0) as texcoords in your fragmentshader (that would means the upper left texel)

–> now you should get a green cube

This doesn’t work. Do I have to also generate the sampler as it is a 2D Texture now or can I skip glGenSamplers(1, &samplerId);.
When does a sampler need to be generated? Before or after I generate the texture stuff?

checking the coordinates:

try displaying the vec3 texcoords (the posattrib value you pass from your vertexshader) as color

-> are you getting a color gradient that smoothly changes? if yes, thats OK

Fragment cordinates are ok, I get a nice gradient if I only use them instead of the sampler

an important note:

your program object has to be activated at the time you call:
glUniform1i(location, value);

that means you have to call:
glUseProgram(program);
BEFORE the command above!

I corrected this in my renderer now. I didn’t spot it as an error because a different program was active by that time. However it didn’t change the result unfortunately

Another question regarding texturing units? Can I have 2 textures for a texture unit at the same index?
For example my program uses a 2D Texture for the heightmap. Then I have the cubemap texture. Is it possible to have both textures at the index 0? or does it need to be index 1 then for the cubemap texture?

The reason I ask is because my architecture of the program is segregated.

I have the heightmap which is responsible for their stuff with its own shader programs and own data and so on.
The I activate the cubemap program as soon as I’d like to draw the skybox.

Both program parts map the textures to index 0 at GL_TEXTURE_0. Is this maybe a problem. I changed it in the program to map it to a different index now but I’m still having the same issue.

As far as I understood it the texture indexes should be only relevant if the same active shader is using more than one texture for it’s drawing process is this correct? Therefore it shouldn’t be relevant.

Simply don’t use samplers. They aren’t necessary. They’re just a mechanism for storing sampling state as a separate object rather than as part of the texture.