added deferred pipeline

This commit is contained in:
Anselme FRANÇOIS 2016-06-24 18:33:53 +02:00
parent 66784724d8
commit 01973cea0b
8 changed files with 584 additions and 0 deletions

83
shaders/gbuffer.frag.glsl Normal file
View File

@ -0,0 +1,83 @@
// - Normal buffer
layout (location = 0) out vec3 outNormal;
// - Color + objectId buffer
layout (location = 1) out vec4 outColor;
// - Specular color + Specular exponent buffer
layout (location = 2) out vec4 outSpecular;
// - Position in view space
layout (location = 3) out vec4 outPosition;
uniform float materialNs;
// variables used for picking
uniform unsigned int object_identifier;
#ifdef INSTANCED
flat in int instanceId;
#endif
#ifdef ALPHA_MASK
uniform sampler2D alphaMask;
#endif
#ifdef DIFFUSE_TEXTURE
uniform sampler2D diffuseTexture;
#else
uniform vec3 materialKd;
#endif
#ifdef SPECULAR_TEXTURE
uniform sampler2D specularTexture;
#else
uniform vec3 materialKs;
#endif
in vec4 posInView;
#ifdef NORMAL_MAP
uniform sampler2D normalMap;
in vec3 varTangent;
in vec3 varBinormal;
#endif
in vec3 varNormal;
in vec2 varTexCoord;
void main()
{
#ifdef ALPHA_MASK
if(texture(alphaMask, varTexCoord).r < 0.5)
discard;
#endif
#ifdef NORMAL_MAP
vec3 normalTexel = normalize(texture(normalMap, varTexCoord).xyz -0.5);
vec3 tangent = normalize(varTangent);
vec3 binormal = normalize(varBinormal);
vec3 normal = normalize(varNormal);
mat3 tangentSpace = mat3(vec3(tangent.x, binormal.x, normal.x),
vec3(tangent.y, binormal.y, normal.y),
vec3(tangent.z, binormal.z, normal.z));
outNormal = normalize(normalTexel * tangentSpace);
#else
outNormal = normalize(varNormal);
#endif
#ifdef DIFFUSE_TEXTURE
outColor.rgb = texture(diffuseTexture, varTexCoord).rgb;
#else
outColor.rgb = materialKd;
#endif
outColor.a = float(object_identifier)/255;
#ifdef SPECULAR_TEXTURE
outSpecular.rgb = texture(specularTexture, varTexCoord).rgb;
#else
outSpecular.rgb = materialKs;
#endif
outSpecular.w = float(materialNs)/255;
outPosition = posInView;
}

49
shaders/gbuffer.vert.glsl Normal file
View File

@ -0,0 +1,49 @@
uniform mat4 projectionMatrix;
uniform mat4 modelViewMatrix;
uniform mat3 normalMatrix;
out vec4 posInView;
#ifdef NORMAL_MAP
out vec3 varTangent;
out vec3 varBinormal;
#endif
out vec3 varNormal;
out vec2 varTexCoord;
layout(location = 0)in vec3 inPosition;
layout(location = 2)in vec2 inTexCoord;
layout(location = 1)in vec3 inNormal;
#ifdef NORMAL_MAP
layout(location = 3)in vec3 inTangent;
layout(location = 4)in vec3 inBinormal;
#endif
#ifdef INSTANCED
layout(location = 5)in vec3 inInstanceOffset;
flat out int instanceId;
#endif
void main(void) {
// computing normals
#ifdef NORMAL_MAP
varTangent = normalize(normalMatrix*inTangent);
varBinormal = normalize(normalMatrix*inBinormal);
#endif
varNormal = normalize(normalMatrix*inNormal);
//computing UVs
varTexCoord = inTexCoord.xy;
// computing positions
#ifdef INSTANCED
instanceId = gl_InstanceID;
vec4 pos = vec4(inPosition + inInstanceOffset, 1.0);
#else
vec4 pos = vec4(inPosition, 1.0);
#endif
posInView = modelViewMatrix*pos;
gl_Position = projectionMatrix * posInView;
}

131
shaders/lighting.frag.glsl Normal file
View File

