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 );
}
}
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:
Your code does not specify an image for
NEGATIVE_X
:Using this table, the image for
NEGATIVE_Y
is specified twice, but it's missingNEGATIVE_X
. It should be:Instead of enumerating the 6 targets, you can also use
GL_TEXTURE_CUBE_MAP_POSITIVE_X + i
fori
in the range 0..5 to address the 6 targets.