const int OffscreenCount = 5; const bool Optimize = true; struct Framebuffers { GLuint Onscreen; GLuint Scene; GLuint OffscreenLeft[OffscreenCount]; GLuint OffscreenRight[OffscreenCount]; };
struct Renderbuffers { GLuint Onscreen; GLuint OffscreenLeft[OffscreenCount]; GLuint OffscreenRight[OffscreenCount]; GLuint SceneColor; GLuint SceneDepth; };
struct Textures { GLuint TombWindow; GLuint Sun; GLuint Scene; GLuint OffscreenLeft[OffscreenCount]; GLuint OffscreenRight[OffscreenCount]; };
...
GLuint RenderingEngine::CreateFboTexture(int w, int h) const { GLuint texture; glGenTextures(1, &texture); glBindTexture(GL_TEXTURE_2D, texture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0); return texture; }
void RenderingEngine::Initialize() { // Load the textures: ...
// Create some geometry: m_kleinBottle = CreateDrawable(KleinBottle(0.2), VertexFlagsNormals); m_quad = CreateDrawable(Quad(2, 2), VertexFlagsTexCoords); // Extract width and height from the color buffer: glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &m_size.x); glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &m_size.y); // Create the onscreen FBO: glGenFramebuffers(1, &m_framebuffers.Onscreen); glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffers.Onscreen); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_renderbuffers.Onscreen); glBindRenderbuffer(GL_RENDERBUFFER, m_renderbuffers.Onscreen);
// Create the depth buffer for the full-size offscreen FBO: glGenRenderbuffers(1, &m_renderbuffers.SceneDepth); glBindRenderbuffer(GL_RENDERBUFFER, m_renderbuffers.SceneDepth); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, m_size.x, m_size.y); glGenRenderbuffers(1, &m_renderbuffers.SceneColor); glBindRenderbuffer(GL_RENDERBUFFER, m_renderbuffers.SceneColor); glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8_OES, m_size.x, m_size.y); glGenFramebuffers(1, &m_framebuffers.Scene); glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffers.Scene); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_renderbuffers.SceneColor); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_renderbuffers.SceneDepth); m_textures.Scene = CreateFboTexture(m_size.x, m_size.y); // Create FBOs for the half, quarter, and eighth sizes: int w = m_size.x, h = m_size.y; for (int i = 0; i < OffscreenCount; ++i, w >>= 1, h >>= 1) { glGenRenderbuffers(1, &m_renderbuffers.OffscreenLeft[i]); glBindRenderbuffer(GL_RENDERBUFFER, m_renderbuffers.OffscreenLeft[i]); glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8_OES, w, h); glGenFramebuffers(1, &m_framebuffers.OffscreenLeft[i]); glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffers.OffscreenLeft[i]); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_renderbuffers.OffscreenLeft[i]); m_textures.OffscreenLeft[i] = CreateFboTexture(w, h);
glGenRenderbuffers(1, &m_renderbuffers.OffscreenRight[i]); glBindRenderbuffer(GL_RENDERBUFFER, m_renderbuffers.OffscreenRight[i]); glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8_OES, w, h); glGenFramebuffers(1, &m_framebuffers.OffscreenRight[i]); glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffers.OffscreenRight[i]); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_renderbuffers.OffscreenRight[i]); m_textures.OffscreenRight[i] = CreateFboTexture(w, h); } ... }
void RenderingEngine::Render(float theta) const { glViewport(0, 0, m_size.x, m_size.y); glEnable(GL_DEPTH_TEST);
// Set the render target to the full-size offscreen buffer: glBindTexture(GL_TEXTURE_2D, m_textures.TombWindow); glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffers.Scene); glBindRenderbuffer(GL_RENDERBUFFER, m_renderbuffers.SceneColor);
// Blit the background texture: glUseProgram(m_blitting.Program); glUniform1f(m_blitting.Uniforms.Threshold, 0); glDepthFunc(GL_ALWAYS); RenderDrawable(m_quad, m_blitting);
// Draw the sun: ...
// Set the light position: glUseProgram(m_lighting.Program); vec4 lightPosition(0.25, 0.25, 1, 0); glUniform3fv(m_lighting.Uniforms.LightPosition, 1, lightPosition.Pointer());
// Set the model-view transform: const float distance = 10; const vec3 target(0, -0.15, 0); const vec3 up(0, 1, 0); const vec3 eye = vec3(0, 0, distance); const mat4 view = mat4::LookAt(eye, target, up); const mat4 model = mat4::RotateY(theta * 180.0f / 3.14f); const mat4 modelview = model * view; glUniformMatrix4fv(m_lighting.Uniforms.Modelview, 1, 0, modelview.Pointer());
// Set the normal matrix: mat3 normalMatrix = modelview.ToMat3(); glUniformMatrix3fv(m_lighting.Uniforms.NormalMatrix, 1, 0, normalMatrix.Pointer());
// Render the Klein bottle: glDepthFunc(GL_LESS); glEnableVertexAttribArray(m_lighting.Attributes.Normal); RenderDrawable(m_kleinBottle, m_lighting); // Set up the high-pass filter: glUseProgram(m_highPass.Program); glUniform1f(m_highPass.Uniforms.Threshold, 0.85); glDisable(GL_DEPTH_TEST);
// Downsample the rendered scene: int w = m_size.x, h = m_size.y; for (int i = 0; i < OffscreenCount; ++i, w >>= 1, h >>= 1) { glViewport(0, 0, w, h); glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffers.OffscreenLeft[i]); glBindRenderbuffer(GL_RENDERBUFFER, m_renderbuffers.OffscreenLeft[i]); glBindTexture(GL_TEXTURE_2D, i ? m_textures.OffscreenLeft[i - 1] : m_textures.Scene); RenderDrawable(m_quad, m_blitting); glUseProgram(m_blitting.Program); } // Set up for Gaussian blur: float kernel[3] = { 5.0f / 16.0f, 6 / 16.0f, 5 / 16.0f }; glUseProgram(m_gaussian.Program); glUniform1fv(m_gaussian.Uniforms.Coefficients, 3, kernel);
// Perform the horizontal blurring pass: w = m_size.x; h = m_size.y; for (int i = 0; i < OffscreenCount; ++i, w >>= 1, h >>= 1) { if (Optimize && i < 2) continue; float offset = 1.2f / (float) w; glUniform2f(m_gaussian.Uniforms.Offset, offset, 0); glViewport(0, 0, w, h); glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffers.OffscreenRight[i]); glBindRenderbuffer(GL_RENDERBUFFER, m_renderbuffers.OffscreenRight[i]); glBindTexture(GL_TEXTURE_2D, m_textures.OffscreenLeft[i]); RenderDrawable(m_quad, m_gaussian); }
// Perform the vertical blurring pass: w = m_size.x; h = m_size.y; for (int i = 0; i < OffscreenCount; ++i, w >>= 1, h >>= 1) { if (Optimize && i < 2) continue; float offset = 1.2f / (float) h; glUniform2f(m_gaussian.Uniforms.Offset, 0, offset); glViewport(0, 0, w, h); glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffers.OffscreenLeft[i]); glBindRenderbuffer(GL_RENDERBUFFER, m_renderbuffers.OffscreenLeft[i]); glBindTexture(GL_TEXTURE_2D, m_textures.OffscreenRight[i]); RenderDrawable(m_quad, m_gaussian); }
// Blit the full-color buffer onto the screen: glUseProgram(m_blitting.Program); glViewport(0, 0, m_size.x, m_size.y); glDisable(GL_BLEND); glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffers.Onscreen); glBindRenderbuffer(GL_RENDERBUFFER, m_renderbuffers.Onscreen); glBindTexture(GL_TEXTURE_2D, m_textures.Scene); RenderDrawable(m_quad, m_blitting);
// Accumulate the bloom textures onto the screen: glBlendFunc(GL_ONE, GL_ONE); glEnable(GL_BLEND); for (int i = 1; i < OffscreenCount; ++i) { glBindTexture(GL_TEXTURE_2D, m_textures.OffscreenLeft[i]); RenderDrawable(m_quad, m_blitting); } glDisable(GL_BLEND); }
|