- port bloom, blur and camera exposure to postprocess steps and remove the old implementation

This commit is contained in:
Magnus Norddahl 2018-06-22 00:29:50 +02:00
parent fd2037bd6c
commit 83f50f5808
14 changed files with 302 additions and 738 deletions

View file

@ -1067,9 +1067,7 @@ set (PCH_SOURCES
hwrenderer/postprocessing/hw_shadowmapshader.cpp
hwrenderer/postprocessing/hw_presentshader.cpp
hwrenderer/postprocessing/hw_present3dRowshader.cpp
hwrenderer/postprocessing/hw_bloomshader.cpp
hwrenderer/postprocessing/hw_ambientshader.cpp
hwrenderer/postprocessing/hw_blurshader.cpp
hwrenderer/postprocessing/hw_colormapshader.cpp
hwrenderer/postprocessing/hw_tonemapshader.cpp
hwrenderer/textures/hw_material.cpp

View file

@ -40,8 +40,6 @@
#include "gl/renderer/gl_postprocessstate.h"
#include "gl/data/gl_vertexbuffer.h"
#include "hwrenderer/postprocessing/hw_ambientshader.h"
#include "hwrenderer/postprocessing/hw_bloomshader.h"
#include "hwrenderer/postprocessing/hw_blurshader.h"
#include "hwrenderer/postprocessing/hw_tonemapshader.h"
#include "hwrenderer/postprocessing/hw_colormapshader.h"
#include "hwrenderer/postprocessing/hw_presentshader.h"
@ -91,6 +89,7 @@ void FGLRenderBuffers::RenderEffect(const FString &name)
default:
case PixelFormat::Rgba8: glformat = GL_RGBA8; break;
case PixelFormat::Rgba16f: glformat = GL_RGBA16F; break;
case PixelFormat::R32f: glformat = GL_R32F; break;
}
if (gltexture && (gltexture.Width != pair->Value.Width || gltexture.Height != pair->Value.Height))
@ -345,125 +344,17 @@ void FGLRenderer::AmbientOccludeScene()
FGLDebug::PopGroup();
}
//-----------------------------------------------------------------------------
//
// Extracts light average from the scene and updates the camera exposure texture
//
//-----------------------------------------------------------------------------
void FGLRenderer::UpdateCameraExposure()
{
if (!gl_bloom && gl_tonemap == 0)
return;
FGLDebug::PushGroup("UpdateCameraExposure");
FGLPostProcessState savedState;
savedState.SaveTextureBindings(2);
// Extract light level from scene texture:
auto &level0 = mBuffers->ExposureLevels[0];
level0.Framebuffer.Bind();
glViewport(0, 0, level0.Width, level0.Height);
mBuffers->BindCurrentTexture(0, GL_LINEAR);
mExposureExtractShader->Bind(NOQUEUE);
mExposureExtractShader->Uniforms->Scale = screen->SceneScale();
mExposureExtractShader->Uniforms->Offset = screen->SceneOffset();
mExposureExtractShader->Uniforms.Set();
RenderScreenQuad();
// Find the average value:
for (unsigned int i = 0; i + 1 < mBuffers->ExposureLevels.Size(); i++)
{
auto &level = mBuffers->ExposureLevels[i];
auto &next = mBuffers->ExposureLevels[i + 1];
next.Framebuffer.Bind();
glViewport(0, 0, next.Width, next.Height);
level.Texture.Bind(0);
mExposureAverageShader->Bind(NOQUEUE);
RenderScreenQuad();
}
// Combine average value with current camera exposure:
mBuffers->ExposureFB.Bind();
glViewport(0, 0, 1, 1);
if (!mBuffers->FirstExposureFrame)
{
glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
else
{
mBuffers->FirstExposureFrame = false;
}
mBuffers->ExposureLevels.Last().Texture.Bind(0);
mExposureCombineShader->Bind(NOQUEUE);
mExposureCombineShader->Uniforms->ExposureBase = gl_exposure_base;
mExposureCombineShader->Uniforms->ExposureMin = gl_exposure_min;
mExposureCombineShader->Uniforms->ExposureScale = gl_exposure_scale;
mExposureCombineShader->Uniforms->ExposureSpeed = gl_exposure_speed;
mExposureCombineShader->Uniforms.Set();
RenderScreenQuad();
const auto &mScreenViewport = screen->mScreenViewport;
glViewport(mScreenViewport.left, mScreenViewport.top, mScreenViewport.width, mScreenViewport.height);
FGLDebug::PopGroup();
}
//-----------------------------------------------------------------------------
//
// Adds bloom contribution to scene texture
//
//-----------------------------------------------------------------------------
static float ComputeBlurGaussian(float n, float theta) // theta = Blur Amount
{
return (float)((1.0f / sqrtf(2 * (float)M_PI * theta)) * expf(-(n * n) / (2.0f * theta * theta)));
}
static void ComputeBlurSamples(int sampleCount, float blurAmount, float *sampleWeights)
{
sampleWeights[0] = ComputeBlurGaussian(0, blurAmount);
float totalWeights = sampleWeights[0];
for (int i = 0; i < sampleCount / 2; i++)
{
float weight = ComputeBlurGaussian(i + 1.0f, blurAmount);
sampleWeights[i * 2 + 1] = weight;
sampleWeights[i * 2 + 2] = weight;
totalWeights += weight * 2;
}
for (int i = 0; i < sampleCount; i++)
{
sampleWeights[i] /= totalWeights;
}
}
static void RenderBlur(FGLRenderer *renderer, float blurAmount, PPTexture input, PPFrameBuffer output, int width, int height, bool vertical)
{
ComputeBlurSamples(7, blurAmount, renderer->mBlurShader->Uniforms[vertical]->SampleWeights);
renderer->mBlurShader->Bind(NOQUEUE, vertical);
renderer->mBlurShader->Uniforms[vertical].Set(POSTPROCESS_BINDINGPOINT);
input.Bind(0);
output.Bind();
glViewport(0, 0, width, height);
glDisable(GL_BLEND);
renderer->RenderScreenQuad();
PPCameraExposure exposure;
exposure.DeclareShaders();
exposure.UpdateTextures(mBuffers->GetSceneWidth(), mBuffers->GetSceneHeight());
exposure.UpdateSteps();
mBuffers->RenderEffect("UpdateCameraExposure");
}
void FGLRenderer::BloomScene(int fixedcm)
{
#if 0
if (mBuffers->GetSceneWidth() <= 0 || mBuffers->GetSceneHeight() <= 0)
return;
@ -471,157 +362,21 @@ void FGLRenderer::BloomScene(int fixedcm)
bloom.DeclareShaders();
bloom.UpdateTextures(mBuffers->GetSceneWidth(), mBuffers->GetSceneHeight());
bloom.UpdateSteps(fixedcm);
mBuffers->RenderEffect("Bloom");
#else
// Only bloom things if enabled and no special fixed light mode is active
if (!gl_bloom || fixedcm != CM_DEFAULT || gl_ssao_debug)
return;
FGLDebug::PushGroup("BloomScene");
FGLPostProcessState savedState;
savedState.SaveTextureBindings(2);
const float blurAmount = gl_bloom_amount;
auto &level0 = mBuffers->BloomLevels[0];
// Extract blooming pixels from scene texture:
level0.VFramebuffer.Bind();
glViewport(0, 0, level0.Width, level0.Height);
mBuffers->BindCurrentTexture(0, GL_LINEAR);
mBuffers->ExposureTexture.Bind(1);
mBloomExtractShader->Bind(NOQUEUE);
mBloomExtractShader->Uniforms->Scale = screen->SceneScale();
mBloomExtractShader->Uniforms->Offset = screen->SceneOffset();
mBloomExtractShader->Uniforms.Set();
RenderScreenQuad();
// Blur and downscale:
for (int i = 0; i < FGLRenderBuffers::NumBloomLevels - 1; i++)
{
auto &level = mBuffers->BloomLevels[i];
auto &next = mBuffers->BloomLevels[i + 1];
RenderBlur(this, blurAmount, level.VTexture, level.HFramebuffer, level.Width, level.Height, false);
RenderBlur(this, blurAmount, level.HTexture, next.VFramebuffer, next.Width, next.Height, true);
mBuffers->RenderEffect("BloomScene");
}
// Blur and upscale:
for (int i = FGLRenderBuffers::NumBloomLevels - 1; i > 0; i--)
{
auto &level = mBuffers->BloomLevels[i];
auto &next = mBuffers->BloomLevels[i - 1];
RenderBlur(this, blurAmount, level.VTexture, level.HFramebuffer, level.Width, level.Height, false);
RenderBlur(this, blurAmount, level.HTexture, level.VFramebuffer, level.Width, level.Height, true);
// Linear upscale:
next.VFramebuffer.Bind();
glViewport(0, 0, next.Width, next.Height);
level.VTexture.Bind(0, GL_LINEAR);
mBloomCombineShader->Bind(NOQUEUE);
RenderScreenQuad();
}
RenderBlur(this, blurAmount, level0.VTexture, level0.HFramebuffer, level0.Width, level0.Height, false);
RenderBlur(this, blurAmount, level0.HTexture, level0.VFramebuffer, level0.Width, level0.Height, true);
const auto &mSceneViewport = screen->mSceneViewport;
const auto &mScreenViewport = screen->mScreenViewport;
// Add bloom back to scene texture:
mBuffers->BindCurrentFB();
glViewport(mSceneViewport.left, mSceneViewport.top, mSceneViewport.width, mSceneViewport.height);
glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD);
glBlendFunc(GL_ONE, GL_ONE);
level0.VTexture.Bind(0, GL_LINEAR);
mBloomCombineShader->Bind(NOQUEUE);
RenderScreenQuad();
glViewport(mScreenViewport.left, mScreenViewport.top, mScreenViewport.width, mScreenViewport.height);
FGLDebug::PopGroup();
#endif
}
//-----------------------------------------------------------------------------
//
// Blur the scene
//
//-----------------------------------------------------------------------------
void FGLRenderer::BlurScene(float gameinfobluramount)
{
// first, respect the CVar
float blurAmount = gl_menu_blur;
// if CVar is negative, use the gameinfo entry
if (gl_menu_blur < 0)
blurAmount = gameinfobluramount;
// if blurAmount == 0 or somehow still returns negative, exit to prevent a crash, clearly we don't want this
if (blurAmount <= 0.0)
if (mBuffers->GetSceneWidth() <= 0 || mBuffers->GetSceneHeight() <= 0)
return;
FGLDebug::PushGroup("BlurScene");
FGLPostProcessState savedState;
savedState.SaveTextureBindings(2);
int numLevels = 3; // Must be 4 or less (since FGLRenderBuffers::NumBloomLevels is 4 and we are using its buffers).
assert(numLevels <= FGLRenderBuffers::NumBloomLevels);
const auto &viewport = screen->mScreenViewport; // The area we want to blur. Could also be mSceneViewport if only the scene area is to be blured
const auto &level0 = mBuffers->BloomLevels[0];
// Grab the area we want to bloom:
mBuffers->BlitLinear(mBuffers->GetCurrentFB(), level0.VFramebuffer, viewport.left, viewport.top, viewport.width, viewport.height, 0, 0, level0.Width, level0.Height);
// Blur and downscale:
for (int i = 0; i < numLevels - 1; i++)
{
auto &level = mBuffers->BloomLevels[i];
auto &next = mBuffers->BloomLevels[i + 1];
RenderBlur(this, blurAmount, level.VTexture, level.HFramebuffer, level.Width, level.Height, false);
RenderBlur(this, blurAmount, level.HTexture, next.VFramebuffer, next.Width, next.Height, true);
PPBloom blur;
blur.DeclareShaders();
blur.UpdateTextures(mBuffers->GetSceneWidth(), mBuffers->GetSceneHeight());
blur.UpdateBlurSteps(gameinfobluramount);
mBuffers->RenderEffect("BlurScene");
}
// Blur and upscale:
for (int i = numLevels - 1; i > 0; i--)
{
auto &level = mBuffers->BloomLevels[i];
auto &next = mBuffers->BloomLevels[i - 1];
RenderBlur(this, blurAmount, level.VTexture, level.HFramebuffer, level.Width, level.Height, false);
RenderBlur(this, blurAmount, level.HTexture, level.VFramebuffer, level.Width, level.Height, true);
// Linear upscale:
next.VFramebuffer.Bind();
glViewport(0, 0, next.Width, next.Height);
level.VTexture.Bind(0, GL_LINEAR);
mBloomCombineShader->Bind(NOQUEUE);
RenderScreenQuad();
}
RenderBlur(this, blurAmount, level0.VTexture, level0.HFramebuffer, level0.Width, level0.Height, false);
RenderBlur(this, blurAmount, level0.HTexture, level0.VFramebuffer, level0.Width, level0.Height, true);
// Copy blur back to scene texture:
mBuffers->BlitLinear(level0.VFramebuffer, mBuffers->GetCurrentFB(), 0, 0, level0.Width, level0.Height, viewport.left, viewport.top, viewport.width, viewport.height);
glViewport(viewport.left, viewport.top, viewport.width, viewport.height);
FGLDebug::PopGroup();
}
//-----------------------------------------------------------------------------
//
// Tonemap scene texture and place the result in the HUD/2D texture
//
//-----------------------------------------------------------------------------
void FGLRenderer::TonemapScene()
{
if (gl_tonemap == 0)
@ -650,7 +405,7 @@ void FGLRenderer::TonemapScene()
}
else
{
mBuffers->ExposureTexture.Bind(1);
//mBuffers->ExposureTexture.Bind(1);
}
RenderScreenQuad();

