- convert the SSAO pass to use hw_postprocess
This commit is contained in:
parent
ecb5d69ae3
commit
35c13763db
11 changed files with 464 additions and 553 deletions
|
|
@ -1,138 +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/
|
||||
//
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
|
||||
#include "v_video.h"
|
||||
#include "hwrenderer/utility/hw_cvars.h"
|
||||
#include "hw_ambientshader.h"
|
||||
|
||||
void FLinearDepthShader::Bind(IRenderQueue *q)
|
||||
{
|
||||
bool multisample = (gl_multisample > 1);
|
||||
if (mMultisample != multisample)
|
||||
mShader.reset();
|
||||
|
||||
if (!mShader)
|
||||
{
|
||||
FString prolog = Uniforms.CreateDeclaration("Uniforms", UniformBlock::Desc());
|
||||
if (multisample) prolog += "#define MULTISAMPLE\n";
|
||||
|
||||
mShader.reset(screen->CreateShaderProgram());
|
||||
mShader->Compile(IShaderProgram::Vertex, "shaders/glsl/screenquad.vp", "", 330);
|
||||
mShader->Compile(IShaderProgram::Fragment, "shaders/glsl/lineardepth.fp", prolog, 330);
|
||||
mShader->Link("shaders/glsl/lineardepth");
|
||||
mShader->SetUniformBufferLocation(Uniforms.BindingPoint(), "Uniforms");
|
||||
Uniforms.Init();
|
||||
mMultisample = multisample;
|
||||
}
|
||||
mShader->Bind(q);
|
||||
}
|
||||
|
||||
void FSSAOShader::Bind(IRenderQueue *q)
|
||||
{
|
||||
bool multisample = (gl_multisample > 1);
|
||||
if (mCurrentQuality != gl_ssao || mMultisample != multisample)
|
||||
mShader.reset();
|
||||
|
||||
if (!mShader)
|
||||
{
|
||||
FString prolog = Uniforms.CreateDeclaration("Uniforms", UniformBlock::Desc());
|
||||
prolog += GetDefines(gl_ssao, multisample);
|
||||
|
||||
mShader.reset(screen->CreateShaderProgram());
|
||||
mShader->Compile(IShaderProgram::Vertex, "shaders/glsl/screenquad.vp", "", 330);
|
||||
mShader->Compile(IShaderProgram::Fragment, "shaders/glsl/ssao.fp", prolog, 330);
|
||||
mShader->Link("shaders/glsl/ssao");
|
||||
mShader->SetUniformBufferLocation(Uniforms.BindingPoint(), "Uniforms");
|
||||
Uniforms.Init();
|
||||
mMultisample = multisample;
|
||||
}
|
||||
mShader->Bind(q);
|
||||
}
|
||||
|
||||
FString FSSAOShader::GetDefines(int mode, bool multisample)
|
||||
{
|
||||
// Must match quality values in FGLRenderBuffers::CreateAmbientOcclusion
|
||||
int numDirections, numSteps;
|
||||
switch (gl_ssao)
|
||||
{
|
||||
default:
|
||||
case LowQuality: numDirections = 2; numSteps = 4; break;
|
||||
case MediumQuality: numDirections = 4; numSteps = 4; break;
|
||||
case HighQuality: numDirections = 8; numSteps = 4; break;
|
||||
}
|
||||
|
||||
FString defines;
|
||||
defines.Format(R"(
|
||||
#define USE_RANDOM_TEXTURE
|
||||
#define RANDOM_TEXTURE_WIDTH 4.0
|
||||
#define NUM_DIRECTIONS %d.0
|
||||
#define NUM_STEPS %d.0
|
||||
)", numDirections, numSteps);
|
||||
|
||||
if (multisample)
|
||||
defines += "\n#define MULTISAMPLE\n";
|
||||
return defines;
|
||||
}
|
||||
|
||||
void FDepthBlurShader::Bind(IRenderQueue *q, bool vertical)
|
||||
{
|
||||
auto &shader = mShader[vertical];
|
||||
if (!shader)
|
||||
{
|
||||
FString prolog = Uniforms[vertical].CreateDeclaration("Uniforms", UniformBlock::Desc());
|
||||
if (vertical)
|
||||
prolog += "#define BLUR_VERTICAL\n";
|
||||
else
|
||||
prolog += "#define BLUR_HORIZONTAL\n";
|
||||
|
||||
shader.reset(screen->CreateShaderProgram());
|
||||
shader->Compile(IShaderProgram::Vertex, "shaders/glsl/screenquad.vp", "", 330);
|
||||
shader->Compile(IShaderProgram::Fragment, "shaders/glsl/depthblur.fp", prolog, 330);
|
||||
shader->Link("shaders/glsl/depthblur");
|
||||
shader->SetUniformBufferLocation(Uniforms[vertical].BindingPoint(), "Uniforms");
|
||||
Uniforms[vertical].Init();
|
||||
}
|
||||
shader->Bind(q);
|
||||
}
|
||||
|
||||
void FSSAOCombineShader::Bind(IRenderQueue *q)
|
||||
{
|
||||
bool multisample = (gl_multisample > 1);
|
||||
if (mMultisample != multisample)
|
||||
mShader.reset();
|
||||
|
||||
if (!mShader)
|
||||
{
|
||||
FString prolog = Uniforms.CreateDeclaration("Uniforms", UniformBlock::Desc());
|
||||
if (multisample)
|
||||
prolog += "#define MULTISAMPLE\n";
|
||||
|
||||
mShader.reset(screen->CreateShaderProgram());
|
||||
mShader->Compile(IShaderProgram::Vertex, "shaders/glsl/screenquad.vp", "", 330);
|
||||
mShader->Compile(IShaderProgram::Fragment, "shaders/glsl/ssaocombine.fp", prolog, 330);
|
||||
mShader->Link("shaders/glsl/ssaocombine");
|
||||
mShader->SetUniformBufferLocation(Uniforms.BindingPoint(), "Uniforms");
|
||||
Uniforms.Init();
|
||||
mMultisample = multisample;
|
||||
}
|
||||
mShader->Bind(q);
|
||||
}
|
||||
|
|
@ -1,168 +0,0 @@
|
|||
#ifndef __GL_AMBIENTSHADER_H
|
||||
#define __GL_AMBIENTSHADER_H
|
||||
|
||||
#include "hwrenderer/postprocessing/hw_shaderprogram.h"
|
||||
|
||||
class FLinearDepthShader
|
||||
{
|
||||
public:
|
||||
void Bind(IRenderQueue *q);
|
||||
|
||||
struct UniformBlock
|
||||
{
|
||||
int SampleIndex;
|
||||
float LinearizeDepthA;
|
||||
float LinearizeDepthB;
|
||||
float InverseDepthRangeA;
|
||||
float InverseDepthRangeB;
|
||||
float Padding0, Padding1, Padding2;
|
||||
FVector2 Scale;
|
||||
FVector2 Offset;
|
||||
|
||||
static std::vector<UniformFieldDesc> Desc()
|
||||
{
|
||||
return
|
||||
{
|
||||
{ "SampleIndex", UniformType::Int, offsetof(UniformBlock, SampleIndex) },
|
||||
{ "LinearizeDepthA", UniformType::Float, offsetof(UniformBlock, LinearizeDepthA) },
|
||||
{ "LinearizeDepthB", UniformType::Float, offsetof(UniformBlock, LinearizeDepthB) },
|
||||
{ "InverseDepthRangeA", UniformType::Float, offsetof(UniformBlock, InverseDepthRangeA) },
|
||||
{ "InverseDepthRangeB", UniformType::Float, offsetof(UniformBlock, InverseDepthRangeB) },
|
||||
{ "Padding0", UniformType::Float, offsetof(UniformBlock, Padding0) },
|
||||
{ "Padding1", UniformType::Float, offsetof(UniformBlock, Padding1) },
|
||||
{ "Padding2", UniformType::Float, offsetof(UniformBlock, Padding2) },
|
||||
{ "Scale", UniformType::Vec2, offsetof(UniformBlock, Scale) },
|
||||
{ "Offset", UniformType::Vec2, offsetof(UniformBlock, Offset) }
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
ShaderUniforms<UniformBlock, POSTPROCESS_BINDINGPOINT> Uniforms;
|
||||
|
||||
private:
|
||||
std::unique_ptr<IShaderProgram> mShader;
|
||||
bool mMultisample = false;
|
||||
};
|
||||
|
||||
class FSSAOShader
|
||||
{
|
||||
public:
|
||||
void Bind(IRenderQueue *q);
|
||||
|
||||
struct UniformBlock
|
||||
{
|
||||
FVector2 UVToViewA;
|
||||
FVector2 UVToViewB;
|
||||
FVector2 InvFullResolution;
|
||||
float NDotVBias;
|
||||
float NegInvR2;
|
||||
float RadiusToScreen;
|
||||
float AOMultiplier;
|
||||
float AOStrength;
|
||||
int SampleIndex;
|
||||
float Padding0, Padding1;
|
||||
FVector2 Scale;
|
||||
FVector2 Offset;
|
||||
|
||||
static std::vector<UniformFieldDesc> Desc()
|
||||
{
|
||||
return
|
||||
{
|
||||
{ "UVToViewA", UniformType::Vec2, offsetof(UniformBlock, UVToViewA) },
|
||||
{ "UVToViewB", UniformType::Vec2, offsetof(UniformBlock, UVToViewB) },
|
||||
{ "InvFullResolution", UniformType::Vec2, offsetof(UniformBlock, InvFullResolution) },
|
||||
{ "NDotVBias", UniformType::Float, offsetof(UniformBlock, NDotVBias) },
|
||||
{ "NegInvR2", UniformType::Float, offsetof(UniformBlock, NegInvR2) },
|
||||
{ "RadiusToScreen", UniformType::Float, offsetof(UniformBlock, RadiusToScreen) },
|
||||
{ "AOMultiplier", UniformType::Float, offsetof(UniformBlock, AOMultiplier) },
|
||||
{ "AOStrength", UniformType::Float, offsetof(UniformBlock, AOStrength) },
|
||||
{ "SampleIndex", UniformType::Int, offsetof(UniformBlock, SampleIndex) },
|
||||
{ "Padding0", UniformType::Float, offsetof(UniformBlock, Padding0) },
|
||||
{ "Padding1", UniformType::Float, offsetof(UniformBlock, Padding1) },
|
||||
{ "Scale", UniformType::Vec2, offsetof(UniformBlock, Scale) },
|
||||
{ "Offset", UniformType::Vec2, offsetof(UniformBlock, Offset) },
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
ShaderUniforms<UniformBlock, POSTPROCESS_BINDINGPOINT> Uniforms;
|
||||
|
||||
private:
|
||||
enum Quality
|
||||
{
|
||||
Off,
|
||||
LowQuality,
|
||||
MediumQuality,
|
||||
HighQuality,
|
||||
NumQualityModes
|
||||
};
|
||||
|
||||
FString GetDefines(int mode, bool multisample);
|
||||
|
||||
std::unique_ptr<IShaderProgram> mShader;
|
||||
Quality mCurrentQuality = Off;
|
||||
bool mMultisample = false;
|
||||
};
|
||||
|
||||
class FDepthBlurShader
|
||||
{
|
||||
public:
|
||||
void Bind(IRenderQueue *q, bool vertical);
|
||||
|
||||
struct UniformBlock
|
||||
{
|
||||
float BlurSharpness;
|
||||
float PowExponent;
|
||||
FVector2 InvFullResolution;
|
||||
|
||||
static std::vector<UniformFieldDesc> Desc()
|
||||
{
|
||||
return
|
||||
{
|
||||
{ "BlurSharpness", UniformType::Float, offsetof(UniformBlock, BlurSharpness) },
|
||||
{ "PowExponent", UniformType::Float, offsetof(UniformBlock, PowExponent) },
|
||||
{ "InvFullResolution", UniformType::Vec2, offsetof(UniformBlock, InvFullResolution) }
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
ShaderUniforms<UniformBlock, POSTPROCESS_BINDINGPOINT> Uniforms[2];
|
||||
|
||||
private:
|
||||
std::unique_ptr<IShaderProgram> mShader[2];
|
||||
};
|
||||
|
||||
class FSSAOCombineShader
|
||||
{
|
||||
public:
|
||||
void Bind(IRenderQueue *q);
|
||||
|
||||
struct UniformBlock
|
||||
{
|
||||
int SampleCount;
|
||||
int Padding0, Padding1, Padding2;
|
||||
FVector2 Scale;
|
||||
FVector2 Offset;
|
||||
|
||||
static std::vector<UniformFieldDesc> Desc()
|
||||
{
|
||||
return
|
||||
{
|
||||
{ "SampleCount", UniformType::Int, offsetof(UniformBlock, SampleCount) },
|
||||
{ "Padding0", UniformType::Int, offsetof(UniformBlock, Padding0) },
|
||||
{ "Padding1", UniformType::Int, offsetof(UniformBlock, Padding1) },
|
||||
{ "Padding2", UniformType::Int, offsetof(UniformBlock, Padding2) },
|
||||
{ "Scale", UniformType::Vec2, offsetof(UniformBlock, Scale) },
|
||||
{ "Offset", UniformType::Vec2, offsetof(UniformBlock, Offset) }
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
ShaderUniforms<UniformBlock, POSTPROCESS_BINDINGPOINT> Uniforms;
|
||||
|
||||
private:
|
||||
std::unique_ptr<IShaderProgram> mShader;
|
||||
bool mMultisample = false;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -3,6 +3,7 @@
|
|||
#include "hw_postprocess.h"
|
||||
#include "hwrenderer/utility/hw_cvars.h"
|
||||
#include "hwrenderer/postprocessing/hw_postprocess_cvars.h"
|
||||
#include <random>
|
||||
|
||||
Postprocess hw_postprocess;
|
||||
|
||||
|
|
@ -558,8 +559,7 @@ void PPTonemap::UpdateTextures()
|
|||
{
|
||||
if (gl_tonemap == Palette)
|
||||
{
|
||||
auto &texture = hw_postprocess.Textures["Tonemap.Palette"];
|
||||
if (!texture.Data)
|
||||
if (!hw_postprocess.Textures.CheckKey("Tonemap.Palette"))
|
||||
{
|
||||
std::shared_ptr<void> data(new uint32_t[512 * 512], [](void *p) { delete[](uint32_t*)p; });
|
||||
|
||||
|
|
@ -581,7 +581,7 @@ void PPTonemap::UpdateTextures()
|
|||
}
|
||||
}
|
||||
|
||||
texture = { 512, 512, PixelFormat::Rgba8, data };
|
||||
hw_postprocess.Textures["Tonemap.Palette"] = { 512, 512, PixelFormat::Rgba8, data };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -618,3 +618,218 @@ void PPTonemap::UpdateSteps()
|
|||
steps.Push(step);
|
||||
hw_postprocess.Effects["TonemapScene"] = steps;
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void PPAmbientOcclusion::DeclareShaders()
|
||||
{
|
||||
// Must match quality values in PPAmbientOcclusion::UpdateTextures
|
||||
int numDirections, numSteps;
|
||||
switch (gl_ssao)
|
||||
{
|
||||
default:
|
||||
case LowQuality: numDirections = 2; numSteps = 4; break;
|
||||
case MediumQuality: numDirections = 4; numSteps = 4; break;
|
||||
case HighQuality: numDirections = 8; numSteps = 4; break;
|
||||
}
|
||||
|
||||
FString defines;
|
||||
defines.Format(R"(
|
||||
#define USE_RANDOM_TEXTURE
|
||||
#define RANDOM_TEXTURE_WIDTH 4.0
|
||||
#define NUM_DIRECTIONS %d.0
|
||||
#define NUM_STEPS %d.0
|
||||
)", numDirections, numSteps);
|
||||
|
||||
hw_postprocess.Shaders["SSAO.LinearDepth"] = { "shaders/glsl/lineardepth.fp", "", LinearDepthUniforms::Desc() };
|
||||
hw_postprocess.Shaders["SSAO.LinearDepthMS"] = { "shaders/glsl/lineardepth.fp", "#define MULTISAMPLE\n", LinearDepthUniforms::Desc() };
|
||||
hw_postprocess.Shaders["SSAO.AmbientOcclude"] = { "shaders/glsl/ssao.fp", defines, SSAOUniforms::Desc() };
|
||||
hw_postprocess.Shaders["SSAO.AmbientOccludeMS"] = { "shaders/glsl/ssao.fp", defines + "\n#define MULTISAMPLE\n", SSAOUniforms::Desc() };
|
||||
hw_postprocess.Shaders["SSAO.BlurVertical"] = { "shaders/glsl/depthblur.fp", "#define BLUR_VERTICAL\n", DepthBlurUniforms::Desc() };
|
||||
hw_postprocess.Shaders["SSAO.BlurHorizontal"] = { "shaders/glsl/depthblur.fp", "#define BLUR_HORIZONTAL\n", DepthBlurUniforms::Desc() };
|
||||
hw_postprocess.Shaders["SSAO.Combine"] = { "shaders/glsl/ssaocombine.fp", "", AmbientCombineUniforms::Desc() };
|
||||
hw_postprocess.Shaders["SSAO.CombineMS"] = { "shaders/glsl/ssaocombine.fp", "#define MULTISAMPLE\n", AmbientCombineUniforms::Desc() };
|
||||
}
|
||||
|
||||
void PPAmbientOcclusion::UpdateTextures()
|
||||
{
|
||||
int width = hw_postprocess.SceneWidth;
|
||||
int height = hw_postprocess.SceneHeight;
|
||||
|
||||
if (width <= 0 || height <= 0)
|
||||
return;
|
||||
|
||||
AmbientWidth = (width + 1) / 2;
|
||||
AmbientHeight = (height + 1) / 2;
|
||||
|
||||
hw_postprocess.Textures["SSAO.LinearDepth"] = { AmbientWidth, AmbientHeight, PixelFormat::R32f };
|
||||
hw_postprocess.Textures["SSAO.Ambient0"] = { AmbientWidth, AmbientHeight, PixelFormat::Rg16f };
|
||||
hw_postprocess.Textures["SSAO.Ambient1"] = { AmbientWidth, AmbientHeight, PixelFormat::Rg16f };
|
||||
|
||||
// We only need to create the random texture once
|
||||
if (!hw_postprocess.Textures.CheckKey("SSAO.Random0"))
|
||||
{
|
||||
// Must match quality enum in PPAmbientOcclusion::DeclareShaders
|
||||
double numDirections[NumAmbientRandomTextures] = { 2.0, 4.0, 8.0 };
|
||||
|
||||
std::mt19937 generator(1337);
|
||||
std::uniform_real_distribution<double> distribution(0.0, 1.0);
|
||||
for (int quality = 0; quality < NumAmbientRandomTextures; quality++)
|
||||
{
|
||||
std::shared_ptr<void> data(new int16_t[16 * 4], [](void *p) { delete[](int16_t*)p; });
|
||||
int16_t *randomValues = (int16_t *)data.get();
|
||||
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
double angle = 2.0 * M_PI * distribution(generator) / numDirections[quality];
|
||||
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);
|
||||
}
|
||||
|
||||
FString name;
|
||||
name.Format("SSAO.Random%d", quality);
|
||||
|
||||
hw_postprocess.Textures[name] = { 4, 4, PixelFormat::Rgba16_snorm, data };
|
||||
AmbientRandomTexture[quality] = name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PPAmbientOcclusion::UpdateSteps()
|
||||
{
|
||||
if (gl_ssao == 0 || hw_postprocess.SceneWidth == 0 || hw_postprocess.SceneHeight == 0)
|
||||
{
|
||||
hw_postprocess.Effects["AmbientOccludeScene"] = {};
|
||||
return;
|
||||
}
|
||||
|
||||
float bias = gl_ssao_bias;
|
||||
float aoRadius = gl_ssao_radius;
|
||||
const float blurAmount = gl_ssao_blur;
|
||||
float aoStrength = gl_ssao_strength;
|
||||
|
||||
//float tanHalfFovy = tan(fovy * (M_PI / 360.0f));
|
||||
float tanHalfFovy = 1.0f / hw_postprocess.m5;
|
||||
float invFocalLenX = tanHalfFovy * (hw_postprocess.SceneWidth / (float)hw_postprocess.SceneHeight);
|
||||
float invFocalLenY = tanHalfFovy;
|
||||
float nDotVBias = clamp(bias, 0.0f, 1.0f);
|
||||
float r2 = aoRadius * aoRadius;
|
||||
|
||||
float blurSharpness = 1.0f / blurAmount;
|
||||
|
||||
auto sceneScale = screen->SceneScale();
|
||||
auto sceneOffset = screen->SceneOffset();
|
||||
|
||||
int randomTexture = clamp(gl_ssao - 1, 0, NumAmbientRandomTextures - 1);
|
||||
|
||||
LinearDepthUniforms linearUniforms;
|
||||
linearUniforms.SampleIndex = 0;
|
||||
linearUniforms.LinearizeDepthA = 1.0f / screen->GetZFar() - 1.0f / screen->GetZNear();
|
||||
linearUniforms.LinearizeDepthB = MAX(1.0f / screen->GetZNear(), 1.e-8f);
|
||||
linearUniforms.InverseDepthRangeA = 1.0f;
|
||||
linearUniforms.InverseDepthRangeB = 0.0f;
|
||||
linearUniforms.Scale = sceneScale;
|
||||
linearUniforms.Offset = sceneOffset;
|
||||
|
||||
SSAOUniforms ssaoUniforms;
|
||||
ssaoUniforms.SampleIndex = 0;
|
||||
ssaoUniforms.UVToViewA = { 2.0f * invFocalLenX, 2.0f * invFocalLenY };
|
||||
ssaoUniforms.UVToViewB = { -invFocalLenX, -invFocalLenY };
|
||||
ssaoUniforms.InvFullResolution = { 1.0f / AmbientWidth, 1.0f / AmbientHeight };
|
||||
ssaoUniforms.NDotVBias = nDotVBias;
|
||||
ssaoUniforms.NegInvR2 = -1.0f / r2;
|
||||
ssaoUniforms.RadiusToScreen = aoRadius * 0.5f / tanHalfFovy * AmbientHeight;
|
||||
ssaoUniforms.AOMultiplier = 1.0f / (1.0f - nDotVBias);
|
||||
ssaoUniforms.AOStrength = aoStrength;
|
||||
ssaoUniforms.Scale = sceneScale;
|
||||
ssaoUniforms.Offset = sceneOffset;
|
||||
|
||||
DepthBlurUniforms blurUniforms;
|
||||
blurUniforms.BlurSharpness = blurSharpness;
|
||||
blurUniforms.InvFullResolution = { 1.0f / AmbientWidth, 1.0f / AmbientHeight };
|
||||
blurUniforms.PowExponent = gl_ssao_exponent;
|
||||
|
||||
AmbientCombineUniforms combineUniforms;
|
||||
combineUniforms.SampleCount = gl_multisample;
|
||||
combineUniforms.Scale = screen->SceneScale();
|
||||
combineUniforms.Offset = screen->SceneOffset();
|
||||
|
||||
IntRect ambientViewport;
|
||||
ambientViewport.left = 0;
|
||||
ambientViewport.top = 0;
|
||||
ambientViewport.width = AmbientWidth;
|
||||
ambientViewport.height = AmbientHeight;
|
||||
|
||||
TArray<PPStep> steps;
|
||||
|
||||
// Calculate linear depth values
|
||||
{
|
||||
PPStep step;
|
||||
step.ShaderName = gl_multisample ? "SSAO.LinearDepthMS" : "SSAO.LinearDepth";
|
||||
step.Uniforms.Set(linearUniforms);
|
||||
step.Viewport = ambientViewport;
|
||||
step.SetInputSceneDepth(0);
|
||||
step.SetInputSceneColor(1);
|
||||
step.SetOutputTexture("SSAO.LinearDepth");
|
||||
step.SetNoBlend();
|
||||
steps.Push(step);
|
||||
}
|
||||
|
||||
// Apply ambient occlusion
|
||||
{
|
||||
PPStep step;
|
||||
step.ShaderName = gl_multisample ? "SSAO.AmbientOccludeMS" : "SSAO.AmbientOcclude";
|
||||
step.Uniforms.Set(ssaoUniforms);
|
||||
step.Viewport = ambientViewport;
|
||||
step.SetInputTexture(0, "SSAO.LinearDepth");
|
||||
step.SetInputSceneNormal(1);
|
||||
step.SetInputTexture(2, AmbientRandomTexture[randomTexture], PPFilterMode::Nearest, PPWrapMode::Repeat);
|
||||
step.SetOutputTexture("SSAO.Ambient0");
|
||||
step.SetNoBlend();
|
||||
steps.Push(step);
|
||||
}
|
||||
|
||||
// Blur SSAO texture
|
||||
if (gl_ssao_debug < 2)
|
||||
{
|
||||
PPStep step;
|
||||
step.ShaderName = "SSAO.BlurHorizontal";
|
||||
step.Uniforms.Set(blurUniforms);
|
||||
step.Viewport = ambientViewport;
|
||||
step.SetInputTexture(0, "SSAO.Ambient0");
|
||||
step.SetOutputTexture("SSAO.Ambient1");
|
||||
step.SetNoBlend();
|
||||
steps.Push(step);
|
||||
|
||||
step.ShaderName = "SSAO.BlurVertical";
|
||||
step.SetInputTexture(0, "SSAO.Ambient1");
|
||||
step.SetOutputTexture("SSAO.Ambient0");
|
||||
steps.Push(step);
|
||||
}
|
||||
|
||||
// Add SSAO back to scene texture:
|
||||
{
|
||||
PPStep step;
|
||||
step.ShaderName = gl_multisample ? "SSAO.CombineMS" : "SSAO.Combine";
|
||||
step.Uniforms.Set(combineUniforms);
|
||||
step.Viewport = screen->mSceneViewport;
|
||||
step.SetInputTexture(0, "SSAO.Ambient0", PPFilterMode::Linear);
|
||||
step.SetInputSceneFog(1);
|
||||
step.SetOutputSceneColor();
|
||||
if (gl_ssao_debug != 0)
|
||||
step.SetNoBlend();
|
||||
else
|
||||
step.SetAlphaBlend();
|
||||
steps.Push(step);
|
||||
}
|
||||
|
||||
hw_postprocess.Effects["AmbientOccludeScene"] = steps;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,12 +10,14 @@ typedef FRenderStyle PPBlendMode;
|
|||
typedef IntRect PPViewport;
|
||||
|
||||
enum class PPFilterMode { Nearest, Linear };
|
||||
enum class PPTextureType { CurrentPipelineTexture, NextPipelineTexture, PPTexture };
|
||||
enum class PPWrapMode { Clamp, Repeat };
|
||||
enum class PPTextureType { CurrentPipelineTexture, NextPipelineTexture, PPTexture, SceneColor, SceneFog, SceneNormal, SceneDepth };
|
||||
|
||||
class PPTextureInput
|
||||
{
|
||||
public:
|
||||
PPFilterMode Filter;
|
||||
PPWrapMode Wrap;
|
||||
PPTextureType Type;
|
||||
PPTextureName Texture;
|
||||
};
|
||||
|
|
@ -99,23 +101,50 @@ public:
|
|||
class PPStep
|
||||
{
|
||||
public:
|
||||
void SetInputTexture(int index, PPTextureName texture, PPFilterMode filter = PPFilterMode::Nearest)
|
||||
void SetInputTexture(int index, PPTextureName texture, PPFilterMode filter = PPFilterMode::Nearest, PPWrapMode wrap = PPWrapMode::Clamp)
|
||||
{
|
||||
if ((int)Textures.Size() < index + 1)
|
||||
Textures.Resize(index + 1);
|
||||
auto &tex = Textures[index];
|
||||
tex.Filter = filter;
|
||||
tex.Wrap = wrap;
|
||||
tex.Type = PPTextureType::PPTexture;
|
||||
tex.Texture = texture;
|
||||
}
|
||||
|
||||
void SetInputCurrent(int index, PPFilterMode filter = PPFilterMode::Nearest)
|
||||
void SetInputCurrent(int index, PPFilterMode filter = PPFilterMode::Nearest, PPWrapMode wrap = PPWrapMode::Clamp)
|
||||
{
|
||||
SetInputSpecialType(index, PPTextureType::CurrentPipelineTexture, filter, wrap);
|
||||
}
|
||||
|
||||
void SetInputSceneColor(int index, PPFilterMode filter = PPFilterMode::Nearest, PPWrapMode wrap = PPWrapMode::Clamp)
|
||||
{
|
||||
SetInputSpecialType(index, PPTextureType::SceneColor, filter, wrap);
|
||||
}
|
||||
|
||||
void SetInputSceneFog(int index, PPFilterMode filter = PPFilterMode::Nearest, PPWrapMode wrap = PPWrapMode::Clamp)
|
||||
{
|
||||
SetInputSpecialType(index, PPTextureType::SceneFog, filter, wrap);
|
||||
}
|
||||
|
||||
void SetInputSceneNormal(int index, PPFilterMode filter = PPFilterMode::Nearest, PPWrapMode wrap = PPWrapMode::Clamp)
|
||||
{
|
||||
SetInputSpecialType(index, PPTextureType::SceneNormal, filter, wrap);
|
||||
}
|
||||
|
||||
void SetInputSceneDepth(int index, PPFilterMode filter = PPFilterMode::Nearest, PPWrapMode wrap = PPWrapMode::Clamp)
|
||||
{
|
||||
SetInputSpecialType(index, PPTextureType::SceneDepth, filter, wrap);
|
||||
}
|
||||
|
||||
void SetInputSpecialType(int index, PPTextureType type, PPFilterMode filter = PPFilterMode::Nearest, PPWrapMode wrap = PPWrapMode::Clamp)
|
||||
{
|
||||
if ((int)Textures.Size() < index + 1)
|
||||
Textures.Resize(index + 1);
|
||||
auto &tex = Textures[index];
|
||||
tex.Filter = filter;
|
||||
tex.Type = PPTextureType::CurrentPipelineTexture;
|
||||
tex.Wrap = wrap;
|
||||
tex.Type = type;
|
||||
tex.Texture = {};
|
||||
}
|
||||
|
||||
|
|
@ -137,6 +166,12 @@ public:
|
|||
Output.Texture = {};
|
||||
}
|
||||
|
||||
void SetOutputSceneColor()
|
||||
{
|
||||
Output.Type = PPTextureType::SceneColor;
|
||||
Output.Texture = {};
|
||||
}
|
||||
|
||||
void SetNoBlend()
|
||||
{
|
||||
BlendMode.BlendOp = STYLEOP_Add;
|
||||
|
|
@ -173,7 +208,9 @@ enum class PixelFormat
|
|||
{
|
||||
Rgba8,
|
||||
Rgba16f,
|
||||
R32f
|
||||
R32f,
|
||||
Rg16f,
|
||||
Rgba16_snorm
|
||||
};
|
||||
|
||||
class PPTextureDesc
|
||||
|
|
@ -221,8 +258,9 @@ public:
|
|||
|
||||
int SceneWidth = 0;
|
||||
int SceneHeight = 0;
|
||||
int fixedcm;
|
||||
float gameinfobluramount;
|
||||
int fixedcm = 0;
|
||||
float gameinfobluramount = 0.0f;
|
||||
float m5 = 0.0f;
|
||||
|
||||
TMap<FString, TArray<PPStep>> Effects;
|
||||
TMap<FString, PPTextureDesc> Textures;
|
||||
|
|
@ -457,3 +495,132 @@ public:
|
|||
NumTonemapModes
|
||||
};
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct LinearDepthUniforms
|
||||
{
|
||||
int SampleIndex;
|
||||
float LinearizeDepthA;
|
||||
float LinearizeDepthB;
|
||||
float InverseDepthRangeA;
|
||||
float InverseDepthRangeB;
|
||||
float Padding0, Padding1, Padding2;
|
||||
FVector2 Scale;
|
||||
FVector2 Offset;
|
||||
|
||||
static std::vector<UniformFieldDesc> Desc()
|
||||
{
|
||||
return
|
||||
{
|
||||
{ "SampleIndex", UniformType::Int, offsetof(LinearDepthUniforms, SampleIndex) },
|
||||
{ "LinearizeDepthA", UniformType::Float, offsetof(LinearDepthUniforms, LinearizeDepthA) },
|
||||
{ "LinearizeDepthB", UniformType::Float, offsetof(LinearDepthUniforms, LinearizeDepthB) },
|
||||
{ "InverseDepthRangeA", UniformType::Float, offsetof(LinearDepthUniforms, InverseDepthRangeA) },
|
||||
{ "InverseDepthRangeB", UniformType::Float, offsetof(LinearDepthUniforms, InverseDepthRangeB) },
|
||||
{ "Padding0", UniformType::Float, offsetof(LinearDepthUniforms, Padding0) },
|
||||
{ "Padding1", UniformType::Float, offsetof(LinearDepthUniforms, Padding1) },
|
||||
{ "Padding2", UniformType::Float, offsetof(LinearDepthUniforms, Padding2) },
|
||||
{ "Scale", UniformType::Vec2, offsetof(LinearDepthUniforms, Scale) },
|
||||
{ "Offset", UniformType::Vec2, offsetof(LinearDepthUniforms, Offset) }
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
struct SSAOUniforms
|
||||
{
|
||||
FVector2 UVToViewA;
|
||||
FVector2 UVToViewB;
|
||||
FVector2 InvFullResolution;
|
||||
float NDotVBias;
|
||||
float NegInvR2;
|
||||
float RadiusToScreen;
|
||||
float AOMultiplier;
|
||||
float AOStrength;
|
||||
int SampleIndex;
|
||||
float Padding0, Padding1;
|
||||
FVector2 Scale;
|
||||
FVector2 Offset;
|
||||
|
||||
static std::vector<UniformFieldDesc> Desc()
|
||||
{
|
||||
return
|
||||
{
|
||||
{ "UVToViewA", UniformType::Vec2, offsetof(SSAOUniforms, UVToViewA) },
|
||||
{ "UVToViewB", UniformType::Vec2, offsetof(SSAOUniforms, UVToViewB) },
|
||||
{ "InvFullResolution", UniformType::Vec2, offsetof(SSAOUniforms, InvFullResolution) },
|
||||
{ "NDotVBias", UniformType::Float, offsetof(SSAOUniforms, NDotVBias) },
|
||||
{ "NegInvR2", UniformType::Float, offsetof(SSAOUniforms, NegInvR2) },
|
||||
{ "RadiusToScreen", UniformType::Float, offsetof(SSAOUniforms, RadiusToScreen) },
|
||||
{ "AOMultiplier", UniformType::Float, offsetof(SSAOUniforms, AOMultiplier) },
|
||||
{ "AOStrength", UniformType::Float, offsetof(SSAOUniforms, AOStrength) },
|
||||
{ "SampleIndex", UniformType::Int, offsetof(SSAOUniforms, SampleIndex) },
|
||||
{ "Padding0", UniformType::Float, offsetof(SSAOUniforms, Padding0) },
|
||||
{ "Padding1", UniformType::Float, offsetof(SSAOUniforms, Padding1) },
|
||||
{ "Scale", UniformType::Vec2, offsetof(SSAOUniforms, Scale) },
|
||||
{ "Offset", UniformType::Vec2, offsetof(SSAOUniforms, Offset) },
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
struct DepthBlurUniforms
|
||||
{
|
||||
float BlurSharpness;
|
||||
float PowExponent;
|
||||
FVector2 InvFullResolution;
|
||||
|
||||
static std::vector<UniformFieldDesc> Desc()
|
||||
{
|
||||
return
|
||||
{
|
||||
{ "BlurSharpness", UniformType::Float, offsetof(DepthBlurUniforms, BlurSharpness) },
|
||||
{ "PowExponent", UniformType::Float, offsetof(DepthBlurUniforms, PowExponent) },
|
||||
{ "InvFullResolution", UniformType::Vec2, offsetof(DepthBlurUniforms, InvFullResolution) }
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
struct AmbientCombineUniforms
|
||||
{
|
||||
int SampleCount;
|
||||
int Padding0, Padding1, Padding2;
|
||||
FVector2 Scale;
|
||||
FVector2 Offset;
|
||||
|
||||
static std::vector<UniformFieldDesc> Desc()
|
||||
{
|
||||
return
|
||||
{
|
||||
{ "SampleCount", UniformType::Int, offsetof(AmbientCombineUniforms, SampleCount) },
|
||||
{ "Padding0", UniformType::Int, offsetof(AmbientCombineUniforms, Padding0) },
|
||||
{ "Padding1", UniformType::Int, offsetof(AmbientCombineUniforms, Padding1) },
|
||||
{ "Padding2", UniformType::Int, offsetof(AmbientCombineUniforms, Padding2) },
|
||||
{ "Scale", UniformType::Vec2, offsetof(AmbientCombineUniforms, Scale) },
|
||||
{ "Offset", UniformType::Vec2, offsetof(AmbientCombineUniforms, Offset) }
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
class PPAmbientOcclusion : public PPEffectManager
|
||||
{
|
||||
public:
|
||||
void DeclareShaders() override;
|
||||
void UpdateTextures() override;
|
||||
void UpdateSteps() override;
|
||||
|
||||
private:
|
||||
enum Quality
|
||||
{
|
||||
Off,
|
||||
LowQuality,
|
||||
MediumQuality,
|
||||
HighQuality,
|
||||
NumQualityModes
|
||||
};
|
||||
|
||||
int AmbientWidth = 0;
|
||||
int AmbientHeight = 0;
|
||||
|
||||
enum { NumAmbientRandomTextures = 3 };
|
||||
PPTextureName AmbientRandomTexture[NumAmbientRandomTextures];
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue