SparrowRenderer/src/deferredpipeline.cpp
2016-07-11 20:06:37 +02:00

264 lines
8.8 KiB
C++

#include "sparrowrenderer.h"
#include "deferredpipeline.h"
#include "texture.h"
#include "scene.h"
#include "mesh.h"
#include "shader.h"
#include <glm/ext.hpp>
#include "shadersource.h"
#include "phongmaterial.h"
#include "camera.h"
#include <resource.h>
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; i<NB_BUFFERS; ++i)
getTexture(i)->bind();
}
void GBuffer::unbindTextures()
{
for(int i=0; i<NB_BUFFERS; ++i)
getTexture(i)->unbind();
}
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<GeometryNode*> 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<GeometryNode*>* 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<Light*>* 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);
}