View file

@ -58,8 +58,6 @@ FGLRenderBuffers::~FGLRenderBuffers()
ClearScene();
ClearPipeline();
ClearEyeBuffers();
ClearBloom();
ClearExposureLevels();
ClearAmbientOcclusion();
ClearShadowMap();
}
@ -93,31 +91,6 @@ void FGLRenderBuffers::ClearPipeline()
}
}
void FGLRenderBuffers::ClearBloom()
{
for (int i = 0; i < NumBloomLevels; i++)
{
auto &level = BloomLevels[i];
DeleteFrameBuffer(level.HFramebuffer);
DeleteFrameBuffer(level.VFramebuffer);
DeleteTexture(level.HTexture);
DeleteTexture(level.VTexture);
level = FGLBloomTextureLevel();
}
}
void FGLRenderBuffers::ClearExposureLevels()
{
for (auto &level : ExposureLevels)
{
DeleteTexture(level.Texture);
DeleteFrameBuffer(level.Framebuffer);
}
ExposureLevels.Clear();
DeleteTexture(ExposureTexture);
DeleteFrameBuffer(ExposureFB);
}
void FGLRenderBuffers::ClearEyeBuffers()
{
for (auto handle : mEyeFBs)
@ -198,8 +171,6 @@ 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 (mSceneWidth != sceneWidth || mSceneHeight != sceneHeight)
{
CreateBloom(sceneWidth, sceneHeight);
CreateExposureLevels(sceneWidth, sceneHeight);
CreateAmbientOcclusion(sceneWidth, sceneHeight);
mSceneWidth = sceneWidth;
mSceneHeight = sceneHeight;
@ -215,8 +186,6 @@ bool FGLRenderBuffers::Setup(int width, int height, int sceneWidth, int sceneHei
ClearScene();
ClearPipeline();
ClearEyeBuffers();
ClearBloom();
ClearExposureLevels();
mWidth = 0;
mHeight = 0;
mSamples = 0;
@ -294,38 +263,6 @@ void FGLRenderBuffers::CreatePipeline(int width, int height)
}
}
//==========================================================================
//
// Creates bloom pass working buffers
//
//==========================================================================
void FGLRenderBuffers::CreateBloom(int width, int height)
{
ClearBloom();
// No scene, no bloom!
if (width <= 0 || height <= 0)
return;
int bloomWidth = (width + 1) / 2;
int bloomHeight = (height + 1) / 2;
for (int i = 0; i < NumBloomLevels; i++)
{
auto &level = BloomLevels[i];
level.Width = (bloomWidth + 1) / 2;
level.Height = (bloomHeight + 1) / 2;
level.VTexture = Create2DTexture("Bloom.VTexture", GL_RGBA16F, level.Width, level.Height);
level.HTexture = Create2DTexture("Bloom.HTexture", GL_RGBA16F, level.Width, level.Height);
level.VFramebuffer = CreateFrameBuffer("Bloom.VFramebuffer", level.VTexture);
level.HFramebuffer = CreateFrameBuffer("Bloom.HFramebuffer", level.HTexture);
bloomWidth = level.Width;
bloomHeight = level.Height;
}
}
//==========================================================================
//
// Creates ambient occlusion working buffers
@ -375,41 +312,6 @@ void FGLRenderBuffers::CreateAmbientOcclusion(int width, int height)
}
}
//==========================================================================
//
// Creates camera exposure level buffers
//
//==========================================================================
void FGLRenderBuffers::CreateExposureLevels(int width, int height)
{
ClearExposureLevels();
int i = 0;
do
{
width = MAX(width / 2, 1);
height = MAX(height / 2, 1);
FString textureName, fbName;
textureName.Format("Exposure.Texture%d", i);
fbName.Format("Exposure.Framebuffer%d", i);
i++;
FGLExposureTextureLevel level;
level.Width = width;
level.Height = height;
level.Texture = Create2DTexture(textureName.GetChars(), GL_R32F, level.Width, level.Height);
level.Framebuffer = CreateFrameBuffer(fbName.GetChars(), level.Texture);
ExposureLevels.Push(level);
} while (width > 1 || height > 1);
ExposureTexture = Create2DTexture("Exposure.CameraTexture", GL_R32F, 1, 1);
ExposureFB = CreateFrameBuffer("Exposure.CameraFB", ExposureTexture);
FirstExposureFrame = true;
}
//==========================================================================
//
// Creates eye buffers if needed

