#include "sparrowrenderer.h" #include "deferredpipeline.h" #include "texture.h" #include "scene.h" #include "mesh.h" #include "shader.h" #include #include "shadersource.h" #include "phongmaterial.h" #include "camera.h" #include RESOURCE_PACK(shaders) GBuffer::GBuffer(int width, int height) : FrameBuffer() { Texture* tex; // - Normal buffer tex = new Texture(GL_RGB, GL_RGB16F, width, height, GL_FLOAT, GL_TEXTURE_RECTANGLE); tex->setFiltering(GL_NEAREST); tex->setUnit(NORMAL); addTexture(tex, GL_COLOR_ATTACHMENT0); // - Color + objectId buffer tex = new Texture(GL_RGBA, GL_RGBA, width, height, GL_UNSIGNED_BYTE, GL_TEXTURE_RECTANGLE); tex->setFiltering(GL_NEAREST); tex->setUnit(DIFFUSE); addTexture(tex, GL_COLOR_ATTACHMENT1); // - Specular color + Specular exponent buffer tex = new Texture(GL_RGBA, GL_RGBA, width, height, GL_UNSIGNED_BYTE, GL_TEXTURE_RECTANGLE); tex->setFiltering(GL_NEAREST); tex->setUnit(SPECULAR); addTexture(tex, GL_COLOR_ATTACHMENT2); // - Position buffer tex = new Texture(GL_RGBA, GL_RGBA16F, width, height, GL_FLOAT, GL_TEXTURE_RECTANGLE); tex->setFiltering(GL_NEAREST); tex->setUnit(POSITION); addTexture(tex, GL_COLOR_ATTACHMENT3); // - depth buffer tex = new Texture(GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, width, height, GL_FLOAT, GL_TEXTURE_RECTANGLE); tex->setFiltering(GL_NEAREST); tex->setUnit(DEPTH); addTexture(tex, GL_DEPTH_ATTACHMENT); initColorAttachments(); } void GBuffer::bindTextures() { for(int i=0; ibind(); } void GBuffer::unbindTextures() { for(int i=0; iunbind(); } LightingBuffer::LightingBuffer(int width, int height) : FrameBuffer() { // colors are encoded in float to allow tonemapping Texture* tex = new Texture(GL_RGBA, GL_RGBA16F, width, height, GL_FLOAT, GL_TEXTURE_RECTANGLE); tex->setFiltering(GL_NEAREST); addTexture(tex, GL_COLOR_ATTACHMENT0); initColorAttachments(); } DeferredPipeline::DeferredPipeline() : m_camera(NULL), m_width(512), m_height(512), m_gBuffer(NULL), m_lightingBuffer(NULL), m_renderTarget(NULL) { Resource::ResourceMap shaderMap; Resource::getResourcePack_shaders(shaderMap); m_gBufferSource = new ShaderSource(); m_gBufferSource->setSource(shaderMap["shaders/gbuffer.vert.glsl"], ShaderSource::VERTEX); m_gBufferSource->setSource(shaderMap["shaders/gbuffer.frag.glsl"], ShaderSource::FRAGMENT); m_lightingSource = new ShaderSource(); m_lightingSource->setSource(shaderMap["shaders/lighting.vert.glsl"], ShaderSource::VERTEX); m_lightingSource->setSource(shaderMap["shaders/lighting.frag.glsl"], ShaderSource::FRAGMENT); m_mesh2DSource = new ShaderSource(); m_mesh2DSource->setSource(shaderMap["shaders/gui.vert.glsl"], ShaderSource::VERTEX); m_mesh2DSource->setSource(shaderMap["shaders/gui.frag.glsl"], ShaderSource::FRAGMENT); std::string vertSource = shaderMap["shaders/posteffects.vert.glsl"]; std::string fragSource = shaderMap["shaders/posteffects.frag.glsl"]; m_postEffectsShader = new Shader(vertSource, fragSource); } void DeferredPipeline::renderGL(Scene *scene) { if(m_renderTarget == NULL) return; // GEOMETRY PASS std::vector mesh2D; m_gBuffer->bindFBO(); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LESS); glDisable(GL_BLEND); glClearColor(0.0f, 0.0f, 0.0f, 1.f); glClearDepth(1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // loop on geometry unsigned int id = 2; for(SceneIterator* geometryIt = scene->getGeometry(); geometryIt->isValid(); geometryIt->next()) { GeometryNode* node = geometryIt->getItem(); unsigned int type = node->mesh->getFlags(); if(type & (1 << Mesh::MESH_2D)) { mesh2D.push_back(node); continue; } Shader *shader = m_mesh3DShaders[node->mesh->getFlags()]; if(shader == NULL) { fprintf(stderr, "no shader to render this 3D geometry, please call refreshScene to generate the shader\n"); continue; } shader->bind(); shader->bindUnsignedInteger(shader->getLocation("object_identifier"), id); if(node->mesh->instances_offsets.empty()) ++id; else id += node->mesh->instances_offsets.size(); glm::mat4 modelViewMatrix = m_camera->getViewMatrix() * node->modelMatrix; glm::mat4 normalMatrix = glm::transpose(glm::inverse(modelViewMatrix)); shader->bindMat4(shader->getLocation("projectionMatrix"), m_camera->getProjectionMatrix()); shader->bindMat4(shader->getLocation("modelViewMatrix"), modelViewMatrix); shader->bindMat3(shader->getLocation("normalMatrix"), glm::mat3(normalMatrix)); // draw geometry node->mesh->draw(shader); } // LIGHTING PASS m_lightingBuffer->bindFBO(); glDepthFunc(GL_LEQUAL); glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); m_gBuffer->bindTextures(); for(SceneIterator* lightIt = scene->getLights(); lightIt->isValid(); lightIt->next()) { Light* light = lightIt->getItem(); Shader *shader = m_lightShaders[light->getFlags()]; if(shader == NULL) { fprintf(stderr, "no shader to render this light, please call refreshScene to generate the shader\n"); continue; } shader->bind(); // bind GBuffer shader->bindInteger(shader->getLocation("normalBuffer"), GBuffer::NORMAL); shader->bindInteger(shader->getLocation("colorBuffer"), GBuffer::DIFFUSE); shader->bindInteger(shader->getLocation("specularBuffer"), GBuffer::SPECULAR); shader->bindInteger(shader->getLocation("positionBuffer"), GBuffer::POSITION); shader->bindInteger(shader->getLocation("depthBuffer"), GBuffer::DEPTH); // bind light light->bindAttributes(shader, m_camera); // compute fragments SparrowRenderer::drawQuad(); } m_gBuffer->unbindTextures(); // POST EFFECTS PASS m_renderTarget->bindFBO(); glDisable(GL_BLEND); m_lightingBuffer->getTexture(0)->bind(0); m_postEffectsShader->bind(); m_postEffectsShader->bindInteger(m_postEffectsShader->getLocation("lightBuffer"), 0); SparrowRenderer::drawQuad(); m_lightingBuffer->getTexture(0)->unbind(); // 2D GUI PASS glClear(GL_DEPTH_BUFFER_BIT); for(GeometryNode* node : mesh2D) { Shader *shader = m_mesh2DShaders[node->mesh->getFlags()]; if(shader == NULL) { fprintf(stderr, "no shader to render this 2D geometry, please call refreshScene to generate the shader\n"); continue; } shader->bind(); shader->bindMat4(shader->getLocation("orthoMatrix"), m_orthoMatrix); shader->bindMat4(shader->getLocation("transformMatrix"), node->modelMatrix); // draw geometry node->mesh->draw(shader); } } void DeferredPipeline::resizeGL(int w, int h) { // updating dimensions m_width = w; m_height = h; // rebuilding FrameBuffers if(m_gBuffer != NULL) { delete m_gBuffer; delete m_lightingBuffer; } m_gBuffer = new GBuffer(w, h); m_lightingBuffer = new LightingBuffer(w, h); m_orthoMatrix = glm::ortho(0.f, float(m_width), float(m_height), 0.f); } void DeferredPipeline::setSources(ShaderSource *gBufferSource, ShaderSource *lightingSource, ShaderSource *guiSource, Shader *postEffectsShader) { if(m_gBufferSource != NULL) delete m_gBufferSource; m_gBufferSource = gBufferSource; if(m_lightingSource != NULL) delete m_lightingSource; m_lightingSource = lightingSource; if(m_mesh2DSource != NULL) delete m_mesh2DSource; m_mesh2DSource = guiSource; if(m_postEffectsShader != NULL) delete m_postEffectsShader; m_postEffectsShader = postEffectsShader; } void DeferredPipeline::refreshScene(Scene *scene) { for(auto it : m_mesh3DShaders) delete it.second; m_mesh3DShaders.clear(); m_meshTypes.clear(); scene->getMeshTypes(m_meshTypes); for(unsigned int type : m_meshTypes) { if(type & (1 << Mesh::MESH_2D)) m_mesh2DShaders[type] = m_mesh2DSource->compile(type, 0); else m_mesh3DShaders[type] = m_gBufferSource->compile(type, 0); } for(auto it : m_lightShaders) delete it.second; m_lightShaders.clear(); m_lightTypes.clear(); scene->getLightTypes(m_lightTypes); for(unsigned int type : m_lightTypes) m_lightShaders[type] = m_lightingSource->compile(0, type); }