I'm using the following code to create a cube map render target:
glGenTextures( 1, &id );
glBindTexture( GL_TEXTURE_CUBE_MAP, id );
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 );
// Creates a renderbuffer object to store depth info.
GLuint bufferId;
glGenRenderbuffers( 1, &bufferId );
glBindRenderbuffer( GL_RENDERBUFFER, bufferId );
glRenderbufferStorage( GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width, height );
glBindRenderbuffer( GL_RENDERBUFFER, 0 );
glGenFramebuffers( 1, &fboId );
glBindFramebuffer( GL_FRAMEBUFFER, fboId );
const GLenum externalFormat = GL_RGBA;
const GLenum internalFormat = GL_RGBA8;
const GLenum dataType = GL_UNSIGNED_BYTE;
for (int i = 0; i < 6; ++i)
{
glTexImage2D( GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, internalFormat,
size, size, 0, externalFormat,
dataType, nullptr );
glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, id, 0 );
}
glFramebufferRenderbuffer( GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, bufferId );
It doesn't generate any OpenGL errors in OpenGL 3.2 context but when running the same code under OpenGL 4.3 context, debug output callback gives the following error on glFramebufferTexture2D:
OpenGL: Framebuffer unsupported. Attachment COLOR_ATTACHMENT0 unsupported because it uses an inconsistent texture due to invalid texture parameters.
I'm running the code on Windows 8.1 with NVIDIA GeForce GT 750M, driver 337.88. Am I creating the render target wrongly?
I'm not sure what the error is about, but maybe related to a mismatch between size
, width
and height
.
Regardless, there's a few other issues:
Each loop iteration simply overrides GL_COLOR_ATTACHMENT0
. Perhaps change to GL_COLOR_ATTACHMENT0 + i
.
However this means you must write to every layer in the cube when ever a fragment passes the depth test.
You also have a single renderbuffer with just one layer which means a single depth test is used for all sides of your cube.
I don't think the above is what you want anyway.
To render to a cube texture you could bind each layer in turn, rendering the whole scene multiple times each from a new projection. This is the old way of doing it.
To render to a cube texture with just one rendering pass you can bind the entire cube map (which is really just 6 layers of a regular texture) to GL_COLOR_ATTACHMENT0
. For depth testing, you create and bind another cube texture (or renderbuffer, but not sure if you can) with GL_DEPTH_COMPONENT
to GL_DEPTH_ATTACHMENT
. Then in the geometry shader you duplicate everything 6 times, one for each face of your cube. gl_Layer
in the geometry shader is used to set which face in the cube the primitive draws to. Come to think of it you could also use instancing (glDrawElementsInstanced
/gl_InstanceID
) to duplicate your geometry 6 times which would shift computation from the geometry shader to the vertex shader and may be a little faster if your vertex operations are expensive.
In both cases you'll need a 90 degree projection matrix with aspect ration 1 and will need to rotate the view to match the cube faces (this is pretty fiddly so save your code for future use). So create 6 the view matrices and pass them in to either the geometry or vertex shader depending on whether you use instancing or not.