Commit 7ef3739d authored by Christopher Tenter's avatar Christopher Tenter

add deferred shading plugin

git-svn-id: http://www.openflipper.org/svnrepo/OpenFlipper/branches/Free-Staging@18532 383ad7c9-94d9-4d36-a494-682f7c89f535
parent d6f0e82d
include (plugin)
openflipper_plugin ( INSTALLDATA Shaders )
/*===========================================================================*\
* *
* OpenFlipper *
* Copyright (C) 2001-2014 by Computer Graphics Group, RWTH Aachen *
* www.openflipper.org *
* *
*--------------------------------------------------------------------------- *
* This file is part of OpenFlipper. *
* *
* OpenFlipper is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation, either version 3 of *
* the License, or (at your option) any later version with the *
* following exceptions: *
* *
* If other files instantiate templates or use macros *
* or inline functions from this file, or you compile this file and *
* link it with other files to produce an executable, this file does *
* not by itself cause the resulting executable to be covered by the *
* GNU Lesser General Public License. This exception does not however *
* invalidate any other reasons why the executable file might be *
* covered by the GNU Lesser General Public License. *
* *
* OpenFlipper is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU LesserGeneral Public *
* License along with OpenFlipper. If not, *
* see <http://www.gnu.org/licenses/>. *
* *
\*===========================================================================*/
/*===========================================================================*\
* *
* $Revision: 18127 $ *
* $LastChangedBy: moebius $ *
* $Date: 2014-02-05 10:12:54 +0100 (Wed, 05 Feb 2014) $ *
* *
\*===========================================================================*/
#pragma once
#include <QObject>
#include <OpenFlipper/BasePlugin/BaseInterface.hh>
#include <OpenFlipper/BasePlugin/RenderInterface.hh>
#include <ACG/GL/IRenderer.hh>
#include <ACG/GL/FBO.hh>
#include <ACG/GL/globjects.hh>
#include <ACG/GL/AntiAliasing.hh>
#include <vector>
class DeferredShading : public QObject, BaseInterface, RenderInterface, ACG::IRenderer
{
Q_OBJECT
Q_INTERFACES(BaseInterface)
Q_INTERFACES(RenderInterface)
#if QT_VERSION >= 0x050000
Q_PLUGIN_METADATA(IID "org.OpenFlipper.Plugins.Plugin-Deferred-Shading")
#endif
public:
DeferredShading();
~DeferredShading();
QString name() { return (QString("Deferred Shading Renderer")); };
QString description( ) { return (QString(tr("Render scene with deferred shading for each light"))); };
public slots:
QString version() { return QString("1.0"); };
QString renderObjectsInfo(bool _outputShaderInfo);
QAction* optionsAction();
private slots:
//BaseInterface
void initializePlugin();
void exit(){}
// RenderInterface
void render(ACG::GLState* _glState, Viewer::ViewerProperties& _properties);
QString rendererName() {return QString("Deferred_Shading");}
void supportedDrawModes(ACG::SceneGraph::DrawModes::DrawMode& _mode) {_mode = ACG::SceneGraph::DrawModes::DEFAULT;}
void reloadShaders();
QString checkOpenGL();
void slotMSAASelection( QAction * );
private:
void loadShader();
/// emissive color pass
GLSL::Program* progEmissive_;
/// emissive color pass with multisampling
GLSL::Program* progEmissiveMS_;
/// background color pass
GLSL::Program* progBackground_;
/// directional lighting pass
GLSL::Program* progDirectional_;
/// directional lighting pass with multisampling
GLSL::Program* progDirectionalMS_;
/// point lighting pass
GLSL::Program* progPoint_;
/// point lighting pass with multisampling
GLSL::Program* progPointMS_;
/// spot lighting pass
GLSL::Program* progSpot_;
/// spot lighting pass with multisampling
GLSL::Program* progSpotMS_;
/// Collection of fbos for each viewport
struct ViewerResources
{
ViewerResources() : scene_(0) {}
~ViewerResources() {delete scene_;}
void resize( int _newWidth, int _newHeight, int& _numSamples );
ACG::FBO* scene_;
};
ACG::TextureBuffer filterWeightsBuffer_;
int numSamples_;
ACG::TextureBuffer materialBuffer_;
std::vector<ACG::Vec3f> materialBufferData_;
/**
* Stores fbo resources for each viewport.
* Mapping: viewerID -> ViewerResources
*/
std::map<int, ViewerResources> viewerRes_;
};
// G-buffer access functions
// compute view space position of a pixel
vec3 ComputePosVS(in float zPosVS, in vec2 vTexCoord, in float mProj_00, in float mProj_11)
{
/*
Reconstructing the position of a pixel based on its z-coord in viewspace
1. Compute the clip-space position of the pixel:
- extent texcoord from range [0,1] to [-1,1]
2. Undo perspective projection of xy-coordinate:
perspective projection matrix: http://www.opengl.org/sdk/docs/man2/xhtml/gluPerspective.xml
f/aspect 0 0 0
0 f 0 0
0 0 * *
0 0 -1 0
(where f = cotangent(fovy/2), aspect = width/height)
projection of viewspace position:
xPS = f/aspect * xVS
yPS = f * yVS
zPS = ..
wPS = -zVS
post perspective homogenization in clip-space:
xCS = xPS / wPS = xPS / -zVS
yCS = yPS / wPS = yPS / -zVS
Revert perspective projection to get xVS and yVS:
xVS = xCS * (-zVS) / (f/aspect)
yVS = yCS * (-zVS) / f
*/
// compute xy-position in clip space (position on near clipping plane)
vec2 vPosCS = vTexCoord * 2 - vec2(1,1);
// revert perspective projection
vec3 vPos;
vPos.xy = (vPosCS * (-zPosVS)) / vec2(mProj_00, mProj_11);
vPos.z = zPosVS;
return vPos;
}
// read position in view space
vec3 ReadPositionVS(in sampler2D samplerDepth, in vec2 vTexCoord, in float mProj_00, in float mProj_11)
{
float depthVS = texture2D(samplerDepth, vTexCoord).x;
return ComputePosVS(depthVS, vTexCoord, mProj_00, mProj_11);
}
// read normal in view space
vec3 ReadNormalVS(in sampler2D samplerNormal, in vec2 vTexCoord)
{
vec3 n = texture2D(samplerNormal, vTexCoord).xyz;
n = n * 2 - vec3(1,1,1);
return normalize(n);
}
vec4 WritePositionVS(in vec4 vPosVS, in float materialID)
{
// return vPosVS.zzzz;
return vec4(vPosVS.z, materialID, 0, 1);
}
vec3 WriteNormalVS(in vec3 vNormalVS)
{
return vNormalVS * 0.5 + vec3(0.5, 0.5, 0.5);
}
\ No newline at end of file
/*
Access of depth buffer values:
Convert between projected and linear depth values.
P22 and P23 are the entries in the projection matrix
see http://www.opengl.org/sdk/docs/man2/xhtml/gluPerspective.xml
*/
// convert depth buffer value to viewspace z-coord
float ProjectedToViewspaceDepth(in float depth, in float P22, in float P23)
{
// convert to [-1,1]
float d = depth * 2.0 - 1.0;
return -P23 / (d + P22);
}
// convert view space z-coordinate to the depth value written into the depth buffer
float ViewspaceToProjectedDepth(in float zVS, in float P22, in float P23)
{
// convert to non-linear depth in [-1,1]
float d = -(P22 + P23 / zVS);
// convert to [0,1]
return d * 0.5 + 0.5;
}
/*
Algorithm to compute filter weights:
vec2 samplePosition[numSamples];
for (i = 0; i < numSamples; ++i)
glGetMultisamplefv(GL_SAMPLE_POSITION, i, &samplePosition[i]);
float sampleWeights[numSamples];
for (i = 0; i < numSamples; ++i)
sampleWeights[i] = 1 - norm( samplePosition[i] - vec2(0.5, 0.5) );
normalize sampleWeights array s.t. the sum equals 1
*/
vec4 ReadMultisampledTexture(in sampler2DMS tex, in ivec2 pos, in int numSamples, in samplerBuffer filterWeights)
{
vec4 texel = vec4(0,0,0,0);
for (int i = 0; i < numSamples; ++i)
{
float filterWeight = texelFetch(filterWeights, i).x;
vec4 sample = texelFetch(tex, pos, i);
texel += filterWeight * sample;
}
return texel;
}
vec4 FilterMultisampledTextureBilinear(in sampler2DMS tex, in vec2 texcoord, in int numSamples, in samplerBuffer filterWeights)
{
ivec2 texSize = textureSize(tex);
// top-left texel position
vec2 pos00 = floor( texSize * texcoord );
ivec2 loc00 = ivec2(pos00);
// lerp weights
vec2 alpha = fract( texSize * texcoord );
// bilinear filtering
// lerp in u-direction top
vec4 sampleX0 = mix(
ReadMultisampledTexture(tex, loc00, numSamples, filterWeights),
ReadMultisampledTexture(tex, loc00 + ivec2(1,0), numSamples, filterWeights),
alpha.x);
// lerp in u-direction bottom
vec4 sampleX1 = mix(
ReadMultisampledTexture(tex, loc00 + ivec2(0,1), numSamples, filterWeights),
ReadMultisampledTexture(tex, loc00 + ivec2(1,1), numSamples, filterWeights),
alpha.x);
// lerp in v direction
return mix(sampleX0, sampleX1, alpha.y);
}
\ No newline at end of file
#version 150
uniform vec4 bkColor;
in vec2 vTexCoord;
out vec4 outColor;
void main()
{
outColor = bkColor;
gl_FragDepth = 1.0;
}
#version 150
#include "GBufferAccess.glsl"
#include "depthbuffer.glsl"
uniform sampler2D samplerPos;
uniform sampler2D samplerNormal;
uniform samplerBuffer samplerMaterial;
uniform vec3 lightDir;
uniform vec3 lightAmbient;
uniform vec3 lightDiffuse;
uniform vec3 lightSpecular;
uniform vec4 projParams;
uniform vec2 clipPlanes;
in vec2 vTexCoord;
out vec4 outColor;
void main()
{
// read G-buffer
vec3 cEmissive;
vec3 cAmbient;
vec3 cDiffuse;
vec4 cSpecular;
float shininess;
int matID = int(floor(texture2D(samplerPos, vTexCoord).y));
cEmissive = texelFetch(samplerMaterial, matID * 5).xyz;
cAmbient = texelFetch(samplerMaterial, matID * 5 + 1).xyz * lightAmbient;
cDiffuse = texelFetch(samplerMaterial, matID * 5 + 2).xyz * lightDiffuse;
cSpecular.xyz = texelFetch(samplerMaterial, matID * 5 + 3).xyz * lightSpecular;
shininess = texelFetch(samplerMaterial, matID * 5 + 4).y;
vec3 fragPos = ReadPositionVS(samplerPos, vTexCoord, projParams.x, projParams.y);
vec3 fragNormal = ReadNormalVS(samplerNormal, vTexCoord);
// vec3 fragColor = cEmissive + cAmbient;
vec3 fragColor = cAmbient;
// lighting
// diffuse
float ldotn = clamp(dot(lightDir, fragNormal), 0, 1);
fragColor += ldotn * cDiffuse;
// specular
vec3 h = normalize(lightDir - vec3(0,0,-1));
float hdotn = max(dot(h, fragNormal), 0);
// hdotn = max(0, dot( reflect(lightDir, fragNormal), vec3(0,0,-1) ) );
fragColor += pow(hdotn, shininess) * cSpecular.xyz;
// saturate
fragColor = clamp(fragColor, 0, 1);
outColor = vec4(fragColor, 1);
// outColor = vec4(float(matID) / 100, float(matID) / 100, float(matID) / 100, 1.0);
// compute depth buffer value
gl_FragDepth = ViewspaceToProjectedDepth(fragPos.z, projParams.z, projParams.w);
}
// version with multisampling
#version 150
#include "GBufferAccess.glsl"
#include "depthbuffer.glsl"
uniform sampler2DMS samplerPos;
uniform sampler2DMS samplerNormal;
uniform samplerBuffer samplerMaterial;
uniform vec3 lightDir;
uniform vec3 lightAmbient;
uniform vec3 lightDiffuse;
uniform vec3 lightSpecular;
uniform vec4 projParams;
uniform int numSamples;
uniform samplerBuffer samplerFilterWeights;
in vec2 vTexCoord;
out vec4 outColor;
void main()
{
ivec2 texSize = textureSize(samplerPos);
// absolute pixel index
ivec2 absIndex = ivec2(floor( texSize * vTexCoord ));
vec3 fragColorMS = vec3(0,0,0);
vec3 fragPosMS = vec3(0,0,0);
for (int i = 0; i < numSamples; ++i)
{
// read G-buffer
vec3 cEmissive;
vec3 cAmbient;
vec3 cDiffuse;
vec4 cSpecular;
float shininess;
vec2 depthMatID = texelFetch(samplerPos, absIndex, i).xy;
int matID = int(floor(depthMatID.y));
cEmissive = texelFetch(samplerMaterial, matID * 5).xyz;
cAmbient = texelFetch(samplerMaterial, matID * 5 + 1).xyz * lightAmbient;
cDiffuse = texelFetch(samplerMaterial, matID * 5 + 2).xyz * lightDiffuse;
cSpecular.xyz = texelFetch(samplerMaterial, matID * 5 + 3).xyz * lightSpecular;
shininess = texelFetch(samplerMaterial, matID * 5 + 4).y;
float depthVS = depthMatID.x;
vec3 fragPos = ComputePosVS(depthVS, vTexCoord, projParams.x, projParams.y);
vec3 fragNormal = texelFetch(samplerNormal, absIndex, i).xyz;
fragNormal = normalize( fragNormal * 2 - vec3(1,1,1) );
vec3 sampleColor = cAmbient;
// lighting
// diffuse
float ldotn = clamp(dot(lightDir, fragNormal), 0, 1);
sampleColor += ldotn * cDiffuse;
// specular
vec3 h = normalize(lightDir - vec3(0,0,-1));
float hdotn = max(dot(h, fragNormal), 0);
sampleColor += pow(hdotn, shininess) * cSpecular.xyz;
// saturate
sampleColor = clamp(sampleColor, 0, 1);
// sample weighting
float weight = texelFetch(samplerFilterWeights, i).x;
fragColorMS += weight * sampleColor;
fragPosMS += weight * fragPos;
}
// saturate
fragColorMS = clamp(fragColorMS, 0, 1);
outColor = vec4(fragColorMS, 1);
gl_FragDepth = ViewspaceToProjectedDepth(fragPosMS.z, projParams.z, projParams.w);
}
// version with multisampling
#version 150
#include "GBufferAccess.glsl"
#include "depthbuffer.glsl"
uniform sampler2DMS samplerPos;
uniform sampler2DMS samplerNormal;
uniform samplerBuffer samplerMaterial;
uniform vec3 lightDir;
uniform vec3 lightAmbient;
uniform vec3 lightDiffuse;
uniform vec3 lightSpecular;
uniform vec4 projParams;
uniform int numSamples;
uniform samplerBuffer samplerFilterWeights;
in vec2 vTexCoord;
out vec4 outColor;
void main()
{
ivec2 texSize = textureSize(samplerPos);
// absolute pixel index
ivec2 absIndex = ivec2(floor( texSize * vTexCoord ));
vec3 fragColorMS = vec3(0,0,0);
vec3 fragPosMS = vec3(0,0,0);
for (int i = 0; i < numSamples; ++i)
{
// read G-buffer
vec3 cEmissive;
vec3 cAmbient;
vec3 cDiffuse;
vec4 cSpecular;
float shininess;
vec2 depthMatID = texelFetch(samplerPos, absIndex, i).xy;
int matID = int(floor(depthMatID.y));
cEmissive = texelFetch(samplerMaterial, matID * 5).xyz;
cAmbient = texelFetch(samplerMaterial, matID * 5 + 1).xyz * lightAmbient;
cDiffuse = texelFetch(samplerMaterial, matID * 5 + 2).xyz * lightDiffuse;
cSpecular.xyz = texelFetch(samplerMaterial, matID * 5 + 3).xyz * lightSpecular;
shininess = texelFetch(samplerMaterial, matID * 5 + 4).y;
float depthVS = depthMatID.x;
vec3 fragPos = ComputePosVS(depthVS, vTexCoord, projParams.x, projParams.y);
vec3 fragNormal = texelFetch(samplerNormal, absIndex, i).xyz;
fragNormal = normalize( fragNormal * 2 - vec3(1,1,1) );
vec3 sampleColor = cEmissive + cAmbient;