Added SSAO pass

This commit is contained in:
Magnus Norddahl 2016-08-29 13:10:22 +02:00
parent a1d90e1229
commit 737e700774
14 changed files with 531 additions and 47 deletions

View file

@ -1113,6 +1113,7 @@ set( FASTMATH_SOURCES
gl/shaders/gl_shaderprogram.cpp
gl/shaders/gl_presentshader.cpp
gl/shaders/gl_bloomshader.cpp
gl/shaders/gl_ambientshader.cpp
gl/shaders/gl_blurshader.cpp
gl/shaders/gl_tonemapshader.cpp
gl/shaders/gl_lensshader.cpp

View file

@ -68,6 +68,7 @@
#include "gl/renderer/gl_postprocessstate.h"
#include "gl/data/gl_data.h"
#include "gl/data/gl_vertexbuffer.h"
#include "gl/shaders/gl_ambientshader.h"
#include "gl/shaders/gl_bloomshader.h"
#include "gl/shaders/gl_blurshader.h"
#include "gl/shaders/gl_tonemapshader.h"
@ -106,6 +107,20 @@ CVAR(Float, gl_lens_k, -0.12f, 0)
CVAR(Float, gl_lens_kcube, 0.1f, 0)
CVAR(Float, gl_lens_chromatic, 1.12f, 0)
CVAR(Bool, gl_ssao, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
CVAR(Bool, gl_ssao_debug, false, 0)
CVAR(Float, gl_ssao_bias, 0.5f, 0)
CVAR(Float, gl_ssao_radius, 100.0f, 0)
CUSTOM_CVAR(Float, gl_ssao_blur_amount, 6.0f, 0)
{
if (self < 0.1f) self = 0.1f;
}
CUSTOM_CVAR(Int, gl_ssao_blur_samples, 9, 0)
{
if (self < 3 || self > 15 || self % 2 == 0)
self = 9;
}
EXTERN_CVAR(Float, vid_brightness)
EXTERN_CVAR(Float, vid_contrast)
@ -117,6 +132,95 @@ void FGLRenderer::RenderScreenQuad()
GLRenderer->mVBO->RenderArray(GL_TRIANGLE_STRIP, FFlatVertexBuffer::PRESENT_INDEX, 4);
}
void FGLRenderer::PostProcessScene()
{
if (FGLRenderBuffers::IsEnabled()) mBuffers->BlitSceneToTexture();
AmbientOccludeScene();
BloomScene();
TonemapScene();
LensDistortScene();
}
//-----------------------------------------------------------------------------
//
// Adds ambient occlusion to the scene
//
//-----------------------------------------------------------------------------
void FGLRenderer::AmbientOccludeScene()
{
if (!gl_ssao || !FGLRenderBuffers::IsEnabled())
return;
FGLDebug::PushGroup("AmbientOccludeScene");
FGLPostProcessState savedState;
float bias = gl_ssao_bias;
float aoRadius = gl_ssao_radius;
const float blurAmount = gl_ssao_blur_amount;
int blurSampleCount = gl_ssao_blur_samples;
//float tanHalfFovy = tan(fovy * (M_PI / 360.0f));
float tanHalfFovy = 1.0f / 1.33333302f; //gl_RenderState.mProjectionMatrix.get()[5];
float invFocalLenX = tanHalfFovy * (mBuffers->AmbientWidth / (float)mBuffers->AmbientHeight);
float invFocalLenY = tanHalfFovy;
float nDotVBias = clamp(bias, 0.0f, 1.0f);
float r2 = aoRadius * aoRadius;
// Calculate linear depth values
glBindFramebuffer(GL_FRAMEBUFFER, mBuffers->AmbientFB0);
glViewport(0, 0, mBuffers->AmbientWidth, mBuffers->AmbientHeight);
mBuffers->BindSceneDepthTexture(0);
mLinearDepthShader->Bind();
mLinearDepthShader->DepthTexture.Set(0);
mLinearDepthShader->LinearizeDepthA.Set(1.0f / GetZFar() - 1.0f / GetZNear());
mLinearDepthShader->LinearizeDepthB.Set(MAX(1.0f / GetZNear(), 1.e-8f));
mLinearDepthShader->InverseDepthRangeA.Set(1.0f);
mLinearDepthShader->InverseDepthRangeB.Set(0.0f);
RenderScreenQuad();
// Apply ambient occlusion
glBindFramebuffer(GL_FRAMEBUFFER, mBuffers->AmbientFB1);
glBindTexture(GL_TEXTURE_2D, mBuffers->AmbientTexture0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
mSSAOShader->Bind();
mSSAOShader->DepthTexture.Set(0);
mSSAOShader->UVToViewA.Set(2.0f * invFocalLenX, -2.0f * invFocalLenY);
mSSAOShader->UVToViewB.Set(-invFocalLenX, invFocalLenY);
mSSAOShader->InvFullResolution.Set(1.0f / mBuffers->AmbientWidth, 1.0f / mBuffers->AmbientHeight);
mSSAOShader->NDotVBias.Set(nDotVBias);
mSSAOShader->NegInvR2.Set(-1.0f / r2);
mSSAOShader->RadiusToScreen.Set(aoRadius * 0.5 / tanHalfFovy * mBuffers->AmbientHeight);
mSSAOShader->AOMultiplier.Set(1.0f / (1.0f - nDotVBias));
RenderScreenQuad();
// Blur SSAO texture
mBlurShader->BlurHorizontal(this, blurAmount, blurSampleCount, mBuffers->AmbientTexture1, mBuffers->AmbientFB0, mBuffers->AmbientWidth, mBuffers->AmbientHeight);
mBlurShader->BlurVertical(this, blurAmount, blurSampleCount, mBuffers->AmbientTexture0, mBuffers->AmbientFB1, mBuffers->AmbientWidth, mBuffers->AmbientHeight);
// Add SSAO back to scene texture:
mBuffers->BindCurrentFB();
glViewport(mSceneViewport.left, mSceneViewport.top, mSceneViewport.width, mSceneViewport.height);
glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD);
if (gl_ssao_debug)
glBlendFunc(GL_ONE, GL_ZERO);
else
glBlendFunc(GL_ZERO, GL_SRC_COLOR);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, mBuffers->AmbientTexture1);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
mBloomCombineShader->Bind();
mBloomCombineShader->BloomTexture.Set(0);
RenderScreenQuad();
glViewport(mScreenViewport.left, mScreenViewport.top, mScreenViewport.width, mScreenViewport.height);
FGLDebug::PopGroup();
}
//-----------------------------------------------------------------------------
//
// Adds bloom contribution to scene texture
@ -126,7 +230,7 @@ void FGLRenderer::RenderScreenQuad()
void FGLRenderer::BloomScene()
{
// Only bloom things if enabled and no special fixed light mode is active
if (!gl_bloom || !FGLRenderBuffers::IsEnabled() || gl_fixedcolormap != CM_DEFAULT)
if (!gl_bloom || !FGLRenderBuffers::IsEnabled() || gl_fixedcolormap != CM_DEFAULT || gl_ssao_debug)
return;
FGLDebug::PushGroup("BloomScene");

View file

@ -86,15 +86,16 @@ FGLRenderBuffers::~FGLRenderBuffers()
ClearScene();
ClearPipeline();
ClearBloom();
ClearAmbientOcclusion();
}
void FGLRenderBuffers::ClearScene()
{
DeleteFrameBuffer(mSceneFB);
DeleteRenderBuffer(mSceneMultisample);
DeleteRenderBuffer(mSceneDepthStencil);
DeleteRenderBuffer(mSceneDepth);
DeleteRenderBuffer(mSceneStencil);
DeleteRenderBuffer(mSceneMSColor);
DeleteRenderBuffer(mSceneMSDepthStencil);
DeleteRenderBuffer(mSceneMSDepth);
DeleteRenderBuffer(mSceneMSStencil);
}
void FGLRenderBuffers::ClearPipeline()
@ -104,6 +105,9 @@ void FGLRenderBuffers::ClearPipeline()
DeleteFrameBuffer(mPipelineFB[i]);
DeleteTexture(mPipelineTexture[i]);
}
DeleteTexture(mPipelineDepthStencil);
DeleteTexture(mPipelineDepth);
DeleteTexture(mPipelineStencil);
}
void FGLRenderBuffers::ClearBloom()
@ -119,6 +123,14 @@ void FGLRenderBuffers::ClearBloom()
}
}
void FGLRenderBuffers::ClearAmbientOcclusion()
{
DeleteFrameBuffer(AmbientFB0);
DeleteFrameBuffer(AmbientFB1);
DeleteTexture(AmbientTexture0);
DeleteTexture(AmbientTexture1);
}
void FGLRenderBuffers::DeleteTexture(GLuint &handle)
{
if (handle != 0)
@ -178,11 +190,12 @@ bool FGLRenderBuffers::Setup(int width, int height, int sceneWidth, int sceneHei
}
// Bloom bluring buffers need to match the scene to avoid bloom bleeding artifacts
if (mBloomWidth != sceneWidth || mBloomHeight != sceneHeight)
if (mSceneWidth != sceneWidth || mSceneHeight != sceneHeight)
{
CreateBloom(sceneWidth, sceneHeight);
mBloomWidth = sceneWidth;
mBloomHeight = sceneHeight;
CreateAmbientOcclusion(sceneWidth, sceneHeight);
mSceneWidth = sceneWidth;
mSceneHeight = sceneHeight;
}
glBindTexture(GL_TEXTURE_2D, textureBinding);
@ -198,8 +211,8 @@ bool FGLRenderBuffers::Setup(int width, int height, int sceneWidth, int sceneHei
mWidth = 0;
mHeight = 0;
mSamples = 0;
mBloomWidth = 0;
mBloomHeight = 0;
mSceneWidth = 0;
mSceneHeight = 0;
}
return !FailedCreate;
@ -216,18 +229,27 @@ void FGLRenderBuffers::CreateScene(int width, int height, int samples)
ClearScene();
if (samples > 1)
mSceneMultisample = CreateRenderBuffer("SceneMultisample", GetHdrFormat(), samples, width, height);
if ((gl.flags & RFL_NO_DEPTHSTENCIL) != 0)
{
mSceneDepth = CreateRenderBuffer("SceneDepth", GL_DEPTH_COMPONENT24, samples, width, height);
mSceneStencil = CreateRenderBuffer("SceneStencil", GL_STENCIL_INDEX8, samples, width, height);
mSceneFB = CreateFrameBuffer("SceneFB", samples > 1 ? mSceneMultisample : mPipelineTexture[0], mSceneDepth, mSceneStencil, samples > 1);
mSceneMSColor = CreateRenderBuffer("SceneMSColor", GetHdrFormat(), samples, width, height);
if ((gl.flags & RFL_NO_DEPTHSTENCIL) != 0)
{
mSceneMSDepth = CreateRenderBuffer("SceneMSDepth", GL_DEPTH_COMPONENT24, samples, width, height);
mSceneMSStencil = CreateRenderBuffer("SceneMSStencil", GL_STENCIL_INDEX8, samples, width, height);
mSceneFB = CreateFrameBuffer("SceneFB", mSceneMSColor, mSceneMSDepth, mSceneMSStencil, true);
}
else
{
mSceneMSDepthStencil = CreateRenderBuffer("SceneMSDepthStencil", GL_DEPTH24_STENCIL8, samples, width, height);
mSceneFB = CreateFrameBuffer("SceneFB", mSceneMSColor, mSceneMSDepthStencil, true);
}
}
else
{
mSceneDepthStencil = CreateRenderBuffer("SceneDepthStencil", GL_DEPTH24_STENCIL8, samples, width, height);
mSceneFB = CreateFrameBuffer("SceneFB", samples > 1 ? mSceneMultisample : mPipelineTexture[0], mSceneDepthStencil, samples > 1);
if ((gl.flags & RFL_NO_DEPTHSTENCIL) != 0)
mSceneFB = CreateFrameBuffer("SceneFB", mPipelineTexture[0], mPipelineDepth, mPipelineStencil, false);
else
mSceneFB = CreateFrameBuffer("SceneFB", mPipelineTexture[0], mPipelineDepthStencil, false);
}
}
@ -241,10 +263,23 @@ void FGLRenderBuffers::CreatePipeline(int width, int height)
{
ClearPipeline();
if ((gl.flags & RFL_NO_DEPTHSTENCIL) != 0)
{
mPipelineDepth = Create2DTexture("PipelineDepth", GL_DEPTH_COMPONENT24, width, height);
mPipelineStencil = Create2DTexture("PipelineStencil", GL_STENCIL_INDEX8, width, height);
}
else
{
mPipelineDepthStencil = Create2DTexture("PipelineDepthStencil", GL_DEPTH24_STENCIL8, width, height);
}
for (int i = 0; i < NumPipelineTextures; i++)
{
mPipelineTexture[i] = Create2DTexture("PipelineTexture", GetHdrFormat(), width, height);
mPipelineFB[i] = CreateFrameBuffer("PipelineFB", mPipelineTexture[i]);
if ((gl.flags & RFL_NO_DEPTHSTENCIL) != 0)
mPipelineFB[i] = CreateFrameBuffer("PipelineFB", mPipelineTexture[i], mPipelineDepth, mPipelineStencil, false);
else
mPipelineFB[i] = CreateFrameBuffer("PipelineFB", mPipelineTexture[i], mPipelineDepthStencil, false);
}
}
@ -280,6 +315,27 @@ void FGLRenderBuffers::CreateBloom(int width, int height)
}
}
//==========================================================================
//
// Creates ambient occlusion working buffers
//
//==========================================================================
void FGLRenderBuffers::CreateAmbientOcclusion(int width, int height)
{
ClearAmbientOcclusion();
if (width <= 0 || height <= 0)
return;
AmbientWidth = width / 2;
AmbientHeight = height / 2;
AmbientTexture0 = Create2DTexture("AmbientTexture0", GetHdrFormat(), AmbientWidth, AmbientHeight);
AmbientTexture1 = Create2DTexture("AmbientTexture1", GetHdrFormat(), AmbientWidth, AmbientHeight);
AmbientFB0 = CreateFrameBuffer("AmbientFB0", AmbientTexture0);
AmbientFB1 = CreateFrameBuffer("AmbientFB1", AmbientTexture1);
}
//==========================================================================
//
// Fallback support for older OpenGL where RGBA16F might not be available
@ -299,12 +355,24 @@ GLuint FGLRenderBuffers::GetHdrFormat()
GLuint FGLRenderBuffers::Create2DTexture(const FString &name, GLuint format, int width, int height)
{
GLuint type = (format == GL_RGBA16F) ? GL_FLOAT : GL_UNSIGNED_BYTE;
GLuint handle = 0;
glGenTextures(1, &handle);
glBindTexture(GL_TEXTURE_2D, handle);
FGLDebug::LabelObject(GL_TEXTURE, handle, name);
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, GL_RGBA, type, nullptr);
GLenum dataformat, datatype;
switch (format) // Special thanks to the designers of OpenGL..
{
case GL_RGBA8: dataformat = GL_RGBA; datatype = GL_UNSIGNED_BYTE; break;
case GL_RGBA16: dataformat = GL_RGBA; datatype = GL_UNSIGNED_SHORT; break;
case GL_RGBA16F: dataformat = GL_RGBA; datatype = GL_FLOAT; break;
case GL_DEPTH_COMPONENT24: dataformat = GL_DEPTH_COMPONENT; datatype = GL_FLOAT; break;
case GL_STENCIL_INDEX8: dataformat = GL_STENCIL_INDEX; datatype = GL_INT; break;
case GL_DEPTH24_STENCIL8: dataformat = GL_DEPTH_STENCIL; datatype = GL_UNSIGNED_INT_24_8; break;
default: I_FatalError("Unknown format passed to FGLRenderBuffers.Create2DTexture");
}
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, dataformat, datatype, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
@ -359,34 +427,45 @@ GLuint FGLRenderBuffers::CreateFrameBuffer(const FString &name, GLuint colorbuff
return handle;
}
GLuint FGLRenderBuffers::CreateFrameBuffer(const FString &name, GLuint colorbuffer, GLuint depthstencil, bool colorIsARenderBuffer)
GLuint FGLRenderBuffers::CreateFrameBuffer(const FString &name, GLuint colorbuffer, GLuint depthstencil, bool fromRenderBuffers)
{
GLuint handle = 0;
glGenFramebuffers(1, &handle);
glBindFramebuffer(GL_FRAMEBUFFER, handle);
FGLDebug::LabelObject(GL_FRAMEBUFFER, handle, name);
if (colorIsARenderBuffer)
if (fromRenderBuffers)
{
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorbuffer);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, depthstencil);
}
else
{
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorbuffer, 0);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, depthstencil);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, depthstencil, 0);
}
if (CheckFrameBufferCompleteness())
ClearFrameBuffer(true, true);
return handle;
}
GLuint FGLRenderBuffers::CreateFrameBuffer(const FString &name, GLuint colorbuffer, GLuint depth, GLuint stencil, bool colorIsARenderBuffer)
GLuint FGLRenderBuffers::CreateFrameBuffer(const FString &name, GLuint colorbuffer, GLuint depth, GLuint stencil, bool fromRenderBuffers)
{
GLuint handle = 0;
glGenFramebuffers(1, &handle);
glBindFramebuffer(GL_FRAMEBUFFER, handle);
FGLDebug::LabelObject(GL_FRAMEBUFFER, handle, name);
if (colorIsARenderBuffer)
if (fromRenderBuffers)
{
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorbuffer);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, stencil);
}
else
{
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorbuffer, 0);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, stencil);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, stencil, 0);
}
if (CheckFrameBufferCompleteness())
ClearFrameBuffer(true, true);
return handle;
@ -441,7 +520,7 @@ void FGLRenderBuffers::ClearFrameBuffer(bool stencil, bool depth)
glGetIntegerv(GL_STENCIL_CLEAR_VALUE, &stencilValue);
glGetDoublev(GL_DEPTH_CLEAR_VALUE, &depthValue);
glDisable(GL_SCISSOR_TEST);
glClearColor(0.0, 0.0, 0.0, 0.0);
glClearColor(1.0, 0.0, 0.0, 0.0);
glClearDepth(0.0);
glClearStencil(0);
GLenum flags = GL_COLOR_BUFFER_BIT;
@ -471,7 +550,7 @@ void FGLRenderBuffers::BlitSceneToTexture()
glBindFramebuffer(GL_READ_FRAMEBUFFER, mSceneFB);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mPipelineFB[mCurrentPipelineTexture]);
glBlitFramebuffer(0, 0, mWidth, mHeight, 0, 0, mWidth, mHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST);
glBlitFramebuffer(0, 0, mWidth, mHeight, 0, 0, mWidth, mHeight, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST);
if ((gl.flags & RFL_INVALIDATE_BUFFER) != 0)
{
@ -494,6 +573,21 @@ void FGLRenderBuffers::BindSceneFB()
glBindFramebuffer(GL_FRAMEBUFFER, mSceneFB);
}
//==========================================================================
//
// Binds the depth texture to the specified texture unit
//
//==========================================================================
void FGLRenderBuffers::BindSceneDepthTexture(int index)
{
glActiveTexture(GL_TEXTURE0 + index);
if ((gl.flags & RFL_NO_DEPTHSTENCIL) != 0)
glBindTexture(GL_TEXTURE_2D, mPipelineDepth);
else
glBindTexture(GL_TEXTURE_2D, mPipelineDepthStencil);
}
//==========================================================================
//
// Binds the current scene/effect/hud texture to the specified texture unit

