#include "GBuffer.hpp" #include #include "debug/Logger.hpp" using namespace advanced_pipeline; static debug::Logger logger("gl-gbuffer"); void GBuffer::createColorBuffer() { glGenTextures(1, &colorBuffer); glBindTexture(GL_TEXTURE_2D, colorBuffer); glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr ); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorBuffer, 0 ); } void GBuffer::createPositionsBuffer() { glGenTextures(1, &positionsBuffer); glBindTexture(GL_TEXTURE_2D, positionsBuffer); glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA16F, width, height, 0, GL_RGBA, GL_FLOAT, nullptr ); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, positionsBuffer, 0 ); } void GBuffer::createNormalsBuffer() { glGenTextures(1, &normalsBuffer); glBindTexture(GL_TEXTURE_2D, normalsBuffer); glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA16F, width, height, 0, GL_RGBA, GL_FLOAT, nullptr ); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, normalsBuffer, 0 ); } void GBuffer::createDepthBuffer() { glGenRenderbuffers(1, &depthBuffer); glBindRenderbuffer(GL_RENDERBUFFER, depthBuffer); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height); glFramebufferRenderbuffer( GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthBuffer ); } void GBuffer::createSSAOBuffer() { glGenTextures(1, &ssaoBuffer); glBindTexture(GL_TEXTURE_2D, ssaoBuffer); glTexImage2D( GL_TEXTURE_2D, 0, GL_R16F, width, height, 0, GL_RED, GL_FLOAT, nullptr ); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); } GBuffer::GBuffer(uint width, uint height) : width(width), height(height) { glGenFramebuffers(1, &fbo); glBindFramebuffer(GL_FRAMEBUFFER, fbo); createColorBuffer(); createPositionsBuffer(); createNormalsBuffer(); GLenum attachments[3] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2 }; glDrawBuffers(3, attachments); createDepthBuffer(); if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { logger.error() << "gbuffer is not complete!"; } glBindFramebuffer(GL_FRAMEBUFFER, 0); glGenFramebuffers(1, &ssaoFbo); glBindFramebuffer(GL_FRAMEBUFFER, ssaoFbo); createSSAOBuffer(); glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, ssaoBuffer, 0 ); GLenum ssaoAttachments[1] = {GL_COLOR_ATTACHMENT0}; glDrawBuffers(1, ssaoAttachments); if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { logger.error() << "SSAO framebuffer is not complete!"; } glBindFramebuffer(GL_FRAMEBUFFER, 0); } GBuffer::~GBuffer() { glDeleteTextures(1, &colorBuffer); glDeleteTextures(1, &positionsBuffer); glDeleteTextures(1, &normalsBuffer); glDeleteTextures(1, &ssaoBuffer); glDeleteRenderbuffers(1, &depthBuffer); glDeleteFramebuffers(1, &fbo); glDeleteFramebuffers(1, &ssaoFbo); } void GBuffer::bind() { glBindFramebuffer(GL_FRAMEBUFFER, fbo); glClear(GL_COLOR_BUFFER_BIT); } void GBuffer::bindSSAO() const { glBindFramebuffer(GL_FRAMEBUFFER, ssaoFbo); } void GBuffer::unbind() { glBindFramebuffer(GL_FRAMEBUFFER, 0); } void GBuffer::bindBuffers() const { glActiveTexture(GL_TEXTURE0 + TARGET_NORMALS); glBindTexture(GL_TEXTURE_2D, normalsBuffer); glActiveTexture(GL_TEXTURE0 + TARGET_POSITIONS); glBindTexture(GL_TEXTURE_2D, positionsBuffer); glActiveTexture(GL_TEXTURE0 + TARGET_COLOR); glBindTexture(GL_TEXTURE_2D, colorBuffer); if (TARGET_COLOR != 0) glActiveTexture(GL_TEXTURE0); } void GBuffer::bindSSAOBuffer() const { glBindTexture(GL_TEXTURE_2D, ssaoBuffer); } void GBuffer::bindDepthBuffer() { glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL_DEPTH_BUFFER_BIT, GL_NEAREST); } void GBuffer::resize(uint width, uint height) { if (this->width == width && this->height == height) { return; } this->width = width; this->height = height; glBindFramebuffer(GL_FRAMEBUFFER, fbo); glBindRenderbuffer(GL_RENDERBUFFER, depthBuffer); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height); glBindRenderbuffer(GL_RENDERBUFFER, 0); glBindTexture(GL_TEXTURE_2D, colorBuffer); glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr ); glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorBuffer, 0 ); glBindTexture(GL_TEXTURE_2D, positionsBuffer); glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB16F, width, height, 0, GL_RGB, GL_FLOAT, nullptr ); glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, positionsBuffer, 0 ); glBindTexture(GL_TEXTURE_2D, normalsBuffer); glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB16F, width, height, 0, GL_RGB, GL_FLOAT, nullptr ); glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, normalsBuffer, 0 ); glBindTexture(GL_TEXTURE_2D, 0); glBindFramebuffer(GL_FRAMEBUFFER, 0); glBindFramebuffer(GL_FRAMEBUFFER, ssaoFbo); glBindTexture(GL_TEXTURE_2D, ssaoBuffer); glTexImage2D( GL_TEXTURE_2D, 0, GL_R16F, width, height, 0, GL_RED, GL_FLOAT, nullptr ); glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, ssaoBuffer, 0 ); glBindTexture(GL_TEXTURE_2D, 0); glBindFramebuffer(GL_FRAMEBUFFER, 0); } std::unique_ptr GBuffer::toImage() const { auto data = std::make_unique(width * height * 3); glBindTexture(GL_TEXTURE_2D, colorBuffer); glGetTexImage(GL_TEXTURE_2D, 0, GL_RGB, GL_UNSIGNED_BYTE, data.get()); glBindTexture(GL_TEXTURE_2D, 0); return std::make_unique( ImageFormat::rgb888, width, height, std::move(data) ); } uint GBuffer::getWidth() const { return width; } uint GBuffer::getHeight() const { return height; }