View file

@ -54,26 +54,6 @@ private:
friend class FGLRenderBuffers;
};
class FGLBloomTextureLevel
{
public:
PPTexture VTexture;
PPFrameBuffer VFramebuffer;
PPTexture HTexture;
PPFrameBuffer HFramebuffer;
int Width = 0;
int Height = 0;
};
class FGLExposureTextureLevel
{
public:
PPTexture Texture;
PPFrameBuffer Framebuffer;
int Width = 0;
int Height = 0;
};
class FShaderProgram;
class FGLRenderBuffers
@ -115,14 +95,6 @@ public:
void BindShadowMapFB();
void BindShadowMapTexture(int index);
enum { NumBloomLevels = 4 };
FGLBloomTextureLevel BloomLevels[NumBloomLevels];
TArray<FGLExposureTextureLevel> ExposureLevels;
PPTexture ExposureTexture;
PPFrameBuffer ExposureFB;
bool FirstExposureFrame = true;
// Ambient occlusion buffers
PPTexture LinearDepthTexture;
PPFrameBuffer LinearDepthFB;
@ -147,14 +119,10 @@ private:
void ClearScene();
void ClearPipeline();
void ClearEyeBuffers();
void ClearBloom();
void ClearExposureLevels();
void ClearAmbientOcclusion();
void ClearShadowMap();
void CreateScene(int width, int height, int samples, bool needsSceneTextures);
void CreatePipeline(int width, int height);
void CreateBloom(int width, int height);
void CreateExposureLevels(int width, int height);
void CreateEyeBuffers(int eye);
void CreateShadowMap();
void CreateAmbientOcclusion(int width, int height);