View file

@ -23,6 +23,7 @@ public:
bool Setup(int width, int height, int sceneWidth, int sceneHeight);
void BindSceneFB();
void BindSceneDepthTexture(int index);
void BlitSceneToTexture();
void BindCurrentTexture(int index);
@ -35,6 +36,14 @@ public:
enum { NumBloomLevels = 4 };
FGLBloomTextureLevel BloomLevels[NumBloomLevels];
// Ambient occlusion buffers
GLuint AmbientTexture0 = 0;
GLuint AmbientTexture1 = 0;
GLuint AmbientFB0 = 0;
GLuint AmbientFB1 = 0;
int AmbientWidth = 0;
int AmbientHeight = 0;
static bool IsEnabled();
int GetWidth() const { return mWidth; }
@ -44,15 +53,17 @@ private:
void ClearScene();
void ClearPipeline();
void ClearBloom();
void ClearAmbientOcclusion();
void CreateScene(int width, int height, int samples);
void CreatePipeline(int width, int height);
void CreateBloom(int width, int height);
void CreateAmbientOcclusion(int width, int height);
GLuint Create2DTexture(const FString &name, GLuint format, int width, int height);
GLuint CreateRenderBuffer(const FString &name, GLuint format, int width, int height);
GLuint CreateRenderBuffer(const FString &name, GLuint format, int samples, int width, int height);
GLuint CreateFrameBuffer(const FString &name, GLuint colorbuffer);
GLuint CreateFrameBuffer(const FString &name, GLuint colorbuffer, GLuint depthstencil, bool colorIsARenderBuffer);
GLuint CreateFrameBuffer(const FString &name, GLuint colorbuffer, GLuint depth, GLuint stencil, bool colorIsARenderBuffer);
GLuint CreateFrameBuffer(const FString &name, GLuint colorbuffer, GLuint depthstencil, bool fromRenderBuffers);
GLuint CreateFrameBuffer(const FString &name, GLuint colorbuffer, GLuint depth, GLuint stencil, bool fromRenderBuffers);
bool CheckFrameBufferCompleteness();
void ClearFrameBuffer(bool stencil, bool depth);
void DeleteTexture(GLuint &handle);
@ -65,22 +76,25 @@ private:
int mHeight = 0;
int mSamples = 0;
int mMaxSamples = 0;
int mBloomWidth = 0;
int mBloomHeight = 0;
int mSceneWidth = 0;
int mSceneHeight = 0;
static const int NumPipelineTextures = 2;
int mCurrentPipelineTexture = 0;
// Buffers for the scene
GLuint mSceneMultisample = 0;
GLuint mSceneDepthStencil = 0;
GLuint mSceneDepth = 0;
GLuint mSceneStencil = 0;
GLuint mSceneMSColor = 0;
GLuint mSceneMSDepthStencil = 0;
GLuint mSceneMSDepth = 0;
GLuint mSceneMSStencil = 0;
GLuint mSceneFB = 0;
// Effect/HUD buffers
GLuint mPipelineTexture[NumPipelineTextures];
GLuint mPipelineFB[NumPipelineTextures];
GLuint mPipelineDepthStencil = 0;
GLuint mPipelineDepth = 0;
GLuint mPipelineStencil = 0;
// Back buffer frame buffer
GLuint mOutputFB = 0;

