mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-11 07:12:02 +00:00
- create bloom pass in declarative postprocess form
This commit is contained in:
parent
f2aecd47a5
commit
da5ecf1e5b
3 changed files with 382 additions and 0 deletions
|
@ -1061,6 +1061,7 @@ set (PCH_SOURCES
|
|||
hwrenderer/dynlights/hw_aabbtree.cpp
|
||||
hwrenderer/dynlights/hw_shadowmap.cpp
|
||||
hwrenderer/scene/hw_skydome.cpp
|
||||
hwrenderer/postprocessing/hw_postprocess.cpp
|
||||
hwrenderer/postprocessing/hw_postprocess_cvars.cpp
|
||||
hwrenderer/postprocessing/hw_postprocessshader.cpp
|
||||
hwrenderer/postprocessing/hw_shadowmapshader.cpp
|
||||
|
|
191
src/hwrenderer/postprocessing/hw_postprocess.cpp
Normal file
191
src/hwrenderer/postprocessing/hw_postprocess.cpp
Normal file
|
@ -0,0 +1,191 @@
|
|||
|
||||
#include "v_video.h"
|
||||
#include "hw_postprocess.h"
|
||||
#include "hwrenderer/utility/hw_cvars.h"
|
||||
#include "gl_load/gl_load.h" // for GL_RGBA16F - should we create our own enum instead?
|
||||
|
||||
Postprocess hw_postprocess;
|
||||
|
||||
void PPBloom::DeclareShaders()
|
||||
{
|
||||
PPShader shader;
|
||||
shader.VertexShader = "shaders/glsl/screenquad.vp";
|
||||
shader.FragmentShader = "shaders/glsl/bloomcombine.fp";
|
||||
hw_postprocess.Shaders["BloomCombine"] = shader;
|
||||
|
||||
shader.Uniforms = ExtractUniforms::Desc();
|
||||
shader.FragmentShader = "shaders/glsl/bloomextract.fp";
|
||||
hw_postprocess.Shaders["BloomExtract"] = shader;
|
||||
|
||||
shader.Uniforms = BlurUniforms::Desc();
|
||||
shader.FragmentShader = "shaders/glsl/blur.fp";
|
||||
shader.Defines = "#define BLUR_VERTICAL\n";
|
||||
hw_postprocess.Shaders["BlurVertical"] = shader;
|
||||
|
||||
shader.Defines = "#define BLUR_HORIZONTAL\n";
|
||||
hw_postprocess.Shaders["BlurHorizontal"] = shader;
|
||||
}
|
||||
|
||||
void PPBloom::UpdateTextures(int width, int height)
|
||||
{
|
||||
// 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++)
|
||||
{
|
||||
FString vtexture, htexture;
|
||||
vtexture.Format("Bloom.VTexture.%d", i);
|
||||
htexture.Format("Bloom.HTexture.%d", i);
|
||||
|
||||
auto &level = levels[i];
|
||||
level.Viewport.left = 0;
|
||||
level.Viewport.top = 0;
|
||||
level.Viewport.width = (bloomWidth + 1) / 2;
|
||||
level.Viewport.height = (bloomHeight + 1) / 2;
|
||||
|
||||
PPTextureDesc texture;
|
||||
texture.Width = level.Viewport.width;
|
||||
texture.Height = level.Viewport.height;
|
||||
texture.Format = GL_RGBA16F;
|
||||
|
||||
hw_postprocess.Textures[vtexture] = texture;
|
||||
hw_postprocess.Textures[htexture] = texture;
|
||||
|
||||
bloomWidth = level.Viewport.width;
|
||||
bloomHeight = level.Viewport.height;
|
||||
}
|
||||
}
|
||||
|
||||
void PPBloom::UpdateSteps(int fixedcm)
|
||||
{
|
||||
TArray<PPStep> steps;
|
||||
|
||||
// Only bloom things if enabled and no special fixed light mode is active
|
||||
if (!gl_bloom || fixedcm != CM_DEFAULT || gl_ssao_debug)
|
||||
{
|
||||
hw_postprocess.Effects["BloomScene"] = steps;
|
||||
return;
|
||||
}
|
||||
|
||||
PPStep step;
|
||||
step.Textures.Resize(1);
|
||||
|
||||
ExtractUniforms extractUniforms;
|
||||
extractUniforms.Scale = screen->SceneScale();
|
||||
extractUniforms.Offset = screen->SceneOffset();
|
||||
|
||||
auto &level0 = levels[0];
|
||||
|
||||
// Extract blooming pixels from scene texture:
|
||||
step.Viewport = level0.Viewport;
|
||||
step.Textures[0].Type = PPTextureType::CurrentPipelineTexture;
|
||||
step.Textures[0].Filter = PPFilterMode::Linear;
|
||||
step.ShaderName = "BloomExtract";
|
||||
step.Uniforms.Set(extractUniforms);
|
||||
step.Output.Type = PPTextureType::PPTexture;
|
||||
step.Output.Texture = level0.VTexture;
|
||||
step.BlendMode.BlendOp = STYLEOP_Add;
|
||||
step.BlendMode.SrcAlpha = STYLEALPHA_One;
|
||||
step.BlendMode.DestAlpha = STYLEALPHA_Zero;
|
||||
steps.Push(step);
|
||||
|
||||
const float blurAmount = gl_bloom_amount;
|
||||
BlurUniforms blurUniforms;
|
||||
ComputeBlurSamples(7, blurAmount, blurUniforms.SampleWeights);
|
||||
|
||||
// Blur and downscale:
|
||||
for (int i = 0; i < NumBloomLevels - 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 = NumBloomLevels - 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.Textures[0].Type = PPTextureType::PPTexture;
|
||||
step.Textures[0].Filter = PPFilterMode::Linear;
|
||||
step.Textures[0].Texture = next.VTexture;
|
||||
step.Output.Texture = next.HTexture;
|
||||
step.Viewport = next.Viewport;
|
||||
step.ShaderName = "BloomCombine";
|
||||
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));
|
||||
|
||||
// Add bloom back to scene texture:
|
||||
step.Textures[0].Type = PPTextureType::PPTexture;
|
||||
step.Textures[0].Filter = PPFilterMode::Linear;
|
||||
step.Textures[0].Texture = level0.VTexture;
|
||||
step.Output.Type = PPTextureType::CurrentPipelineTexture;
|
||||
step.Viewport = screen->mSceneViewport;
|
||||
step.ShaderName = "BloomCombine";
|
||||
step.BlendMode.BlendOp = STYLEOP_Add;
|
||||
step.BlendMode.SrcAlpha = STYLEALPHA_One;
|
||||
step.BlendMode.DestAlpha = STYLEALPHA_One;
|
||||
step.BlendMode.Flags = 0;
|
||||
steps.Push(step);
|
||||
|
||||
hw_postprocess.Effects["BloomScene"] = steps;
|
||||
}
|
||||
|
||||
PPStep PPBloom::BlurStep(const BlurUniforms &blurUniforms, PPTextureName input, PPTextureName output, PPViewport viewport, bool vertical)
|
||||
{
|
||||
PPStep step;
|
||||
step.Textures.Resize(1);
|
||||
step.Viewport = viewport;
|
||||
step.Textures[0].Type = PPTextureType::PPTexture;
|
||||
step.Textures[0].Filter = PPFilterMode::Nearest;
|
||||
step.Textures[0].Texture = input;
|
||||
step.ShaderName = vertical ? "BlurVertical" : "BlurHorizontal";
|
||||
step.Uniforms.Set(blurUniforms);
|
||||
step.Output.Type = PPTextureType::PPTexture;
|
||||
step.Output.Texture = output;
|
||||
step.BlendMode.BlendOp = STYLEOP_Add;
|
||||
step.BlendMode.SrcAlpha = STYLEALPHA_One;
|
||||
step.BlendMode.DestAlpha = STYLEALPHA_Zero;
|
||||
step.BlendMode.Flags = 0;
|
||||
return step;
|
||||
}
|
||||
|
||||
float PPBloom::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)));
|
||||
}
|
||||
|
||||
void PPBloom::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;
|
||||
}
|
||||
}
|
190
src/hwrenderer/postprocessing/hw_postprocess.h
Normal file
190
src/hwrenderer/postprocessing/hw_postprocess.h
Normal file
|
@ -0,0 +1,190 @@
|
|||
#pragma once
|
||||
|
||||
#include "hwrenderer/data/shaderuniforms.h"
|
||||
|
||||
typedef FString PPTextureName;
|
||||
typedef FString PPShaderName;
|
||||
|
||||
typedef FRenderStyle PPBlendMode;
|
||||
typedef IntRect PPViewport;
|
||||
|
||||
enum class PPFilterMode { Nearest, Linear };
|
||||
enum class PPTextureType { CurrentPipelineTexture, NextPipelineTexture, PPTexture };
|
||||
|
||||
class PPTextureInput
|
||||
{
|
||||
public:
|
||||
PPFilterMode Filter;
|
||||
PPTextureType Type;
|
||||
PPTextureName Texture;
|
||||
};
|
||||
|
||||
class PPOutput
|
||||
{
|
||||
public:
|
||||
PPTextureType Type;
|
||||
PPTextureName Texture;
|
||||
};
|
||||
|
||||
class PPUniforms
|
||||
{
|
||||
public:
|
||||
PPUniforms()
|
||||
{
|
||||
}
|
||||
|
||||
PPUniforms(const PPUniforms &src)
|
||||
{
|
||||
if (src.Size > 0)
|
||||
{
|
||||
Data = new uint8_t[src.Size];
|
||||
Size = src.Size;
|
||||
memcpy(Data, src.Data, Size);
|
||||
}
|
||||
}
|
||||
|
||||
~PPUniforms()
|
||||
{
|
||||
delete[] Data;
|
||||
}
|
||||
|
||||
PPUniforms &operator=(const PPUniforms &src)
|
||||
{
|
||||
if (this != &src)
|
||||
{
|
||||
if (src.Size > 0)
|
||||
{
|
||||
Data = new uint8_t[src.Size];
|
||||
Size = src.Size;
|
||||
memcpy(Data, src.Data, Size);
|
||||
}
|
||||
else
|
||||
{
|
||||
delete[] Data;
|
||||
Data = nullptr;
|
||||
Size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void Set(const T &v)
|
||||
{
|
||||
if (Size != (int)sizeof(T))
|
||||
{
|
||||
delete[] Data;
|
||||
Data = nullptr;
|
||||
Size = 0;
|
||||
|
||||
Data = new uint8_t[Size];
|
||||
Size = sizeof(T);
|
||||
memcpy(Data, &v, Size);
|
||||
}
|
||||
}
|
||||
|
||||
void *Data = nullptr;
|
||||
int Size = 0;
|
||||
};
|
||||
|
||||
class PPStep
|
||||
{
|
||||
public:
|
||||
PPShaderName ShaderName;
|
||||
TArray<PPTextureInput> Textures;
|
||||
PPUniforms Uniforms;
|
||||
PPViewport Viewport;
|
||||
PPBlendMode BlendMode;
|
||||
PPOutput Output;
|
||||
};
|
||||
|
||||
struct ExtractUniforms
|
||||
{
|
||||
FVector2 Scale;
|
||||
FVector2 Offset;
|
||||
|
||||
static std::vector<UniformFieldDesc> Desc()
|
||||
{
|
||||
return
|
||||
{
|
||||
{ "Scale", UniformType::Vec2, offsetof(ExtractUniforms, Scale) },
|
||||
{ "Offset", UniformType::Vec2, offsetof(ExtractUniforms, Offset) }
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
struct BlurUniforms
|
||||
{
|
||||
float SampleWeights[8];
|
||||
|
||||
static std::vector<UniformFieldDesc> Desc()
|
||||
{
|
||||
return
|
||||
{
|
||||
{ "SampleWeights0", UniformType::Float, offsetof(BlurUniforms, SampleWeights[0]) },
|
||||
{ "SampleWeights1", UniformType::Float, offsetof(BlurUniforms, SampleWeights[1]) },
|
||||
{ "SampleWeights2", UniformType::Float, offsetof(BlurUniforms, SampleWeights[2]) },
|
||||
{ "SampleWeights3", UniformType::Float, offsetof(BlurUniforms, SampleWeights[3]) },
|
||||
{ "SampleWeights4", UniformType::Float, offsetof(BlurUniforms, SampleWeights[4]) },
|
||||
{ "SampleWeights5", UniformType::Float, offsetof(BlurUniforms, SampleWeights[5]) },
|
||||
{ "SampleWeights6", UniformType::Float, offsetof(BlurUniforms, SampleWeights[6]) },
|
||||
{ "SampleWeights7", UniformType::Float, offsetof(BlurUniforms, SampleWeights[7]) },
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
class PPTextureDesc
|
||||
{
|
||||
public:
|
||||
int Width;
|
||||
int Height;
|
||||
int Format;
|
||||
};
|
||||
|
||||
class PPShader
|
||||
{
|
||||
public:
|
||||
FString VertexShader;
|
||||
FString FragmentShader;
|
||||
FString Defines;
|
||||
std::vector<UniformFieldDesc> Uniforms;
|
||||
};
|
||||
|
||||
class Postprocess
|
||||
{
|
||||
public:
|
||||
TMap<FString, TArray<PPStep>> Effects;
|
||||
TMap<FString, PPTextureDesc> Textures;
|
||||
TMap<FString, PPShader> Shaders;
|
||||
};
|
||||
|
||||
extern Postprocess hw_postprocess;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
enum { NumBloomLevels = 4 };
|
||||
|
||||
class PPBlurLevel
|
||||
{
|
||||
public:
|
||||
PPViewport Viewport;
|
||||
PPTextureName VTexture;
|
||||
PPTextureName HTexture;
|
||||
};
|
||||
|
||||
class PPBloom
|
||||
{
|
||||
public:
|
||||
void DeclareShaders();
|
||||
void UpdateTextures(int sceneWidth, int sceneHeight);
|
||||
void UpdateSteps(int fixedcm);
|
||||
|
||||
private:
|
||||
PPStep BlurStep(const BlurUniforms &blurUniforms, PPTextureName input, PPTextureName output, PPViewport viewport, bool vertical);
|
||||
|
||||
static float ComputeBlurGaussian(float n, float theta);
|
||||
static void ComputeBlurSamples(int sampleCount, float blurAmount, float *sampleWeights);
|
||||
|
||||
PPBlurLevel levels[NumBloomLevels];
|
||||
};
|
Loading…
Reference in a new issue