Reputation: 910
I try to render into a cubemap to make a dynamic skybox. And I try to make it with the direct state access feature from OpenGL 4.5.
I get the idea with a simple 2D Texture for off-screen rendering.
Here is how I do it. I paste only the minimal and effective code.
// 1. Initialization code
{
// FBO (Frame Buffer Object)
GLuint FBO;
glCreateFramebuffers(1, &FBO);
// Texture2D for color buffer
{
GLuint colorBuffer;
glCreateTextures(GL_TEXTURE_2D, 1, &colorBuffer);
glTextureStorage2D(colorBuffer, 1, GL_RGB8, 1024, 1024);
glNamedFramebufferTexture(FBO, GL_COLOR_ATTACHMENT0, colorBuffer, 0);
}
// RBO (Render Buffer Object) for depth buffer.
{
GLuint depthBuffer;
glCreateRenderbuffers(1, &depthBuffer);
glNamedRenderbufferStorage(depthBuffer, GL_DEPTH_COMPONENT24, 1024, 1024);
glNamedFramebufferRenderbuffer(FBO, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthBuffer);
}
if ( glCheckNamedFramebufferStatus(m_identifier, GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE )
exit(1);
}
// 2. Drawing code
{
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, FBO);
glClearNamedFramebufferfv(FBO, GL_COLOR, 0, m_clearColor.data());
glClearNamedFramebufferfv(FBO, GL_DEPTH, 0, &m_clearDepth);
// Draw stuffs ...
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
}
So, to render to a cubemap, my idea is to replace "GL_TEXTURE_2D" by a "GL_TEXTURE_CUBEMAP". I know I need to keep using glTextureStorage2D() to create the storage.
Then, I don't know if the RBO will handle a cubemap rendering... I think of reusing it for each face.
And finally, I'm totally lost with the render part. At least, I know I have to render 6 times the scene with different camera angle to complete the cube. But I don't know how to tell OpenGL which face I'm actually rendering.
One of my first clue is to use "glNamedFramebufferDrawBuffer(FBO, GL_COLOR_ATTACHMENT0 + face)", but it doesn't work.
I saw an other solution when creating the frame buffer with glNamedFramebufferTextureLayer(), but I'm not sure if it's correct.
I dig for solution on the web, but I found a lot of way to do it, some are not compatible with DSA.
Is there someone who achieve this? I just need the main idea.
Upvotes: 3
Views: 1369
Reputation: 72469
You have two options:
You cannot create a cube-map renderbuffer. So if you use renderbuffers for the depth buffer then you have to make six rendering passes, one for each face. To attach each face of the texture to the color buffer in turn you use glNamedFramebufferTextureLayer
:
// 1. Initialization code
// ...
{
GLuint colorBuffer;
glCreateTextures(GL_TEXTURE_CUBE_MAP, 1, &colorBuffer);
glTextureStorage2D(colorBuffer, 1, GL_SRGB8_ALPHA8, 1024, 1024);
}
// 2. Drawing code
{
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, FBO);
for(int cube_map_face = 0; cube_map_face < 6; ++cube_map_face)
{
glNamedFramebufferTextureLayer(FBO, GL_COLOR_ATTACHMENT0, colorBuffer, 0, cube_map_face);
glClearNamedFramebufferfv(FBO, GL_COLOR, 0, m_clearColor.data());
glClearNamedFramebufferfv(FBO, GL_DEPTH, 0, &m_clearDepth);
// Draw cub_map_face
}
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
}
Alternatively you can use a depth texture cube map with a geometry shader to dispatch primitives to each of the (relevant) faces.
// 1. Initialization code
{
// FBO (Frame Buffer Object)
GLuint FBO;
glCreateFramebuffers(1, &FBO);
// Texture for color buffer
{
GLuint colorBuffer;
glCreateTextures(GL_TEXTURE_CUBE_MAP, 1, &colorBuffer);
glTextureStorage2D(colorBuffer, 1, GL_SRGB8_ALPHA8, 1024, 1024);
glNamedFramebufferTexture(FBO, GL_COLOR_ATTACHMENT0, colorBuffer, 0);
}
// Texture for depth buffer.
{
GLuint depthBuffer;
glCreateTextures(GL_TEXTURE_CUBE_MAP, 1, &depthBuffer);
glTextureStorage2D(depthBuffer, 1, GL_DEPTH24_STENCIL8, 1024, 1024);
glNamedFramebufferTexture(FBO, GL_DEPTH_ATTACHMENT, depthBuffer, 0);
}
if ( glCheckNamedFramebufferStatus(m_identifier, GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE )
exit(1);
}
// 2. Drawing code
{
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, FBO);
glClearNamedFramebufferfv(FBO, GL_COLOR, 0, m_clearColor.data());
glClearNamedFramebufferfv(FBO, GL_DEPTH, 0, &m_clearDepth);
// Draw stuffs ... (one pass)
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
}
You'll need to attach a geometry shader that duplicates the primitive for each face. See here.
Upvotes: 4