View file

@ -64,6 +64,7 @@
#include "gl/data/gl_vertexbuffer.h"
#include "gl/scene/gl_drawinfo.h"
#include "gl/shaders/gl_shader.h"
#include "gl/shaders/gl_ambientshader.h"
#include "gl/shaders/gl_bloomshader.h"
#include "gl/shaders/gl_blurshader.h"
#include "gl/shaders/gl_tonemapshader.h"
@ -120,6 +121,8 @@ void gl_FlushModels();
void FGLRenderer::Initialize(int width, int height)
{
mBuffers = new FGLRenderBuffers();
mLinearDepthShader = new FLinearDepthShader();
mSSAOShader = new FSSAOShader();
mBloomExtractShader = new FBloomExtractShader();
mBloomCombineShader = new FBloomCombineShader();
mBlurShader = new FBlurShader();
@ -179,6 +182,8 @@ FGLRenderer::~FGLRenderer()
}
if (mBuffers) delete mBuffers;
if (mPresentShader) delete mPresentShader;
if (mLinearDepthShader) delete mLinearDepthShader;
if (mSSAOShader) delete mSSAOShader;
if (mBloomExtractShader) delete mBloomExtractShader;
if (mBloomCombineShader) delete mBloomCombineShader;
if (mBlurShader) delete mBlurShader;

