1 Oct 2021

~ Made Shaders now able to use Defines.
~ Moved complete Bloom-shader code in a single file (not working at the moment)
This commit is contained in:
Nineto Nine 2021-10-01 19:43:00 +02:00
parent 443877019b
commit 8a84182563
15 changed files with 325 additions and 44 deletions

View file

@ -17,6 +17,14 @@ using System.Threading.Tasks;
namespace SM.Base.PostEffects
{
enum BloomEffectShaderType
{
Filtering,
Downsampling,
Upsampling,
Combine
}
/// <summary>
/// The recommended bloom effect, that looks way better than the old one.
/// <para>Based on Blender's implermentation, which is based on COD: Infinite Warfare.</para>
@ -38,13 +46,47 @@ namespace SM.Base.PostEffects
new ShaderFile(AssemblyUtility.ReadAssemblyFile(SMRenderer.PostProcessPath + ".bloom.combine.vert")),
AssemblyUtility.ReadAssemblyFile(SMRenderer.PostProcessPath + ".bloom.combine.frag")
);
static BloomEffect()
{
_upsampleShader.ShaderFiles.Fragment[0].GLSLExtensions.Add(samplingFile);
_combineShader.ShaderFiles.Fragment[0].GLSLExtensions.Add(samplingFile);
}
/*
private static readonly string bloomFile = AssemblyUtility.ReadAssemblyFile(SMRenderer.PostProcessPath + ".bloom.frag");
private static readonly ShaderFile combineVertex = new ShaderFile(AssemblyUtility.ReadAssemblyFile(SMRenderer.PostProcessPath + ".bloom.combine.vert"));
static Dictionary<bool, PostProcessShader[]> _ppShaders = new Dictionary<bool, PostProcessShader[]>(2);
static PostProcessShader[] GetShaders(bool high)
{
if (_ppShaders.ContainsKey(high)) return _ppShaders[high];
PostProcessShader[] shaders;
_ppShaders.Add(high, shaders = new PostProcessShader[4]);
for(int i = 0; i < 4; i++)
{
ShaderFile file = new ShaderFile(bloomFile)
{
Defines =
{
"ACTION_"+((BloomEffectShaderType)i).ToString().ToUpper(),
}
};
if (high) file.Defines.Add("HIGH");
PostProcessShader shader;
if (i == 3) shader = new PostProcessShader(vertex: combineVertex, file);
else shader = new PostProcessShader(file);
shaders[i] = shader;
}
return shaders;
}*/
const int MAXBLOOMSTEPS = 8;
const float INTENSITY = .1f;
@ -52,6 +94,7 @@ namespace SM.Base.PostEffects
private List<Framebuffer> _downsampler;
private List<Framebuffer> _upsample;
private PostProcessShader[] shaders;
private int _iterations;
private float _sampleSize;
@ -98,9 +141,12 @@ namespace SM.Base.PostEffects
/// This creates a more prettier bloom effect.
/// </summary>
/// <param name="hdr">This allows to enable hdr returns.</param>
public BloomEffect(bool hdr = false)
/// <param name="highSetting">If set true, it will use the high quality settings.</param>
public BloomEffect(bool hdr = false, bool highSetting = true)
{
_hdr = hdr;
//shaders = GetShaders(highSetting);
shaders = new[] { _filterShader, _downsampleShader, _upsampleShader, _combineShader };
}
/// <inheritdoc/>
protected override void InitProcess() => CreateFramebuffers();
@ -168,7 +214,7 @@ namespace SM.Base.PostEffects
// Filtering
_downsampler[0].Activate(true);
_filterShader.Draw(source, col =>
shaders[0].Draw(source, col =>
{
col["ThresholdCurve"].SetVector4(_thresholdCurve);
});
@ -180,7 +226,7 @@ namespace SM.Base.PostEffects
ColorAttachment downsampleSource = last;
Framebuffer downsampleTarget = _downsampler[i];
downsampleTarget.Activate(true);
_downsampleShader.Draw(downsampleSource);
shaders[1].Draw(downsampleSource);
last = downsampleTarget["0"];
}
@ -193,7 +239,7 @@ namespace SM.Base.PostEffects
upsampleTarget.Activate(true);
_upsampleShader.Draw(last, (a) =>
shaders[2].Draw(last, (a) =>
{
if (last != null) a["baseBuffer"].SetTexture(downsampleSource);
a["sampleSize"].SetFloat(_sampleSize);
@ -204,7 +250,7 @@ namespace SM.Base.PostEffects
// combine
target.Activate(true);
_combineShader.Draw(last, (a) =>
shaders[3].Draw(last, (a) =>
{
a["sampleSize"].SetFloat(_sampleSize);

View file

@ -23,13 +23,14 @@ namespace SM.Base.PostEffects
/// </summary>
public static class PostProcessUtility
{
public static readonly ShaderFile HDRCurves = new ShaderFile(AssemblyUtility.ReadAssemblyFile(SMRenderer.PostProcessPath + ".hdr_curves.frag"));
private static readonly string _finalizeHdrCode = AssemblyUtility.ReadAssemblyFile(SMRenderer.PostProcessPath + ".finalize_hdr.glsl");
private static readonly Dictionary<HDRColorCurve, PostProcessShader> _hdrExposureShader = new Dictionary<HDRColorCurve, PostProcessShader>()
{
{ HDRColorCurve.OnlyExposure, new PostProcessShader(new ShaderFile(_finalizeHdrCode) { StringOverrides = { { "TYPE", "0" } } }) },
{ HDRColorCurve.Reinhard, new PostProcessShader(new ShaderFile(_finalizeHdrCode) { StringOverrides = { { "TYPE", "1" } } }) },
{ HDRColorCurve.ACES, new PostProcessShader(new ShaderFile(_finalizeHdrCode) { StringOverrides = { { "TYPE", "2" } } }) },
{ HDRColorCurve.OnlyExposure, new PostProcessShader(new ShaderFile(_finalizeHdrCode) {GLSLExtensions = { HDRCurves } }) },
{ HDRColorCurve.Reinhard, new PostProcessShader(new ShaderFile(_finalizeHdrCode) { GLSLExtensions = { HDRCurves }, Defines = { "TYPE_REINHARD" } }) },
{ HDRColorCurve.ACES, new PostProcessShader(new ShaderFile(_finalizeHdrCode) { GLSLExtensions = { HDRCurves }, Defines = { "TYPE_ACES" } }) },
};
private static readonly PostProcessShader _gammaShader =

View file

@ -0,0 +1,188 @@
#version 330 core
/* ACTIONS:
0 = Filtering
1 = Downsamping
2 = Upsampling
3 = Combine
*/
in vec2 vTexture;
uniform vec2 renderedTextureTexelSize;
// Uniforms
uniform vec4 ThresholdCurve;
// Downsampling
uniform float sampleSize;
uniform sampler2D baseBuffer;
in vec2 amountUV;
uniform sampler2D scene;
uniform vec4 bloomColor;
uniform bool HDR;
uniform bool hasAmountMap;
uniform sampler2D amountMap;
uniform vec2 amountLimit;
layout(location = 0) out vec4 color;
layout(location = 1) out vec4 sceneOutput;
vec4 GetRenderColorOffset(vec2);
vec3 reinhardTone(vec3);
// ---- Utils ----
vec3 safe_color(vec3 c) {
return clamp(c, vec3(0.0), vec3(1e20));
}
vec3 median(vec3 a, vec3 b, vec3 c)
{
return a + b + c - min(min(a, b), c) - max(max(a, b), c);
}
float getBrightness(vec3 col) {
return max(col.r, max(col.g, col.b));
return (col.r + col.r + col.b + col.g + col.g + col.g) / 6.0;
}
// ---- Functions ----
vec3 simpleBoxFilter() {
#if defined (ACTION_DOWNSAMPLING)
vec4 d = renderedTextureTexelSize.xyxy * vec4(-1,-1,1,1);
#else
vec4 d = renderedTextureTexelSize.xyxy * vec4(-1,-1,1,1) * (sampleSize * 0.5);
#endif
vec3 s;
s = GetRenderColorOffset(d.xy).rgb;
s += GetRenderColorOffset(d.zy).rgb;
s += GetRenderColorOffset(d.xw).rgb;
s += GetRenderColorOffset(d.zw).rgb;
return s * 0.25; // 1 / 4 = 0.25
}
// Downsampling:
vec3 downsample_high() {
vec4 d = renderedTextureTexelSize.xyxy * vec4(-1,-1, +1, +1);
vec3 s1 = GetRenderColorOffset(d.xy).rgb; // - -
// X -
vec3 s2 = GetRenderColorOffset(d.zy).rgb; // - -
// - X
vec3 s3 = GetRenderColorOffset(d.xw).rgb; // X -
// - -
vec3 s4 = GetRenderColorOffset(d.zw).rgb; // X -
// - -
float s1w = 1.0 / (getBrightness(s1) + 1.0);
float s2w = 1.0 / (getBrightness(s2) + 1.0);
float s3w = 1.0 / (getBrightness(s3) + 1.0);
float s4w = 1.0 / (getBrightness(s4) + 1.0);
float one_div = 1.0 / (s1w + s2w + s3w + s4w);
return (s1 * s1w + s2 * s2w + s3 * s3w + s4 * s4w) * one_div;
}
// Upsampling:
vec3 upsample_high() {
vec4 d = renderedTextureTexelSize.xyxy * vec4(1, 1,-1,0) * sampleSize;
vec3 s;
// Line + 1
s = GetRenderColorOffset(d.zy).rgb; // x - -
s += GetRenderColorOffset(d.wy).rgb * 2; // - X -
s += GetRenderColorOffset(d.xy).rgb; // - - X
// Line 0
s += GetRenderColorOffset(d.zw).rgb * 2; // X - -
s += GetRenderColorOffset(vec2(0)).rgb * 4; // - X -
s += GetRenderColorOffset(d.xw).rgb * 2; // - - X
// Line - 1
s += GetRenderColorOffset(d.zz).rgb; // X - -
s += GetRenderColorOffset(d.wz).rgb * 2; // - X -
s += GetRenderColorOffset(d.xz).rgb; // - - X
return texture2D(baseBuffer, vTexture).rgb + s * 0.0625; // 1 / 16 = 0.0625
}
// ---- Actions ----
vec3 filtering() {
vec3 col = safe_color(GetRenderColorOffset(vec2(0)).rgb);
sceneOutput = vec4(col, 1);
return sceneOutput.rgb;
#ifdef HIGH
vec3 d = renderedTextureTexelSize.xyx * vec3(1,1,0);
vec3 s0 = col + vec3(.1);
vec3 s1 = safe_color(GetRenderColorOffset(-d.xz).rgb) + vec3(.1);
vec3 s2 = safe_color(GetRenderColorOffset(+d.xz).rgb) + vec3(.1);
vec3 s3 = safe_color(GetRenderColorOffset(-d.zy).rgb) + vec3(.1);
vec3 s4 = safe_color(GetRenderColorOffset(+d.zy).rgb) + vec3(.1);
vec3 col = median(median(s0, s1, s2), s3, s4);
#endif
float br = getBrightness(col);
float rq = clamp(br - ThresholdCurve.x, 0, ThresholdCurve.y);
rq = ThresholdCurve.z * rq * rq;
float resultBr = max(rq, br - ThresholdCurve.w) / max(1e-5, br);
return col * resultBr;
}
vec3 downsample() {
#ifdef HIGH
return downsample_high();
#else
return simpleBoxFilter();
#endif
}
vec3 upsample() {
#ifdef HIGH
return upsample_high();
#else
return simpleBoxFilter();
#endif
}
vec3 combine() {
vec3 scene = safe_color(texture2D(scene, vTexture).rgb);
vec3 blur = upsample() * bloomColor.rgb;
if (hasAmountMap) {
blur *= clamp(texture2D(amountMap, amountUV).r * (amountLimit.y - amountLimit.x) + amountLimit.x, 0, 1);
}
if (HDR) {
return scene + blur;
}
return scene + reinhardTone(blur);
}
// main:
void main() {
vec3 col;
#if defined(ACTION_FILTERING)
col = filtering();
#elif defined(ACTION_DOWNSAMPLING)
col = downsample();
#elif defined(ACTION_UPSAMPLING)
col = upsample();
#else
col = combine();
#endif
color = vec4(col, 1);
}

View file

@ -2,7 +2,6 @@
uniform vec2 renderedTextureTexelSize;
vec4 GetRenderColor();
vec4 GetRenderColorOffset(vec2);
float getBrightness(vec3 col) {

View file

@ -8,7 +8,7 @@ vec4 GetRenderColorOffset(vec2);
vec3 upsample_filter_high() {
vec4 d = renderedTextureTexelSize.xyxy * vec4(1, 1,-1,0);
vec4 d = renderedTextureTexelSize.xyxy * vec4(1, 1,-1,0) * sampleSize;
vec3 s;
// Line + 1

View file

@ -1,5 +1,4 @@
#version 330
#define TYPE //!TYPE
in vec2 vTexture;
@ -9,31 +8,19 @@ uniform float Gamma;
layout(location = 0) out vec4 color;
vec3 ACES(vec3 x) {
const float a = 2.51;
const float b = 0.03;
const float c = 2.43;
const float d = 0.59;
const float e = 0.14;
vec3 ACES(vec3);
return clamp((x * (a * x + b)) / (x * (c * x + d) + e), 0,1.0);
}
vec3 reinhardTone(vec3);
vec3 reinhardTone(vec3 col) {
return col / (col + vec3(1.0));
}
vec3 exposure(vec3 scene) {
return vec3(1) - exp(-texture(Scene, vTexture).rgb * Exposure);
}
vec3 exposure(vec3);
void main() {
vec3 scene = texture2D(Scene, vTexture).rgb;
vec3 result = exposure(scene);
#if (TYPE == 1)
#if defined(TYPE_REINHARD)
result = reinhardTone(result);
#elif (TYPE == 2)
#elif defined(TYPE_ACES)
result = ACES(result);
#endif

View file

@ -0,0 +1,21 @@
#version 330 core
uniform float Exposure;
vec3 ACES(vec3 col) {
const float a = 2.51;
const float b = 0.03;
const float c = 2.43;
const float d = 0.59;
const float e = 0.14;
return clamp((col * (a * col + b)) / (col * (c * col + d) + e), 0.0,1.0);
}
vec3 reinhardTone(vec3 col) {
return col / (col + vec3(1.0));
}
vec3 exposure(vec3 col) {
return vec3(1) - exp(-col * Exposure);
}