mirror of
https://github.com/ZDoom/gzdoom-gles.git
synced 2024-11-25 05:31:00 +00:00
Added SSAO pass
This commit is contained in:
parent
8907a8bfe8
commit
9076d46261
14 changed files with 580 additions and 61 deletions
|
@ -1125,6 +1125,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_colormapshader.cpp
|
||||
gl/shaders/gl_tonemapshader.cpp
|
||||
|
|
|
@ -55,6 +55,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"
|
||||
|
@ -98,6 +99,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)
|
||||
|
||||
|
@ -109,6 +124,96 @@ void FGLRenderer::RenderScreenQuad()
|
|||
GLRenderer->mVBO->RenderArray(GL_TRIANGLE_STRIP, FFlatVertexBuffer::PRESENT_INDEX, 4);
|
||||
}
|
||||
|
||||
void FGLRenderer::PostProcessScene()
|
||||
{
|
||||
if (FGLRenderBuffers::IsEnabled()) mBuffers->BlitSceneToTexture();
|
||||
AmbientOccludeScene();
|
||||
UpdateCameraExposure();
|
||||
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();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Extracts light average from the scene and updates the camera exposure texture
|
||||
|
@ -190,7 +295,7 @@ void FGLRenderer::UpdateCameraExposure()
|
|||
void FGLRenderer::BloomScene()
|
||||
{
|
||||
// Only bloom things if enabled and no special fixed light mode is active
|
||||
if (!gl_bloom || gl_fixedcolormap != CM_DEFAULT)
|
||||
if (!gl_bloom || gl_fixedcolormap != CM_DEFAULT || gl_ssao_debug)
|
||||
return;
|
||||
|
||||
FGLDebug::PushGroup("BloomScene");
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
#include "w_wad.h"
|
||||
#include "i_system.h"
|
||||
#include "doomerrors.h"
|
||||
#include <random>
|
||||
|
||||
CVAR(Int, gl_multisample, 1, CVAR_ARCHIVE|CVAR_GLOBALCONFIG);
|
||||
CVAR(Bool, gl_renderbuffers, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL)
|
||||
|
@ -75,15 +76,16 @@ FGLRenderBuffers::~FGLRenderBuffers()
|
|||
ClearEyeBuffers();
|
||||
ClearBloom();
|
||||
ClearExposureLevels();
|
||||
ClearAmbientOcclusion();
|
||||
}
|
||||
|
||||
void FGLRenderBuffers::ClearScene()
|
||||
{
|
||||
DeleteFrameBuffer(mSceneFB);
|
||||
DeleteRenderBuffer(mSceneMultisample);
|
||||
DeleteRenderBuffer(mSceneDepthStencil);
|
||||
DeleteRenderBuffer(mSceneDepth);
|
||||
DeleteRenderBuffer(mSceneStencil);
|
||||
DeleteFrameBuffer(mSceneDataFB);
|
||||
DeleteTexture(mSceneMultisample);
|
||||
DeleteTexture(mSceneData);
|
||||
DeleteTexture(mSceneDepthStencil);
|
||||
}
|
||||
|
||||
void FGLRenderBuffers::ClearPipeline()
|
||||
|
@ -132,6 +134,15 @@ void FGLRenderBuffers::ClearEyeBuffers()
|
|||
mEyeFBs.Clear();
|
||||
}
|
||||
|
||||
void FGLRenderBuffers::ClearAmbientOcclusion()
|
||||
{
|
||||
DeleteFrameBuffer(AmbientFB0);
|
||||
DeleteFrameBuffer(AmbientFB1);
|
||||
DeleteTexture(AmbientTexture0);
|
||||
DeleteTexture(AmbientTexture1);
|
||||
DeleteTexture(AmbientRandomTexture);
|
||||
}
|
||||
|
||||
void FGLRenderBuffers::DeleteTexture(GLuint &handle)
|
||||
{
|
||||
if (handle != 0)
|
||||
|
@ -203,6 +214,7 @@ bool FGLRenderBuffers::Setup(int width, int height, int sceneWidth, int sceneHei
|
|||
{
|
||||
CreateBloom(sceneWidth, sceneHeight);
|
||||
CreateExposureLevels(sceneWidth, sceneHeight);
|
||||
CreateAmbientOcclusion(sceneWidth, sceneHeight);
|
||||
mSceneWidth = sceneWidth;
|
||||
mSceneHeight = sceneHeight;
|
||||
}
|
||||
|
@ -240,10 +252,19 @@ void FGLRenderBuffers::CreateScene(int width, int height, int samples)
|
|||
ClearScene();
|
||||
|
||||
if (samples > 1)
|
||||
mSceneMultisample = CreateRenderBuffer("SceneMultisample", GL_RGBA16F, samples, width, height);
|
||||
{
|
||||
mSceneMultisample = Create2DMultisampleTexture("SceneMultisample", GL_RGBA16F, width, height, samples, false);
|
||||
mSceneDepthStencil = Create2DMultisampleTexture("SceneDepthStencil", GL_DEPTH24_STENCIL8, width, height, samples, false);
|
||||
mSceneData = Create2DMultisampleTexture("SceneSSAOData", GL_RGBA8, width, height, samples, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
mSceneDepthStencil = Create2DTexture("SceneDepthStencil", GL_DEPTH24_STENCIL8, width, height);
|
||||
mSceneData = Create2DTexture("SceneSSAOData", GL_RGBA8, width, height);
|
||||
}
|
||||
|
||||
mSceneDepthStencil = CreateRenderBuffer("SceneDepthStencil", GL_DEPTH24_STENCIL8, samples, width, height);
|
||||
mSceneFB = CreateFrameBuffer("SceneFB", samples > 1 ? mSceneMultisample : mPipelineTexture[0], mSceneDepthStencil, samples > 1);
|
||||
mSceneFB = CreateFrameBuffer("SceneFB", samples > 1 ? mSceneMultisample : mPipelineTexture[0], 0, mSceneDepthStencil, samples > 1);
|
||||
mSceneDataFB = CreateFrameBuffer("SSAOSceneFB", samples > 1 ? mSceneMultisample : mPipelineTexture[0], mSceneData, mSceneDepthStencil, samples > 1);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -296,6 +317,47 @@ 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", GL_RG32F, AmbientWidth, AmbientHeight);
|
||||
AmbientTexture1 = Create2DTexture("AmbientTexture1", GL_RG32F, AmbientWidth, AmbientHeight);
|
||||
AmbientFB0 = CreateFrameBuffer("AmbientFB0", AmbientTexture0);
|
||||
AmbientFB1 = CreateFrameBuffer("AmbientFB1", AmbientTexture1);
|
||||
|
||||
int16_t randomValues[16 * 4];
|
||||
std::mt19937 generator(1337);
|
||||
std::uniform_real_distribution<double> distribution(-1.0, 1.0);
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
double num_directions = 8.0; // Must be same as the define in ssao.fp
|
||||
double angle = 2.0 * M_PI * distribution(generator) / num_directions;
|
||||
double x = cos(angle);
|
||||
double y = sin(angle);
|
||||
double z = distribution(generator);
|
||||
double w = distribution(generator);
|
||||
|
||||
randomValues[i * 4 + 0] = (int16_t)clamp(x * 32767.0, -32768.0, 32767.0);
|
||||
randomValues[i * 4 + 1] = (int16_t)clamp(y * 32767.0, -32768.0, 32767.0);
|
||||
randomValues[i * 4 + 2] = (int16_t)clamp(z * 32767.0, -32768.0, 32767.0);
|
||||
randomValues[i * 4 + 3] = (int16_t)clamp(w * 32767.0, -32768.0, 32767.0);
|
||||
}
|
||||
|
||||
AmbientRandomTexture = Create2DTexture("AmbientRandomTexture", GL_RGBA16_SNORM, 4, 4, randomValues);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Creates camera exposure level buffers
|
||||
|
@ -368,12 +430,28 @@ void FGLRenderBuffers::CreateEyeBuffers(int eye)
|
|||
|
||||
GLuint FGLRenderBuffers::Create2DTexture(const FString &name, GLuint format, int width, int height, const void *data)
|
||||
{
|
||||
GLuint type = (format == GL_RGBA16F || format == GL_R32F) ? 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, format != GL_R32F ? GL_RGBA : GL_RED, type, data);
|
||||
|
||||
GLenum dataformat, datatype;
|
||||
switch (format)
|
||||
{
|
||||
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_RGBA32F: dataformat = GL_RGBA; datatype = GL_FLOAT; break;
|
||||
case GL_R32F: dataformat = GL_RED; datatype = GL_FLOAT; break;
|
||||
case GL_RG32F: dataformat = GL_RG; 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;
|
||||
case GL_RGBA16_SNORM: dataformat = GL_RGBA; datatype = GL_SHORT; break;
|
||||
default: I_FatalError("Unknown format passed to FGLRenderBuffers.Create2DTexture");
|
||||
}
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, dataformat, datatype, data);
|
||||
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);
|
||||
|
@ -381,6 +459,17 @@ GLuint FGLRenderBuffers::Create2DTexture(const FString &name, GLuint format, int
|
|||
return handle;
|
||||
}
|
||||
|
||||
GLuint FGLRenderBuffers::Create2DMultisampleTexture(const FString &name, GLuint format, int width, int height, int samples, bool fixedSampleLocations)
|
||||
{
|
||||
GLuint handle = 0;
|
||||
glGenTextures(1, &handle);
|
||||
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, handle);
|
||||
FGLDebug::LabelObject(GL_TEXTURE, handle, name);
|
||||
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, samples, format, width, height, fixedSampleLocations);
|
||||
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0);
|
||||
return handle;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Creates a render buffer
|
||||
|
@ -428,34 +517,26 @@ 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 colorbuffer0, GLuint colorbuffer1, GLuint depthstencil, bool multisample)
|
||||
{
|
||||
GLuint handle = 0;
|
||||
glGenFramebuffers(1, &handle);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, handle);
|
||||
FGLDebug::LabelObject(GL_FRAMEBUFFER, handle, name);
|
||||
if (colorIsARenderBuffer)
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorbuffer);
|
||||
if (multisample)
|
||||
{
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, colorbuffer0, 0);
|
||||
if (colorbuffer1 != 0)
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D_MULTISAMPLE, colorbuffer1, 0);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D_MULTISAMPLE, depthstencil, 0);
|
||||
}
|
||||
else
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorbuffer, 0);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, depthstencil);
|
||||
if (CheckFrameBufferCompleteness())
|
||||
ClearFrameBuffer(true, true);
|
||||
return handle;
|
||||
}
|
||||
|
||||
GLuint FGLRenderBuffers::CreateFrameBuffer(const FString &name, GLuint colorbuffer, GLuint depth, GLuint stencil, bool colorIsARenderBuffer)
|
||||
{
|
||||
GLuint handle = 0;
|
||||
glGenFramebuffers(1, &handle);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, handle);
|
||||
FGLDebug::LabelObject(GL_FRAMEBUFFER, handle, name);
|
||||
if (colorIsARenderBuffer)
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorbuffer);
|
||||
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_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorbuffer0, 0);
|
||||
if (colorbuffer1 != 0)
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, colorbuffer1, 0);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, depthstencil, 0);
|
||||
}
|
||||
if (CheckFrameBufferCompleteness())
|
||||
ClearFrameBuffer(true, true);
|
||||
return handle;
|
||||
|
@ -475,22 +556,23 @@ bool FGLRenderBuffers::CheckFrameBufferCompleteness()
|
|||
|
||||
FailedCreate = true;
|
||||
|
||||
#if 0
|
||||
FString error = "glCheckFramebufferStatus failed: ";
|
||||
switch (result)
|
||||
if (gl_debug_level > 0)
|
||||
{
|
||||
default: error.AppendFormat("error code %d", (int)result); break;
|
||||
case GL_FRAMEBUFFER_UNDEFINED: error << "GL_FRAMEBUFFER_UNDEFINED"; break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: error << "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT"; break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: error << "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT"; break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER: error << "GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER"; break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER: error << "GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER"; break;
|
||||
case GL_FRAMEBUFFER_UNSUPPORTED: error << "GL_FRAMEBUFFER_UNSUPPORTED"; break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE: error << "GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE"; break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS: error << "GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS"; break;
|
||||
FString error = "glCheckFramebufferStatus failed: ";
|
||||
switch (result)
|
||||
{
|
||||
default: error.AppendFormat("error code %d", (int)result); break;
|
||||
case GL_FRAMEBUFFER_UNDEFINED: error << "GL_FRAMEBUFFER_UNDEFINED"; break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: error << "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT"; break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: error << "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT"; break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER: error << "GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER"; break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER: error << "GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER"; break;
|
||||
case GL_FRAMEBUFFER_UNSUPPORTED: error << "GL_FRAMEBUFFER_UNSUPPORTED"; break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE: error << "GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE"; break;
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS: error << "GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS"; break;
|
||||
}
|
||||
Printf("%s\n", error.GetChars());
|
||||
}
|
||||
I_FatalError(error);
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -595,9 +677,54 @@ void FGLRenderBuffers::BindEyeFB(int eye, bool readBuffer)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
void FGLRenderBuffers::BindSceneFB()
|
||||
void FGLRenderBuffers::BindSceneFB(bool sceneData)
|
||||
{
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, mSceneFB);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, sceneData ? mSceneDataFB : mSceneFB);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Binds the scene color texture to the specified texture unit
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FGLRenderBuffers::BindSceneColorTexture(int index)
|
||||
{
|
||||
glActiveTexture(GL_TEXTURE0 + index);
|
||||
if (mSamples > 1)
|
||||
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, mSceneMultisample);
|
||||
else
|
||||
glBindTexture(GL_TEXTURE_2D, mPipelineTexture[0]);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Binds the scene data texture to the specified texture unit
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FGLRenderBuffers::BindSceneDataTexture(int index)
|
||||
{
|
||||
glActiveTexture(GL_TEXTURE0 + index);
|
||||
if (mSamples > 1)
|
||||
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, mSceneData);
|
||||
else
|
||||
glBindTexture(GL_TEXTURE_2D, mSceneData);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// Binds the depth texture to the specified texture unit
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void FGLRenderBuffers::BindSceneDepthTexture(int index)
|
||||
{
|
||||
glActiveTexture(GL_TEXTURE0 + index);
|
||||
if (mSamples > 1)
|
||||
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, mSceneDepthStencil);
|
||||
else
|
||||
glBindTexture(GL_TEXTURE_2D, mSceneDepthStencil);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
|
|
@ -31,7 +31,10 @@ public:
|
|||
|
||||
bool Setup(int width, int height, int sceneWidth, int sceneHeight);
|
||||
|
||||
void BindSceneFB();
|
||||
void BindSceneFB(bool sceneData);
|
||||
void BindSceneColorTexture(int index);
|
||||
void BindSceneDataTexture(int index);
|
||||
void BindSceneDepthTexture(int index);
|
||||
void BlitSceneToTexture();
|
||||
|
||||
void BindCurrentTexture(int index);
|
||||
|
@ -53,6 +56,15 @@ public:
|
|||
GLuint ExposureFB = 0;
|
||||
bool FirstExposureFrame = true;
|
||||
|
||||
// Ambient occlusion buffers
|
||||
GLuint AmbientTexture0 = 0;
|
||||
GLuint AmbientTexture1 = 0;
|
||||
GLuint AmbientFB0 = 0;
|
||||
GLuint AmbientFB1 = 0;
|
||||
int AmbientWidth = 0;
|
||||
int AmbientHeight = 0;
|
||||
GLuint AmbientRandomTexture = 0;
|
||||
|
||||
static bool IsEnabled();
|
||||
|
||||
int GetWidth() const { return mWidth; }
|
||||
|
@ -64,17 +76,19 @@ private:
|
|||
void ClearEyeBuffers();
|
||||
void ClearBloom();
|
||||
void ClearExposureLevels();
|
||||
void ClearAmbientOcclusion();
|
||||
void CreateScene(int width, int height, int samples);
|
||||
void CreatePipeline(int width, int height);
|
||||
void CreateBloom(int width, int height);
|
||||
void CreateExposureLevels(int width, int height);
|
||||
void CreateEyeBuffers(int eye);
|
||||
void CreateAmbientOcclusion(int width, int height);
|
||||
GLuint Create2DTexture(const FString &name, GLuint format, int width, int height, const void *data = nullptr);
|
||||
GLuint Create2DMultisampleTexture(const FString &name, GLuint format, int width, int height, int samples, bool fixedSampleLocations);
|
||||
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 colorbuffer0, GLuint colorbuffer1, GLuint depthstencil, bool multisample);
|
||||
bool CheckFrameBufferCompleteness();
|
||||
void ClearFrameBuffer(bool stencil, bool depth);
|
||||
void DeleteTexture(GLuint &handle);
|
||||
|
@ -94,9 +108,9 @@ private:
|
|||
// Buffers for the scene
|
||||
GLuint mSceneMultisample = 0;
|
||||
GLuint mSceneDepthStencil = 0;
|
||||
GLuint mSceneDepth = 0;
|
||||
GLuint mSceneStencil = 0;
|
||||
GLuint mSceneData = 0;
|
||||
GLuint mSceneFB = 0;
|
||||
GLuint mSceneDataFB = 0;
|
||||
|
||||
// Effect/HUD buffers
|
||||
GLuint mPipelineTexture[NumPipelineTextures];
|
||||
|
|
|
@ -51,6 +51,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"
|
||||
|
@ -121,6 +122,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();
|
||||
mExposureExtractShader = new FExposureExtractShader();
|
||||
|
@ -184,6 +187,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 (mExposureExtractShader) delete mExposureExtractShader;
|
||||
|
|
|
@ -19,6 +19,8 @@ class FLightBuffer;
|
|||
class FSamplerManager;
|
||||
class DPSprite;
|
||||
class FGLRenderBuffers;
|
||||
class FLinearDepthShader;
|
||||
class FSSAOShader;
|
||||
class FBloomExtractShader;
|
||||
class FBloomCombineShader;
|
||||
class FExposureExtractShader;
|
||||
|
@ -93,6 +95,8 @@ public:
|
|||
int mOldFBID;
|
||||
|
||||
FGLRenderBuffers *mBuffers;
|
||||
FLinearDepthShader *mLinearDepthShader;
|
||||
FSSAOShader *mSSAOShader;
|
||||
FBloomExtractShader *mBloomExtractShader;
|
||||
FBloomCombineShader *mBloomCombineShader;
|
||||
FExposureExtractShader *mExposureExtractShader;
|
||||
|
@ -172,6 +176,8 @@ public:
|
|||
void WriteSavePic (player_t *player, FileWriter *file, int width, int height);
|
||||
void EndDrawScene(sector_t * viewsector);
|
||||
void UpdateCameraExposure();
|
||||
void PostProcessScene();
|
||||
void AmbientOccludeScene();
|
||||
void BloomScene();
|
||||
void TonemapScene();
|
||||
void ColormapScene();
|
||||
|
@ -198,6 +204,9 @@ public:
|
|||
DAngle rotation, FDynamicColormap *colormap, int lightlevel);
|
||||
|
||||
int PTM_BestColor (const uint32 *pal_in, int r, int g, int b, int first, int num);
|
||||
|
||||
static float GetZNear() { return 5.f; }
|
||||
static float GetZFar() { return 65536.f; }
|
||||
};
|
||||
|
||||
// Global functions. Make them members of GLRenderer later?
|
||||
|
|
|
@ -209,7 +209,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
|
||||
|
@ -826,12 +826,7 @@ sector_t * FGLRenderer::RenderViewpoint (AActor * camera, GL_IRECT * bounds, flo
|
|||
if (mainview && toscreen) EndDrawScene(lviewsector); // do not call this for camera textures.
|
||||
if (mainview && FGLRenderBuffers::IsEnabled())
|
||||
{
|
||||
mBuffers->BlitSceneToTexture();
|
||||
UpdateCameraExposure();
|
||||
BloomScene();
|
||||
TonemapScene();
|
||||
ColormapScene();
|
||||
LensDistortScene();
|
||||
PostProcessScene();
|
||||
|
||||
// This should be done after postprocessing, not before.
|
||||
mBuffers->BindCurrentFB();
|
||||
|
|
89
src/gl/shaders/gl_ambientshader.cpp
Normal file
89
src/gl/shaders/gl_ambientshader.cpp
Normal 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();
|
||||
}
|
39
src/gl/shaders/gl_ambientshader.h
Normal file
39
src/gl/shaders/gl_ambientshader.h
Normal 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
|
|
@ -41,7 +41,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;
|
||||
}
|
||||
|
|
|
@ -2633,6 +2633,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";
|
||||
|
|
|
@ -226,4 +226,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"
|
||||
}
|
||||
|
|
16
wadsrc/static/shaders/glsl/lineardepth.fp
Normal file
16
wadsrc/static/shaders/glsl/lineardepth.fp
Normal 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);
|
||||
}
|
117
wadsrc/static/shaders/glsl/ssao.fp
Normal file
117
wadsrc/static/shaders/glsl/ssao.fp
Normal 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);
|
||||
}
|
Loading…
Reference in a new issue