View file

@ -19,6 +19,8 @@ class FLightBuffer;
class FSamplerManager;
class DPSprite;
class FGLRenderBuffers;
class FLinearDepthShader;
class FSSAOShader;
class FBloomExtractShader;
class FBloomCombineShader;
class FBlurShader;
@ -89,6 +91,8 @@ public:
int mOldFBID;
FGLRenderBuffers *mBuffers;
FLinearDepthShader *mLinearDepthShader;
FSSAOShader *mSSAOShader;
FBloomExtractShader *mBloomExtractShader;
FBloomCombineShader *mBloomCombineShader;
FBlurShader *mBlurShader;
@ -164,6 +168,8 @@ public:
void SetFixedColormap (player_t *player);
void WriteSavePic (player_t *player, FILE *file, int width, int height);
void EndDrawScene(sector_t * viewsector);
void PostProcessScene();
void AmbientOccludeScene();
void BloomScene();
void TonemapScene();
void BindTonemapPalette(int texunit);
@ -186,6 +192,9 @@ public:
void FillSimplePoly(FTexture *texture, FVector2 *points, int npoints,
double originx, double originy, double scalex, double scaley,
DAngle rotation, FDynamicColormap *colormap, int lightlevel);
static float GetZNear() { return 5.f; }
static float GetZFar() { return 65536.f; }
};
// Global functions. Make them members of GLRenderer later?