View file

@ -51,8 +51,6 @@
#include "gl/scene/gl_drawinfo.h"
#include "gl/scene/gl_scenedrawer.h"
#include "hwrenderer/postprocessing/hw_ambientshader.h"
#include "hwrenderer/postprocessing/hw_bloomshader.h"
#include "hwrenderer/postprocessing/hw_blurshader.h"
#include "hwrenderer/postprocessing/hw_tonemapshader.h"
#include "hwrenderer/postprocessing/hw_colormapshader.h"
#include "hwrenderer/postprocessing/hw_presentshader.h"
@ -101,12 +99,6 @@ FGLRenderer::FGLRenderer(OpenGLFrameBuffer *fb)
mPresent3dCheckerShader = nullptr;
mPresent3dColumnShader = nullptr;
mPresent3dRowShader = nullptr;
mBloomExtractShader = nullptr;
mBloomCombineShader = nullptr;
mExposureExtractShader = nullptr;
mExposureAverageShader = nullptr;
mExposureCombineShader = nullptr;
mBlurShader = nullptr;
mTonemapShader = nullptr;
mTonemapPalette = nullptr;
mColormapShader = nullptr;
@ -127,12 +119,6 @@ void FGLRenderer::Initialize(int width, int height)
mDepthBlurShader = new FDepthBlurShader();
mSSAOShader = new FSSAOShader();
mSSAOCombineShader = new FSSAOCombineShader();
mBloomExtractShader = new FBloomExtractShader();
mBloomCombineShader = new FBloomCombineShader();
mExposureExtractShader = new FExposureExtractShader();
mExposureAverageShader = new FExposureAverageShader();
mExposureCombineShader = new FExposureCombineShader();
mBlurShader = new FBlurShader();
mTonemapShader = new FTonemapShader();
mColormapShader = new FColormapShader();
mTonemapPalette = nullptr;
@ -190,12 +176,6 @@ FGLRenderer::~FGLRenderer()
if (mPresent3dCheckerShader) delete mPresent3dCheckerShader;
if (mPresent3dColumnShader) delete mPresent3dColumnShader;
if (mPresent3dRowShader) delete mPresent3dRowShader;
if (mBloomExtractShader) delete mBloomExtractShader;
if (mBloomCombineShader) delete mBloomCombineShader;
if (mExposureExtractShader) delete mExposureExtractShader;
if (mExposureAverageShader) delete mExposureAverageShader;
if (mExposureCombineShader) delete mExposureCombineShader;
if (mBlurShader) delete mBlurShader;
if (mTonemapShader) delete mTonemapShader;
if (mTonemapPalette) delete mTonemapPalette;
if (mColormapShader) delete mColormapShader;

View file

@ -29,12 +29,6 @@ class FLinearDepthShader;
class FDepthBlurShader;
class FSSAOShader;
class FSSAOCombineShader;
class FBloomExtractShader;
class FBloomCombineShader;
class FExposureExtractShader;
class FExposureAverageShader;
class FExposureCombineShader;
class FBlurShader;
class FTonemapShader;
class FColormapShader;
class FPresentShader;
@ -81,12 +75,6 @@ public:
FSSAOShader *mSSAOShader;
FDepthBlurShader *mDepthBlurShader;
FSSAOCombineShader *mSSAOCombineShader;
FBloomExtractShader *mBloomExtractShader;
FBloomCombineShader *mBloomCombineShader;
FExposureExtractShader *mExposureExtractShader;
FExposureAverageShader *mExposureAverageShader;
FExposureCombineShader *mExposureCombineShader;
FBlurShader *mBlurShader;
FTonemapShader *mTonemapShader;
FColormapShader *mColormapShader;
FHardwareTexture *mTonemapPalette;

