I would like to render omnidirectional shadow maps in one pass using layered rendering. Unfortunately, my implementation worked only for the POSITIVE_X face of the cube map, the other face were not rendered to.
To debug, I wrote the following minimal example for rendering to a cube map. I tested it on an Intel graphics card and it worked. However, on a NVIDIA (GTX 670) it renders only to one face (as mentioned above). Did anyone experience something similar, or did I do something terribly wrong in my implementation? Any help with this would be greatly appreciated:)
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include "../ext/opengl/program.h"
#include "../ext/opengl/texture.h"
#define TO_STRING(X) #X
static char* g_vertex_shader =
"#version 410
"
TO_STRING(
in vec3 position;
void main()
{
gl_Position = vec4(position, 1.0);
}
);
static char* g_geometry_shader =
"#version 410
"
TO_STRING(
layout(triangles, invocations = 1) in;
layout(triangle_strip, max_vertices = 18) out;
void main()
{
for (int i = 0; i < 6; i++) {
for (int j = 0; j < 3; j++) {
gl_Position = 1.0 / (float(i) + 1.0) * gl_in[j].gl_Position;
gl_Position.w = 1.0;
gl_Layer = i;
EmitVertex();
}
EndPrimitive();
}
}
);
static char* g_fragment_shader =
"#version 410
"
TO_STRING(
out vec4 fragment_color;
void main()
{
fragment_color = vec4(1.0, 0.0, 0.0, 1.0);
}
);
static GLuint g_program = 0;
static GLuint g_vao = 0;
static GLuint g_vbo = 0;
static GLuint g_fbo = 0;
static GLuint g_cube_map = 0;
GLFWwindow* g_window = NULL;
static void initializeWindow()
{
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
g_window = glfwCreateWindow(512, 512, "test", NULL, NULL);
glfwMakeContextCurrent(g_window);
glewExperimental = GL_TRUE;
glewInit();
glGetError();
puts(glGetString(GL_VERSION));
}
static void initializeProgram()
{
g_program = glCreateProgram();
gl_attach_shader_with_source(g_program, GL_VERTEX_SHADER, g_vertex_shader);
gl_attach_shader_with_source(g_program, GL_FRAGMENT_SHADER, g_fragment_shader);
gl_attach_shader_with_source(g_program, GL_GEOMETRY_SHADER, g_geometry_shader);
glBindAttribLocation(g_program, 0, "position");
glBindFragDataLocation(g_program, 0, "fragment_color");
gl_link_program(g_program);
assert(glGetError() == GL_NO_ERROR);
}
static void initializeGeometry()
{
static const float tri[] = {
0.0, 0.0, 1.0,
1.0, 0.0, 1.0,
1.0, 1.0, 1.0,
};
glGenVertexArrays(1, &g_vao);
glBindVertexArray(g_vao);
glGenBuffers(1, &g_vbo);
glBindBuffer(GL_ARRAY_BUFFER, g_vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(tri), tri, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
assert(GL_NO_ERROR == glGetError());
}
static void initializeLayeredFBO()
{
GLenum drawbuffers[] = { GL_COLOR_ATTACHMENT0 };
glGenFramebuffers(1, &g_fbo);
glBindFramebuffer(GL_FRAMEBUFFER, g_fbo);
glGenTextures(1, &g_cube_map);
glBindTexture(GL_TEXTURE_CUBE_MAP, g_cube_map);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
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_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
for (int i = 0; i < 6; i++) {
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGBA32F,
512, 512, 0, GL_RGBA, GL_FLOAT, NULL);
}
assert(GL_NO_ERROR == glGetError());
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, g_cube_map, 0);
glDrawBuffers(1, drawbuffers);
assert(GL_FRAMEBUFFER_COMPLETE == glCheckFramebufferStatus(GL_FRAMEBUFFER));
assert(GL_NO_ERROR == glGetError());
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
static void render()
{
glBindFramebuffer(GL_FRAMEBUFFER, g_fbo);
glViewport(0, 0, 512, 512);
glDisable(GL_DEPTH_TEST);
glClear(GL_COLOR_BUFFER_BIT);
glBindVertexArray(g_vao);
glUseProgram(g_program);
glDrawArrays(GL_TRIANGLES, 0, 3);
gl_save_cube_map_to_ppm(g_cube_map, GL_TEXTURE_CUBE_MAP_POSITIVE_X, "test-pos-x.ppm");
gl_save_cube_map_to_ppm(g_cube_map, GL_TEXTURE_CUBE_MAP_NEGATIVE_X, "test-neg-x.ppm");
gl_save_cube_map_to_ppm(g_cube_map, GL_TEXTURE_CUBE_MAP_POSITIVE_Y, "test-pos-y.ppm");
gl_save_cube_map_to_ppm(g_cube_map, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, "test-neg-y.ppm");
gl_save_cube_map_to_ppm(g_cube_map, GL_TEXTURE_CUBE_MAP_POSITIVE_Z, "test-pos-z.ppm");
gl_save_cube_map_to_ppm(g_cube_map, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, "test-neg-z.ppm");
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
static void pause()
{
system("pause");
}
int main(int argc, char* argv)
{
atexit(pause);
initializeWindow();
initializeProgram();
initializeGeometry();
initializeLayeredFBO();
glClearColor(1.0, 1.0, 1.0, 1.0);
render();
return 0;
}