View file

@ -221,7 +221,7 @@ void FGLRenderer::SetProjection(float fov, float ratio, float fovratio)
{
float fovy = 2 * RAD2DEG(atan(tan(DEG2RAD(fov) / 2) / fovratio));
gl_RenderState.mProjectionMatrix.perspective(fovy, ratio, 5.f, 65536.f);
gl_RenderState.mProjectionMatrix.perspective(fovy, ratio, GetZNear(), GetZFar());
}
// raw matrix input from stereo 3d modes
@ -855,13 +855,7 @@ sector_t * FGLRenderer::RenderViewpoint (AActor * camera, GL_IRECT * bounds, flo
ProcessScene(toscreen);
if (mainview && toscreen) EndDrawScene(retval); // do not call this for camera textures.
if (mainview)
{
if (FGLRenderBuffers::IsEnabled()) mBuffers->BlitSceneToTexture();
BloomScene();
TonemapScene();
LensDistortScene();
}
if (mainview) PostProcessScene();
mDrawingScene2D = false;
eye->TearDown();
}

View file

@ -0,0 +1,89 @@
/*
** gl_bloomshader.cpp
** Shaders used for screen space ambient occlusion
**
**---------------------------------------------------------------------------
** Copyright 2016 Magnus Norddahl
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
** 4. When not used as part of GZDoom or a GZDoom derivative, this code will be
** covered by the terms of the GNU Lesser General Public License as published
** by the Free Software Foundation; either version 2.1 of the License, or (at
** your option) any later version.
** 5. Full disclosure of the entire project's source code, except for third
** party libraries is mandatory. (NOTE: This clause is non-negotiable!)
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
#include "gl/system/gl_system.h"
#include "files.h"
#include "m_swap.h"
#include "v_video.h"
#include "gl/gl_functions.h"
#include "vectors.h"
#include "gl/system/gl_interface.h"
#include "gl/system/gl_framebuffer.h"
#include "gl/system/gl_cvars.h"
#include "gl/shaders/gl_ambientshader.h"
void FLinearDepthShader::Bind()
{
if (!mShader)
{
mShader.Compile(FShaderProgram::Vertex, "shaders/glsl/screenquad.vp", "", 330);
mShader.Compile(FShaderProgram::Fragment, "shaders/glsl/lineardepth.fp", "", 330);
mShader.SetFragDataLocation(0, "FragColor");
mShader.Link("shaders/glsl/lineardepth");
mShader.SetAttribLocation(0, "PositionInProjection");
DepthTexture.Init(mShader, "DepthTexture");
LinearizeDepthA.Init(mShader, "LinearizeDepthA");
LinearizeDepthB.Init(mShader, "LinearizeDepthB");
InverseDepthRangeA.Init(mShader, "InverseDepthRangeA");
InverseDepthRangeB.Init(mShader, "InverseDepthRangeB");
}
mShader.Bind();
}
void FSSAOShader::Bind()
{
if (!mShader)
{
mShader.Compile(FShaderProgram::Vertex, "shaders/glsl/screenquad.vp", "", 330);
mShader.Compile(FShaderProgram::Fragment, "shaders/glsl/ssao.fp", "", 330);
mShader.SetFragDataLocation(0, "FragColor");
mShader.Link("shaders/glsl/ssao");
mShader.SetAttribLocation(0, "PositionInProjection");
DepthTexture.Init(mShader, "DepthTexture");
UVToViewA.Init(mShader, "UVToViewA");
UVToViewB.Init(mShader, "UVToViewB");
InvFullResolution.Init(mShader, "InvFullResolution");
NDotVBias.Init(mShader, "NDotVBias");
NegInvR2.Init(mShader, "NegInvR2");
RadiusToScreen.Init(mShader, "RadiusToScreen");
AOMultiplier.Init(mShader, "AOMultiplier");
}
mShader.Bind();
}

View file

@ -0,0 +1,39 @@
#ifndef __GL_AMBIENTSHADER_H
#define __GL_AMBIENTSHADER_H
#include "gl_shaderprogram.h"
class FLinearDepthShader
{
public:
void Bind();
FBufferedUniformSampler DepthTexture;
FBufferedUniform1f LinearizeDepthA;
FBufferedUniform1f LinearizeDepthB;
FBufferedUniform1f InverseDepthRangeA;
FBufferedUniform1f InverseDepthRangeB;
private:
FShaderProgram mShader;
};
class FSSAOShader
{
public:
void Bind();
FBufferedUniformSampler DepthTexture;
FBufferedUniform2f UVToViewA;
FBufferedUniform2f UVToViewB;
FBufferedUniform2f InvFullResolution;
FBufferedUniform1f NDotVBias;
FBufferedUniform1f NegInvR2;
FBufferedUniform1f RadiusToScreen;
FBufferedUniform1f AOMultiplier;
private:
FShaderProgram mShader;
};
#endif

View file

@ -49,7 +49,7 @@ VSMatrix EyePose::GetProjection(float fov, float aspectRatio, float fovRatio) co
// Lifted from gl_scene.cpp FGLRenderer::SetProjection()
float fovy = (float)(2 * RAD2DEG(atan(tan(DEG2RAD(fov) / 2) / fovRatio)));
result.perspective(fovy, aspectRatio, 5.f, 65536.f);
result.perspective(fovy, aspectRatio, FGLRenderer::GetZNear(), FGLRenderer::GetZFar());
return result;
}

View file

@ -2634,6 +2634,7 @@ GLPREFMNU_MULTISAMPLE = "Multisample";
GLPREFMNU_TONEMAP = "Tonemap Mode";
GLPREFMNU_BLOOM = "Bloom effect";
GLPREFMNU_LENS = "Lens distortion effect";
GLPREFMNU_SSAO = "Ambient occlusion";
// Option Values
OPTVAL_SMART = "Smart";

View file

@ -230,4 +230,5 @@ OptionMenu "GLPrefOptions"
Option "$GLPREFMNU_TONEMAP", gl_tonemap, "TonemapModes"
Option "$GLPREFMNU_BLOOM", gl_bloom, "OnOff"
Option "$GLPREFMNU_LENS", gl_lens, "OnOff"
Option "$GLPREFMNU_SSAO", gl_ssao, "OnOff"
}

View file

@ -0,0 +1,16 @@
in vec2 TexCoord;
out vec4 FragColor;
uniform sampler2D DepthTexture;
uniform float LinearizeDepthA;
uniform float LinearizeDepthB;
uniform float InverseDepthRangeA;
uniform float InverseDepthRangeB;
void main()
{
float depth = texture(DepthTexture, TexCoord).x;
float normalizedDepth = clamp(InverseDepthRangeA * depth + InverseDepthRangeB, 0.0, 1.0);
FragColor = vec4(1.0 / (normalizedDepth * LinearizeDepthA + LinearizeDepthB), 0.0, 0.0, 1.0);
}

View file

@ -0,0 +1,117 @@
in vec2 TexCoord;
out vec4 FragColor;
uniform vec2 UVToViewA;
uniform vec2 UVToViewB;
uniform vec2 InvFullResolution;
uniform float NDotVBias;
uniform float NegInvR2;
uniform float RadiusToScreen;
uniform float AOMultiplier;
uniform sampler2D DepthTexture;
#if USE_RANDOM_TEXTURE
uniform sampler2D RandomTexture;
#endif
#define NUM_DIRECTIONS 8.0
#define NUM_STEPS 4.0
#define PI 3.14159265358979323846
// Calculate eye space position for the specified texture coordinate
vec3 FetchViewPos(vec2 uv)
{
float z = texture(DepthTexture, uv).x;
return vec3((UVToViewA * uv + UVToViewB) * z, z);
}
vec3 MinDiff(vec3 p, vec3 pr, vec3 pl)
{
vec3 v1 = pr - p;
vec3 v2 = p - pl;
return (dot(v1, v1) < dot(v2, v2)) ? v1 : v2;
}
// Reconstruct eye space normal from nearest neighbors
vec3 ReconstructNormal(vec3 p)
{
vec3 pr = FetchViewPos(TexCoord + vec2(InvFullResolution.x, 0));
vec3 pl = FetchViewPos(TexCoord + vec2(-InvFullResolution.x, 0));
vec3 pt = FetchViewPos(TexCoord + vec2(0, InvFullResolution.y));
vec3 pb = FetchViewPos(TexCoord + vec2(0, -InvFullResolution.y));
return normalize(cross(MinDiff(p, pr, pl), MinDiff(p, pt, pb)));
}
// Compute normalized 2D direction
vec2 RotateDirection(vec2 dir, vec2 cossin)
{
return vec2(dir.x * cossin.x - dir.y * cossin.y, dir.x * cossin.y + dir.y * cossin.x);
}
vec4 GetJitter()
{
#if !USE_RANDOM_TEXTURE
return vec4(1,0,1,1);
//vec3 rand = noise3(TexCoord.x + TexCoord.y);
//float angle = 2.0 * PI * rand.x / NUM_DIRECTIONS;
//return vec4(cos(angle), sin(angle), rand.y, rand.z);
#else
#define RANDOM_TEXTURE_WIDTH 4.0
return texture(RandomTexture, gl_FragCoord.xy / RANDOM_TEXTURE_WIDTH);
#endif
}
// Calculates the ambient occlusion of a sample
float ComputeSampleAO(vec3 kernelPos, vec3 normal, vec3 samplePos)
{
vec3 v = samplePos - kernelPos;
float distanceSquare = dot(v, v);
float nDotV = dot(normal, v) * inversesqrt(distanceSquare);
return clamp(nDotV - NDotVBias, 0.0, 1.0) * clamp(distanceSquare * NegInvR2 + 1.0, 0.0, 1.0);
}
// Calculates the total ambient occlusion for the entire fragment
float ComputeAO(vec3 viewPosition, vec3 viewNormal)
{
vec4 rand = GetJitter();
float radiusPixels = RadiusToScreen / viewPosition.z;
float stepSizePixels = radiusPixels / (NUM_STEPS + 1.0);
const float directionAngleStep = 2.0 * PI / NUM_DIRECTIONS;
float ao = 0.0;
for (float directionIndex = 0.0; directionIndex < NUM_DIRECTIONS; ++directionIndex)
{
float angle = directionAngleStep * directionIndex;
vec2 direction = RotateDirection(vec2(cos(angle), sin(angle)), rand.xy);
float rayPixels = (rand.z * stepSizePixels + 1.0);
for (float StepIndex = 0.0; StepIndex < NUM_STEPS; ++StepIndex)
{
vec2 sampleUV = round(rayPixels * direction) * InvFullResolution + TexCoord;
vec3 samplePos = FetchViewPos(sampleUV);
ao += ComputeSampleAO(viewPosition, viewNormal, samplePos);
rayPixels += stepSizePixels;
}
}
ao *= AOMultiplier / (NUM_DIRECTIONS * NUM_STEPS);
return clamp(1.0 - ao * 2.0, 0.0, 1.0);
}
void main()
{
vec3 viewPosition = FetchViewPos(TexCoord);
vec3 viewNormal = ReconstructNormal(viewPosition);
float occlusion = ComputeAO(viewPosition, viewNormal);
//FragColor = vec4(viewPosition.x * 0.001 + 0.5, viewPosition.y * 0.001 + 0.5, viewPosition.z * 0.001, 1.0);
//FragColor = vec4(viewNormal.x * 0.5 + 0.5, viewNormal.y * 0.5 + 0.5, viewNormal.z * 0.5 + 0.5, 1.0);
//FragColor = vec4(occlusion, viewPosition.z, 0.0, 1.0);
FragColor = vec4(occlusion, occlusion, occlusion, 1.0);
}