@ -0,0 +1,131 @@
// G-BUFFER
// - Normal buffer
uniform sampler2DRect normalBuffer;
// - Color + objectId buffer
uniform sampler2DRect colorBuffer;
// - Specular color + Specular exponent buffer
uniform sampler2DRect specularBuffer;
// - Position in view space
uniform sampler2DRect positionBuffer;
// - depth buffer
uniform sampler2DRect depthBuffer;
// LIGHT ATTRIBUTES
uniform vec3 lightColor;
#ifdef SHADOWMAP
uniform sampler2DShadow shadowMap;
uniform mat4 viewToLightMatrix;
#endif
#if defined POINT_LIGHT
uniform vec3 pointLight;
uniform float attenuation;
#elif defined DIRECTIONNAL_LIGHT
uniform vec3 dirLight;
#elif defined SPOT_LIGHT
uniform vec3 pointLight;
uniform float attenuation;
uniform vec3 dirLight;
uniform float cutoff;
#endif
// FRAGMENT POSITIONNING
in vec2 screenPos;
uniform mat4 inverseProjectionMatrix;
// OUTPUT LIGHT
layout(location = 0)out vec4 outColor;
// FUNCTIONS
const float CELL_SHADING = 0.3333;
vec3 phongLighting(in vec3 kd, in vec3 ks, in float ns, in vec3 color, in vec3 normal, in vec3 lightDir, in vec3 halfVec, in vec3 viewDir){
float diffuseComponent = max(dot(normal, lightDir), 0);
float specularComponent = max(dot(halfVec, normal), 0);
return color*diffuseComponent*(kd+ks*pow(specularComponent, ns));
}
vec3 CookTorranceSpecularHighlight(in vec3 ks, in float ns, in vec3 normal, in vec3 lightDir, in vec3 halfVec, in vec3 viewDir){
float HN = dot(halfVec, normal);
float VN = dot(viewDir, normal);
float VH = dot(viewDir, halfVec);
float LN = dot(lightDir, normal);
HN = max(HN, 0);
VN = max(VN, 0);
LN = max(LN, 0);
// GGX normal distribution :
float roughness = 2/(ns+2);
float denom = mix(1, roughness, HN*HN);
float D = roughness/(3.1416*denom*denom);
//D = pow(HN, ns);
// Fresnel term with Schlick's approximation
vec3 F = mix(ks, vec3(1), pow(1 - VH, 5));
VH = max(VH, 0);
// Geometric attenuation
float G = min(1, min(2*HN*VN/VH, 2*HN*LN/VH));
return D * F * G;
}
vec3 testLighting(in vec3 kd, in vec3 ks, in float ns, in vec3 color, in vec3 normal, in vec3 lightDir, in vec3 halfVec, in vec3 viewDir){
float diffuseComponent = max(dot(normal, lightDir), 0);
return color*diffuseComponent*(kd+ks*CookTorranceSpecularHighlight(ks, ns, normal, lightDir, halfVec, viewDir));
}
float computeShadow(sampler2D shadowmap, vec3 shadow){
float lightFragDepth = texture(shadowmap, shadow.xy).r;
return lightFragDepth < shadow.z ? 0 : 1;
}
// MAIN PROGRAM
void main(void) {
ivec2 texCoord = ivec2(gl_FragCoord.xy);
vec3 normal = texelFetch(normalBuffer, texCoord).xyz;
vec4 diffuseTexel = texelFetch(colorBuffer, texCoord);
vec3 diffuse = diffuseTexel.rgb;
vec4 specularTexel = texelFetch(specularBuffer, texCoord);
vec3 specular = specularTexel.rgb;
float shininess = specularTexel.w*255;
vec4 fragPos = texelFetch(positionBuffer, texCoord);
float depth = texelFetch(depthBuffer, texCoord).r;
#ifdef SHADOWMAP
vec4 fragInLightSpace = viewToLightMatrix * fragPos;
fragInLightSpace.z = fragInLightSpace.z - 0.002;
float shadow = texture(shadowMap, fragInLightSpace.xyz/fragInLightSpace.w);
#else
float shadow = 1;
#endif
float att = 1;
#ifdef POINT_LIGHT
vec3 dirLight = pointLight - fragPos.xyz;
float dist = length(dirLight);
if(dist > attenuation)
att = 0;
att = 1 - dist/attenuation;
dirLight = normalize(dirLight);
#endif
#ifdef AMBIENT_LIGHT
outColor = vec4(diffuse*lightColor, 1);
#else
vec3 viewDir = normalize(-fragPos.xyz);
vec3 halfVec = normalize(viewDir + dirLight);
vec3 light = testLighting(diffuse, specular, shininess, lightColor, normal, dirLight, halfVec, viewDir);
outColor = vec4(mix(vec3(0.0), light*shadow, att*att), 1);
#endif
}