View file

@ -1,57 +0,0 @@
//
//---------------------------------------------------------------------------
//
// Copyright(C) 2016 Magnus Norddahl
// All rights reserved.
//
// This program 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.
//
// This program 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 Lesser General Public License
// along with this program. If not, see http://www.gnu.org/licenses/
//
//--------------------------------------------------------------------------
//
/*
** gl_bloomshader.cpp
** Shaders used to do bloom
**
*/
#include "v_video.h"
#include "hw_bloomshader.h"
void FBloomExtractShader::Bind(IRenderQueue *q)
{
if (!mShader)
{
FString prolog = Uniforms.CreateDeclaration("Uniforms", UniformBlock::Desc());
mShader.reset(screen->CreateShaderProgram());
mShader->Compile(IShaderProgram::Vertex, "shaders/glsl/screenquad.vp", "", 330);
mShader->Compile(IShaderProgram::Fragment, "shaders/glsl/bloomextract.fp", prolog, 330);
mShader->Link("shaders/glsl/bloomextract");
mShader->SetUniformBufferLocation(Uniforms.BindingPoint(), "Uniforms");
Uniforms.Init();
}
mShader->Bind(q);
}
void FBloomCombineShader::Bind(IRenderQueue *q)
{
if (!mShader)
{
mShader.reset(screen->CreateShaderProgram());
mShader->Compile(IShaderProgram::Vertex, "shaders/glsl/screenquad.vp", "", 330);
mShader->Compile(IShaderProgram::Fragment, "shaders/glsl/bloomcombine.fp", "", 330);
mShader->Link("shaders/glsl/bloomcombine");
}
mShader->Bind(q);
}

View file

@ -1,41 +0,0 @@
#ifndef __GL_BLOOMSHADER_H
#define __GL_BLOOMSHADER_H
#include "hwrenderer/postprocessing/hw_shaderprogram.h"
class FBloomExtractShader
{
public:
void Bind(IRenderQueue *q);
struct UniformBlock
{
FVector2 Scale;
FVector2 Offset;
static std::vector<UniformFieldDesc> Desc()
{
return
{
{ "Scale", UniformType::Vec2, offsetof(UniformBlock, Scale) },
{ "Offset", UniformType::Vec2, offsetof(UniformBlock, Offset) }
};
}
};
ShaderUniforms<UniformBlock, POSTPROCESS_BINDINGPOINT> Uniforms;
private:
std::unique_ptr<IShaderProgram> mShader;
};
class FBloomCombineShader
{
public:
void Bind(IRenderQueue *q);
private:
std::unique_ptr<IShaderProgram> mShader;
};
#endif

View file

@ -1,50 +0,0 @@
//
//---------------------------------------------------------------------------
//
// Copyright(C) 2016 Magnus Norddahl
// All rights reserved.
//
// This program 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.
//
// This program 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 Lesser General Public License
// along with this program. If not, see http://www.gnu.org/licenses/
//
//--------------------------------------------------------------------------
//
/*
** gl_blurshader.cpp
** Gaussian blur shader
**
*/
#include "v_video.h"
#include "hw_blurshader.h"
void FBlurShader::Bind(IRenderQueue *q, bool vertical)
{
if (!mShader[vertical])
{
FString prolog = Uniforms[vertical].CreateDeclaration("Uniforms", UniformBlock::Desc());
if (vertical)
prolog += "#define BLUR_VERTICAL\n";
else
prolog += "#define BLUR_HORIZONTAL\n";
mShader[vertical].reset(screen->CreateShaderProgram());
mShader[vertical]->Compile(IShaderProgram::Vertex, "shaders/glsl/screenquad.vp", "", 330);
mShader[vertical]->Compile(IShaderProgram::Fragment, "shaders/glsl/blur.fp", prolog, 330);
mShader[vertical]->Link("shaders/glsl/blur");
mShader[vertical]->SetUniformBufferLocation(POSTPROCESS_BINDINGPOINT, "Uniforms");
Uniforms[vertical].Init();
}
mShader[vertical]->Bind(q);
}

View file

@ -1,39 +0,0 @@
#pragma once
#include "hwrenderer/postprocessing/hw_shaderprogram.h"
class FGLRenderer;
class PPFrameBuffer;
class PPTexture;
class FBlurShader
{
public:
void Bind(IRenderQueue *q, bool vertical);
struct UniformBlock
{
float SampleWeights[8];
static std::vector<UniformFieldDesc> Desc()
{
return
{
{ "SampleWeights0", UniformType::Float, offsetof(UniformBlock, SampleWeights[0]) },
{ "SampleWeights1", UniformType::Float, offsetof(UniformBlock, SampleWeights[1]) },
{ "SampleWeights2", UniformType::Float, offsetof(UniformBlock, SampleWeights[2]) },
{ "SampleWeights3", UniformType::Float, offsetof(UniformBlock, SampleWeights[3]) },
{ "SampleWeights4", UniformType::Float, offsetof(UniformBlock, SampleWeights[4]) },
{ "SampleWeights5", UniformType::Float, offsetof(UniformBlock, SampleWeights[5]) },
{ "SampleWeights6", UniformType::Float, offsetof(UniformBlock, SampleWeights[6]) },
{ "SampleWeights7", UniformType::Float, offsetof(UniformBlock, SampleWeights[7]) },
};
}
};
ShaderUniforms<UniformBlock, POSTPROCESS_BINDINGPOINT> Uniforms[2];
private:
std::unique_ptr<IShaderProgram> mShader[2];
};

