Original Post
Hey all, I'm having a bit of trouble trying to get a cubemap to work with OpenGL and GLSL. It seems to upload it just fine, at least GlIntercept outputs the cubemap texture in the way I would expect it too. However, when I try to sample the texture all I seem to get is just plain black no matter which coordinates I use to sample. The source texture has essentially no black at all.
I have been tearing my hair over this for the past few days and I'm wondering if any of you could spot the likely stupid mistake I've made?
Texture loading code:
[source lang="cpp"]namespace
{
SDL_Surface* createCubeMapFace(SDL_Surface* in, int faceStartX, int faceStartY, int width, int height)
{
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
SDL_Surface* bufferSurface = SDL_CreateRGBSurface(0, width, height, 32, 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000);
#else
SDL_Surface* bufferSurface = SDL_CreateRGBSurface(0, width, height, 32, 0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF);
#endif
SDL_Rect rect;
rect.w = width;
rect.h = height;
rect.x = faceStartX;
rect.y = faceStartY;
SDL_Rect dest;
dest.x = 0;
dest.y = 0;
SDL_FillRect(bufferSurface, &dest, SDL_MapRGBA(bufferSurface->format, 0, 0xFF, 0, 0xFF));
SDL_BlitSurface(in, ▭, bufferSurface, &dest);
return bufferSurface;
}
void uploadCubeMapFace(GLenum cubeMapFace, SDL_Surface* face, bool generateMipMaps)
{
glTexImage2D(cubeMapFace, 0, GL_RGBA, face->w, face->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, face->pixels );
tryLogError();
if (generateMipMaps) gluBuild2DMipmaps(cubeMapFace, GL_RGBA, face->w , face->h, GL_RGBA,GL_UNSIGNED_BYTE, face->pixels);
tryLogError();
}
GLuint uploadFaceSet(SDL_Surface*left,
SDL_Surface* front,
SDL_Surface* right,
SDL_Surface* far,
SDL_Surface* top,
SDL_Surface* bottom,
bool mipmapped)
{
GLuint id;
glGenTextures(1, &id);
glEnable(GL_TEXTURE_CUBE_MAP);
glBindTexture(GL_TEXTURE_CUBE_MAP, id);
tryLogError();
// Upload texture
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_MIRRORED_REPEAT);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
//Create cube map
uploadCubeMapFace(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, left, mipmapped);
uploadCubeMapFace(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, front, mipmapped);
uploadCubeMapFace(GL_TEXTURE_CUBE_MAP_POSITIVE_X, right, mipmapped);
uploadCubeMapFace(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, far, mipmapped);
uploadCubeMapFace(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, top, mipmapped);
uploadCubeMapFace(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, bottom, mipmapped);
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
return id;
}
// Loads a Texture into VideoRAM and returns a texture id
GLuint loadCubeMapTextureIntoVRAM(Image* image, bool generateMipMaps)
{
assert(image->getWidth() % 4 == 0);
assert(image->getHeight() % 3 == 0);
assert(image->getWidth()/4 == image->getHeight()/3);
int sideWidth = image->getWidth()/4;
int sideHeight = image->getHeight()/3;
auto left = createCubeMapFace(image->getInternalSurface(), sideWidth*0, sideHeight*1, sideWidth, sideHeight);
auto front = createCubeMapFace(image->getInternalSurface(), sideWidth*1, sideHeight*1, sideWidth, sideHeight);
auto right = createCubeMapFace(image->getInternalSurface(), sideWidth*2, sideHeight*1, sideWidth, sideHeight);
auto far = createCubeMapFace(image->getInternalSurface(), sideWidth*3, sideHeight*1, sideWidth, sideHeight);
auto top = createCubeMapFace(image->getInternalSurface(), sideWidth*1, sideHeight*0, sideWidth, sideHeight);
auto bottom = createCubeMapFace(image->getInternalSurface(), sideWidth*1, sideHeight*2, sideWidth, sideHeight);
auto retVal = uploadFaceSet(left,
front,
right,
far,
top,
bottom,
generateMipMaps);
SDL_FreeSurface(left);
SDL_FreeSurface(front);
SDL_FreeSurface(right);
SDL_FreeSurface(far);
SDL_FreeSurface(top);
SDL_FreeSurface(bottom);
return retVal;
}
}[/source]
Code used to sent the cubemap id to the shader program, I have checked that the id is correct and that the part of the of the code is executed as it should as well as having a unique sampler number.
[source lang="cpp"]void ShaderProgram::setTexture(String variableName, int samplerNo, ICubeMap* texture)
{
assert(this->programId == activeProgram);
assert(samplerNo >= 0);
glEnable(GL_TEXTURE_CUBE_MAP);
glBindTexture(GL_TEXTURE_CUBE_MAP, texture->getOpenGLId());
glActiveTexture(GL_TEXTURE0 + samplerNo);
GLuint loc = glGetUniformLocation(this->programId, variableName.getStringUtf8());
glUniform1i(loc, samplerNo);
}[/source]
Finally, the minimimalistic test fragment shader:
[source lang="cpp"]#version 330
uniform samplerCube cubeMapTexture;
in vec4 rawNormal;
out vec4 fragmentColour;
void main(void)
{
fragmentColour = texture(cubeMapTexture, vec3(rawNormal.xyz));
}[/source]
The vertex shader works as it should, if I hard set the colour in the fragment shader the object appears as expected.
I would be thankful for any help.
I have been tearing my hair over this for the past few days and I'm wondering if any of you could spot the likely stupid mistake I've made?
Texture loading code:
[source lang="cpp"]namespace
{
SDL_Surface* createCubeMapFace(SDL_Surface* in, int faceStartX, int faceStartY, int width, int height)
{
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
SDL_Surface* bufferSurface = SDL_CreateRGBSurface(0, width, height, 32, 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000);
#else
SDL_Surface* bufferSurface = SDL_CreateRGBSurface(0, width, height, 32, 0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF);
#endif
SDL_Rect rect;
rect.w = width;
rect.h = height;
rect.x = faceStartX;
rect.y = faceStartY;
SDL_Rect dest;
dest.x = 0;
dest.y = 0;
SDL_FillRect(bufferSurface, &dest, SDL_MapRGBA(bufferSurface->format, 0, 0xFF, 0, 0xFF));
SDL_BlitSurface(in, ▭, bufferSurface, &dest);
return bufferSurface;
}
void uploadCubeMapFace(GLenum cubeMapFace, SDL_Surface* face, bool generateMipMaps)
{
glTexImage2D(cubeMapFace, 0, GL_RGBA, face->w, face->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, face->pixels );
tryLogError();
if (generateMipMaps) gluBuild2DMipmaps(cubeMapFace, GL_RGBA, face->w , face->h, GL_RGBA,GL_UNSIGNED_BYTE, face->pixels);
tryLogError();
}
GLuint uploadFaceSet(SDL_Surface*left,
SDL_Surface* front,
SDL_Surface* right,
SDL_Surface* far,
SDL_Surface* top,
SDL_Surface* bottom,
bool mipmapped)
{
GLuint id;
glGenTextures(1, &id);
glEnable(GL_TEXTURE_CUBE_MAP);
glBindTexture(GL_TEXTURE_CUBE_MAP, id);
tryLogError();
// Upload texture
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_MIRRORED_REPEAT);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
//Create cube map
uploadCubeMapFace(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, left, mipmapped);
uploadCubeMapFace(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, front, mipmapped);
uploadCubeMapFace(GL_TEXTURE_CUBE_MAP_POSITIVE_X, right, mipmapped);
uploadCubeMapFace(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, far, mipmapped);
uploadCubeMapFace(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, top, mipmapped);
uploadCubeMapFace(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, bottom, mipmapped);
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
return id;
}
// Loads a Texture into VideoRAM and returns a texture id
GLuint loadCubeMapTextureIntoVRAM(Image* image, bool generateMipMaps)
{
assert(image->getWidth() % 4 == 0);
assert(image->getHeight() % 3 == 0);
assert(image->getWidth()/4 == image->getHeight()/3);
int sideWidth = image->getWidth()/4;
int sideHeight = image->getHeight()/3;
auto left = createCubeMapFace(image->getInternalSurface(), sideWidth*0, sideHeight*1, sideWidth, sideHeight);
auto front = createCubeMapFace(image->getInternalSurface(), sideWidth*1, sideHeight*1, sideWidth, sideHeight);
auto right = createCubeMapFace(image->getInternalSurface(), sideWidth*2, sideHeight*1, sideWidth, sideHeight);
auto far = createCubeMapFace(image->getInternalSurface(), sideWidth*3, sideHeight*1, sideWidth, sideHeight);
auto top = createCubeMapFace(image->getInternalSurface(), sideWidth*1, sideHeight*0, sideWidth, sideHeight);
auto bottom = createCubeMapFace(image->getInternalSurface(), sideWidth*1, sideHeight*2, sideWidth, sideHeight);
auto retVal = uploadFaceSet(left,
front,
right,
far,
top,
bottom,
generateMipMaps);
SDL_FreeSurface(left);
SDL_FreeSurface(front);
SDL_FreeSurface(right);
SDL_FreeSurface(far);
SDL_FreeSurface(top);
SDL_FreeSurface(bottom);
return retVal;
}
}[/source]
Code used to sent the cubemap id to the shader program, I have checked that the id is correct and that the part of the of the code is executed as it should as well as having a unique sampler number.
[source lang="cpp"]void ShaderProgram::setTexture(String variableName, int samplerNo, ICubeMap* texture)
{
assert(this->programId == activeProgram);
assert(samplerNo >= 0);
glEnable(GL_TEXTURE_CUBE_MAP);
glBindTexture(GL_TEXTURE_CUBE_MAP, texture->getOpenGLId());
glActiveTexture(GL_TEXTURE0 + samplerNo);
GLuint loc = glGetUniformLocation(this->programId, variableName.getStringUtf8());
glUniform1i(loc, samplerNo);
}[/source]
Finally, the minimimalistic test fragment shader:
[source lang="cpp"]#version 330
uniform samplerCube cubeMapTexture;
in vec4 rawNormal;
out vec4 fragmentColour;
void main(void)
{
fragmentColour = texture(cubeMapTexture, vec3(rawNormal.xyz));
}[/source]
The vertex shader works as it should, if I hard set the colour in the fragment shader the object appears as expected.
I would be thankful for any help.