View File

@ -0,0 +1,8 @@
layout(location = 0)in vec2 inPosition;
out vec2 screenPos;
void main(void) {
gl_Position = vec4(inPosition, 0.0, 1.0);
screenPos = inPosition;
}

View File

@ -0,0 +1,17 @@
#version 330 core
// LIGHT BUFFER
uniform sampler2DRect lightBuffer;
// OUTPUT LIGHT
layout(location = 0)out vec4 outColor;
// MAIN PROGRAM
void main(void) {
ivec2 texCoord = ivec2(gl_FragCoord.xy);
vec3 color = texelFetch(lightBuffer, texCoord).xyz;
outColor = vec4(color, 1.0);
}

View File

@ -0,0 +1,7 @@
#version 330 core
layout(location = 0)in vec2 inPosition;
void main(void) {
gl_Position = vec4(inPosition, 0.0, 1.0);
}

228
src/deferredpipeline.cpp Normal file
View File

@ -0,0 +1,228 @@
#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);
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
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();
Shader *shader = m_meshShaders[node->mesh->getFlags()];
if(shader == NULL)
{
fprintf(stderr, "no shader to render this geometry, please use 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 use 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);
// TODO : send uniforms
SparrowRenderer::drawQuad();
m_lightingBuffer->getTexture(0)->unbind();
}
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);
}
void setSources(ShaderSource *gBufferSource, ShaderSource *lightingSource, Shader *postEffectsShader)
{
if(m_gBufferSource != NULL)
delete m_gBufferSource;
m_gBufferSource = gBufferSource;
if(m_lightingSource != NULL)
delete m_lightingSource;
m_lightingSource = lightingSource;
if(m_postEffectsShader != NULL)
delete m_postEffectsShader;
m_postEffectsShader = postEffectsShader;
}
void DeferredPipeline::refreshScene(Scene *scene)
{
for(auto it : m_meshShaders)
delete it.second;
m_meshShaders.clear();
m_meshTypes.clear();
scene->getMeshTypes(m_meshTypes);
for(unsigned int type : m_meshTypes)
m_meshShaders[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);
}

61
src/deferredpipeline.h Normal file
View File

@ -0,0 +1,61 @@
#ifndef DEFERREDPIPELINE_H
#define DEFERREDPIPELINE_H
#include <pipeline.h>
#include <framebuffer.h>
#include <unordered_map>
class Shader;
class Camera;
class GBuffer : public FrameBuffer
{
public:
enum Buffers { NORMAL, DIFFUSE, SPECULAR, POSITION, DEPTH, NB_BUFFERS };
GBuffer(int width, int height);
void bindTextures();
void unbindTextures();
};
class LightingBuffer : public FrameBuffer
{
public:
LightingBuffer(int width, int height);
};
class DeferredPipeline : public Pipeline
{
Camera *m_camera;
int m_width;
int m_height;
// shaders
std::vector<unsigned int> m_meshTypes;
std::vector<unsigned int> m_lightTypes;
std::unordered_map<unsigned int, Shader*> m_meshShaders;
std::unordered_map<unsigned int, Shader*> m_lightShaders;
ShaderSource *m_gBufferSource;
ShaderSource *m_lightingSource;
Shader *m_postEffectsShader;
// framebuffers
GBuffer *m_gBuffer;
LightingBuffer *m_lightingBuffer;
const FrameBuffer *m_renderTarget;
public:
DeferredPipeline();
void setCamera(Camera *camera) { m_camera = camera; }
void setSources(ShaderSource *gBufferSource, ShaderSource *lightingSource, Shader *postEffectsShader);
void setRenderTarget(const FrameBuffer *fbo) { m_renderTarget = fbo; }
void refreshScene(Scene *scene);
virtual void renderGL(Scene *scene);
virtual void resizeGL(int w, int h);
};
#endif // DEFERREDPIPELINE_H