View file

@ -61,11 +61,11 @@ void PPBloom::UpdateSteps(int fixedcm)
auto &level0 = levels[0];
// Extract blooming pixels from scene texture:
step.Viewport = level0.Viewport;
step.SetInputCurrent(0, PPFilterMode::Linear);
step.SetInputTexture(1, "ExposureTexture");
step.ShaderName = "BloomExtract";
step.Uniforms.Set(extractUniforms);
step.Viewport = level0.Viewport;
step.SetInputCurrent(0, PPFilterMode::Linear);
step.SetInputTexture(1, "Exposure.CameraTexture");
step.SetOutputTexture(level0.VTexture);
step.SetNoBlend();
steps.Push(step);
@ -93,10 +93,12 @@ void PPBloom::UpdateSteps(int fixedcm)
steps.Push(BlurStep(blurUniforms, level.HTexture, level.VTexture, level.Viewport, true));
// Linear upscale:
step.SetInputTexture(0, next.VTexture, PPFilterMode::Linear);
step.SetOutputTexture(next.HTexture);
step.Viewport = next.Viewport;
step.ShaderName = "BloomCombine";
step.Uniforms.Clear();
step.Viewport = next.Viewport;
step.SetInputTexture(0, level.VTexture, PPFilterMode::Linear);
step.SetOutputTexture(next.VTexture);
step.SetNoBlend();
steps.Push(step);
}
@ -104,23 +106,103 @@ void PPBloom::UpdateSteps(int fixedcm)
steps.Push(BlurStep(blurUniforms, level0.HTexture, level0.VTexture, level0.Viewport, true));
// Add bloom back to scene texture:
step.ShaderName = "BloomCombine";
step.Uniforms.Clear();
step.Viewport = screen->mSceneViewport;
step.SetInputTexture(0, level0.VTexture, PPFilterMode::Linear);
step.SetOutputCurrent();
step.Viewport = screen->mSceneViewport;
step.ShaderName = "BloomCombine";
step.SetAdditiveBlend();
steps.Push(step);
hw_postprocess.Effects["BloomScene"] = steps;
}
void PPBloom::UpdateBlurSteps(float gameinfobluramount)
{
// first, respect the CVar
float blurAmount = gl_menu_blur;
// if CVar is negative, use the gameinfo entry
if (gl_menu_blur < 0)
blurAmount = gameinfobluramount;
// if blurAmount == 0 or somehow still returns negative, exit to prevent a crash, clearly we don't want this
if (blurAmount <= 0.0)
{
hw_postprocess.Effects["BlurScene"] = {};
return;
}
TArray<PPStep> steps;
PPStep step;
int numLevels = 3;
assert(numLevels <= NumBloomLevels);
const auto &level0 = levels[0];
// Grab the area we want to bloom:
step.ShaderName = "BloomCombine";
step.Uniforms.Clear();
step.Viewport = level0.Viewport;
step.SetInputCurrent(0, PPFilterMode::Linear);
step.SetOutputTexture(level0.VTexture);
step.SetNoBlend();
steps.Push(step);
BlurUniforms blurUniforms;
ComputeBlurSamples(7, blurAmount, blurUniforms.SampleWeights);
// Blur and downscale:
for (int i = 0; i < numLevels - 1; i++)
{
auto &level = levels[i];
auto &next = levels[i + 1];
steps.Push(BlurStep(blurUniforms, level.VTexture, level.HTexture, level.Viewport, false));
steps.Push(BlurStep(blurUniforms, level.HTexture, next.VTexture, next.Viewport, true));
}
// Blur and upscale:
for (int i = numLevels - 1; i > 0; i--)
{
auto &level = levels[i];
auto &next = levels[i - 1];
steps.Push(BlurStep(blurUniforms, level.VTexture, level.HTexture, level.Viewport, false));
steps.Push(BlurStep(blurUniforms, level.HTexture, level.VTexture, level.Viewport, true));
// Linear upscale:
step.ShaderName = "BloomCombine";
step.Uniforms.Clear();
step.Viewport = next.Viewport;
step.SetInputTexture(0, level.VTexture, PPFilterMode::Linear);
step.SetOutputTexture(next.VTexture);
step.SetNoBlend();
steps.Push(step);
}
steps.Push(BlurStep(blurUniforms, level0.VTexture, level0.HTexture, level0.Viewport, false));
steps.Push(BlurStep(blurUniforms, level0.HTexture, level0.VTexture, level0.Viewport, true));
// Copy blur back to scene texture:
step.ShaderName = "BloomCombine";
step.Uniforms.Clear();
step.Viewport = screen->mScreenViewport;
step.SetInputTexture(0, level0.VTexture, PPFilterMode::Linear);
step.SetOutputCurrent();
step.SetNoBlend();
steps.Push(step);
hw_postprocess.Effects["BlurScene"] = steps;
}
PPStep PPBloom::BlurStep(const BlurUniforms &blurUniforms, PPTextureName input, PPTextureName output, PPViewport viewport, bool vertical)
{
PPStep step;
step.Viewport = viewport;
step.SetInputTexture(0, input);
step.ShaderName = vertical ? "BlurVertical" : "BlurHorizontal";
step.Uniforms.Set(blurUniforms);
step.Viewport = viewport;
step.SetInputTexture(0, input);
step.SetOutputTexture(output);
step.SetNoBlend();
return step;
@ -202,12 +284,12 @@ void PPLensDistort::UpdateSteps()
TArray<PPStep> steps;
PPStep step;
step.ShaderName = "Lens";
step.Uniforms.Set(uniforms);
step.Viewport = screen->mScreenViewport;
step.SetInputCurrent(0, PPFilterMode::Linear);
step.SetOutputNext();
step.SetNoBlend();
step.Uniforms.Set(uniforms);
step.Viewport = screen->mScreenViewport;
step.ShaderName = "Lens";
steps.Push(step);
hw_postprocess.Effects["LensDistortScene"] = steps;
@ -235,16 +317,20 @@ void PPFXAA::UpdateSteps()
TArray<PPStep> steps;
PPStep step;
step.ShaderName = "FXAALuma";
step.Uniforms.Clear();
step.Viewport = screen->mScreenViewport;
step.SetInputCurrent(0, PPFilterMode::Nearest);
step.SetOutputNext();
step.SetNoBlend();
step.Viewport = screen->mScreenViewport;
step.ShaderName = "FXAALuma";
steps.Push(step);
step.SetInputCurrent(0, PPFilterMode::Linear);
step.Uniforms.Set(uniforms);
step.ShaderName = "FXAA";
step.Uniforms.Set(uniforms);
step.Viewport = screen->mScreenViewport;
step.SetInputCurrent(0, PPFilterMode::Linear);
step.SetOutputNext();
step.SetNoBlend();
steps.Push(step);
hw_postprocess.Effects["ApplyFXAA"] = steps;
@ -281,3 +367,114 @@ FString PPFXAA::GetDefines()
return result;
}
/////////////////////////////////////////////////////////////////////////////
void PPCameraExposure::DeclareShaders()
{
hw_postprocess.Shaders["ExposureExtract"] = { "shaders/glsl/exposureextract.fp", "", ExposureExtractUniforms::Desc() };
hw_postprocess.Shaders["ExposureAverage"] = { "shaders/glsl/exposureaverage.fp", "", {}, 400 };
hw_postprocess.Shaders["ExposureCombine"] = { "shaders/glsl/exposurecombine.fp", "", ExposureCombineUniforms::Desc() };
}
void PPCameraExposure::UpdateTextures(int width, int height)
{
if (ExposureLevels.Size() > 0 && ExposureLevels[0].Viewport.width == width && ExposureLevels[0].Viewport.height == height)
{
return;
}
ExposureLevels.Clear();
int i = 0;
do
{
width = MAX(width / 2, 1);
height = MAX(height / 2, 1);
PPExposureLevel level;
level.Viewport.left = 0;
level.Viewport.top = 0;
level.Viewport.width = width;
level.Viewport.height = height;
level.Texture.Format("Exposure.Level.%d", i);
ExposureLevels.Push(level);
PPTextureDesc texture = { level.Viewport.width, level.Viewport.height, PixelFormat::R32f };
hw_postprocess.Textures[level.Texture] = texture;
i++;
} while (width > 1 || height > 1);
hw_postprocess.Textures["Exposure.CameraTexture"] = { 1, 1, PixelFormat::R32f };
FirstExposureFrame = true;
}
void PPCameraExposure::UpdateSteps()
{
if (!gl_bloom && gl_tonemap == 0)
{
hw_postprocess.Effects["UpdateCameraExposure"] = {};
return;
}
TArray<PPStep> steps;
PPStep step;
ExposureExtractUniforms extractUniforms;
extractUniforms.Scale = screen->SceneScale();
extractUniforms.Offset = screen->SceneOffset();
ExposureCombineUniforms combineUniforms;
combineUniforms.ExposureBase = gl_exposure_base;
combineUniforms.ExposureMin = gl_exposure_min;
combineUniforms.ExposureScale = gl_exposure_scale;
combineUniforms.ExposureSpeed = gl_exposure_speed;
auto &level0 = ExposureLevels[0];
// Extract light level from scene texture:
step.ShaderName = "ExposureExtract";
step.Uniforms.Set(extractUniforms);
step.Viewport = level0.Viewport;
step.SetInputCurrent(0, PPFilterMode::Linear);
step.SetOutputTexture(level0.Texture);
step.SetNoBlend();
steps.Push(step);
// Find the average value:
for (unsigned int i = 0; i + 1 < ExposureLevels.Size(); i++)
{
auto &level = ExposureLevels[i];
auto &next = ExposureLevels[i + 1];
step.ShaderName = "ExposureAverage";
step.Uniforms.Clear();
step.Viewport = next.Viewport;
step.SetInputTexture(0, level.Texture, PPFilterMode::Linear);
step.SetOutputTexture(next.Texture);
step.SetNoBlend();
steps.Push(step);
}
// Combine average value with current camera exposure:
step.ShaderName = "ExposureCombine";
step.Uniforms.Set(combineUniforms);
step.Viewport.left = 0;
step.Viewport.top = 0;
step.Viewport.width = 1;
step.Viewport.height = 1;
step.SetInputTexture(0, ExposureLevels.Last().Texture, PPFilterMode::Linear);
step.SetOutputTexture("Exposure.CameraTexture");
if (!FirstExposureFrame)
step.SetAlphaBlend();
else
step.SetNoBlend();
steps.Push(step);
FirstExposureFrame = false;
hw_postprocess.Effects["UpdateCameraExposure"] = steps;
}

View file

@ -45,7 +45,7 @@ public:
~PPUniforms()
{
delete[] Data;
Clear();
}
PPUniforms &operator=(const PPUniforms &src)
@ -69,6 +69,13 @@ public:
return *this;
}
void Clear()
{
delete[] Data;
Data = nullptr;
Size = 0;
}
template<typename T>
void Set(const T &v)
{
@ -145,6 +152,14 @@ public:
BlendMode.Flags = 0;
}
void SetAlphaBlend()
{
BlendMode.BlendOp = STYLEOP_Add;
BlendMode.SrcAlpha = STYLEALPHA_Src;
BlendMode.DestAlpha = STYLEALPHA_InvSrc;
BlendMode.Flags = 0;
}
PPShaderName ShaderName;
TArray<PPTextureInput> Textures;
PPUniforms Uniforms;
@ -156,7 +171,8 @@ public:
enum class PixelFormat
{
Rgba8,
Rgba16f
Rgba16f,
R32f
};
class PPTextureDesc
@ -246,6 +262,7 @@ public:
void DeclareShaders();
void UpdateTextures(int sceneWidth, int sceneHeight);
void UpdateSteps(int fixedcm);
void UpdateBlurSteps(float gameinfobluramount);
private:
PPStep BlurStep(const BlurUniforms &blurUniforms, PPTextureName input, PPTextureName output, PPViewport viewport, bool vertical);
@ -315,3 +332,58 @@ private:
int GetMaxVersion();
FString GetDefines();
};
/////////////////////////////////////////////////////////////////////////////
struct ExposureExtractUniforms
{
FVector2 Scale;
FVector2 Offset;
static std::vector<UniformFieldDesc> Desc()
{
return
{
{ "Scale", UniformType::Vec2, offsetof(ExposureExtractUniforms, Scale) },
{ "Offset", UniformType::Vec2, offsetof(ExposureExtractUniforms, Offset) }
};
}
};
struct ExposureCombineUniforms
{
float ExposureBase;
float ExposureMin;
float ExposureScale;
float ExposureSpeed;
static std::vector<UniformFieldDesc> Desc()
{
return
{
{ "ExposureBase", UniformType::Float, offsetof(ExposureCombineUniforms, ExposureBase) },
{ "ExposureMin", UniformType::Float, offsetof(ExposureCombineUniforms, ExposureMin) },
{ "ExposureScale", UniformType::Float, offsetof(ExposureCombineUniforms, ExposureScale) },
{ "ExposureSpeed", UniformType::Float, offsetof(ExposureCombineUniforms, ExposureSpeed) }
};
}
};
class PPExposureLevel
{
public:
PPViewport Viewport;
PPTextureName Texture;
};
class PPCameraExposure
{
public:
void DeclareShaders();
void UpdateTextures(int sceneWidth, int sceneHeight);
void UpdateSteps();
private:
TArray<PPExposureLevel> ExposureLevels;
bool FirstExposureFrame = true;
};

View file

@ -61,47 +61,3 @@ const char *FTonemapShader::GetDefines(int mode)
case Palette: return "#define PALETTE\n";
}
}
void FExposureExtractShader::Bind(IRenderQueue *q)
{
if (!mShader)
{
FString prolog = Uniforms.CreateDeclaration("Uniforms", UniformBlock::Desc());
mShader.reset(screen->CreateShaderProgram());
mShader->Compile(IShaderProgram::Vertex, "shaders/glsl/screenquad.vp", "", 330);
mShader->Compile(IShaderProgram::Fragment, "shaders/glsl/exposureextract.fp", prolog, 330);
mShader->Link("shaders/glsl/exposureextract");
mShader->SetUniformBufferLocation(Uniforms.BindingPoint(), "Uniforms");
Uniforms.Init();
}
mShader->Bind(q);
}
void FExposureAverageShader::Bind(IRenderQueue *q)
{
if (!mShader)
{
mShader.reset(screen->CreateShaderProgram());
mShader->Compile(IShaderProgram::Vertex, "shaders/glsl/screenquad.vp", "", 400);
mShader->Compile(IShaderProgram::Fragment, "shaders/glsl/exposureaverage.fp", "", 400);
mShader->Link("shaders/glsl/exposureaverage");
}
mShader->Bind(q);
}
void FExposureCombineShader::Bind(IRenderQueue *q)
{
if (!mShader)
{
FString prolog = Uniforms.CreateDeclaration("Uniforms", UniformBlock::Desc());
mShader.reset(screen->CreateShaderProgram());
mShader->Compile(IShaderProgram::Vertex, "shaders/glsl/screenquad.vp", "", 330);
mShader->Compile(IShaderProgram::Fragment, "shaders/glsl/exposurecombine.fp", prolog, 330);
mShader->Link("shaders/glsl/exposurecombine");
mShader->SetUniformBufferLocation(Uniforms.BindingPoint(), "Uniforms");
Uniforms.Init();
}
mShader->Bind(q);
}

View file

@ -27,69 +27,4 @@ private:
std::unique_ptr<IShaderProgram> mShader[NumTonemapModes];
};
class FExposureExtractShader
{
public:
void Bind(IRenderQueue *q);
struct UniformBlock
{
FVector2 Scale;
FVector2 Offset;
static std::vector<UniformFieldDesc> Desc()
{
return
{
{ "Scale", UniformType::Vec2, offsetof(UniformBlock, Scale) },
{ "Offset", UniformType::Vec2, offsetof(UniformBlock, Offset) }
};
}
};
ShaderUniforms<UniformBlock, POSTPROCESS_BINDINGPOINT> Uniforms;
private:
std::unique_ptr<IShaderProgram> mShader;
};
class FExposureAverageShader
{
public:
void Bind(IRenderQueue *q);
private:
std::unique_ptr<IShaderProgram> mShader;
};
class FExposureCombineShader
{
public:
void Bind(IRenderQueue *q);
struct UniformBlock
{
float ExposureBase;
float ExposureMin;
float ExposureScale;
float ExposureSpeed;
static std::vector<UniformFieldDesc> Desc()
{
return
{
{ "ExposureBase", UniformType::Float, offsetof(UniformBlock, ExposureBase) },
{ "ExposureMin", UniformType::Float, offsetof(UniformBlock, ExposureMin) },
{ "ExposureScale", UniformType::Float, offsetof(UniformBlock, ExposureScale) },
{ "ExposureSpeed", UniformType::Float, offsetof(UniformBlock, ExposureSpeed) }
};
}
};
ShaderUniforms<UniformBlock, POSTPROCESS_BINDINGPOINT> Uniforms;
private:
std::unique_ptr<IShaderProgram> mShader;
};
#endif