From 071b66999d845e01842ddd4e4e43741e5f81b6ad Mon Sep 17 00:00:00 2001 From: psi29a Date: Sun, 21 Aug 2022 12:53:46 +0000 Subject: [PATCH] Merge branch 'bloom_shader' into 'master' Add wareya's linear bloom shader See merge request OpenMW/openmw!2313 (cherry picked from commit 537c6e96abc4952a6c93eeedd6eecfaf7344809d) 534f0377 Add wareya's linear bloom shader 84c72b1c Add dots at the end, and add the .ru translation --- files/data/CMakeLists.txt | 1 + files/data/l10n/BuiltInShaders/en.yaml | 17 +- files/data/l10n/BuiltInShaders/ru.yaml | 13 +- files/data/shaders/bloomlinear.omwfx | 231 +++++++++++++++++++++++++ 4 files changed, 258 insertions(+), 4 deletions(-) create mode 100644 files/data/shaders/bloomlinear.omwfx diff --git a/files/data/CMakeLists.txt b/files/data/CMakeLists.txt index e067d5192a..6186759102 100644 --- a/files/data/CMakeLists.txt +++ b/files/data/CMakeLists.txt @@ -97,6 +97,7 @@ set(BUILTIN_DATA_FILES scripts/omw/mwui/init.lua shaders/adjustments.omwfx + shaders/bloomlinear.omwfx shaders/debug.omwfx mygui/core.skin diff --git a/files/data/l10n/BuiltInShaders/en.yaml b/files/data/l10n/BuiltInShaders/en.yaml index 4454fdefa5..00354a45ff 100644 --- a/files/data/l10n/BuiltInShaders/en.yaml +++ b/files/data/l10n/BuiltInShaders/en.yaml @@ -1,4 +1,5 @@ AdjustmentsDescription: "Colour adjustments." +BloomDescription: "Bloom shader performing its calculations in (approximately) linear light." DebugDescription: "Debug shader." DebugHeaderDepth: "Depth Buffer" DebugHeaderNormals: "Normals" @@ -6,7 +7,17 @@ DisplayDepthFactorName: "Depth colour factor" DisplayDepthFactorDescription: "Determines correlation between pixel depth value and its output colour. High values lead to brighter image." DisplayDepthName: "Visualize depth buffer" DisplayNormalsName: "Visualize pass normals" -ContrastLevelDescription: "Constrast level" +ContrastLevelDescription: "Constrast level." ContrastLevelName: "Constrast" -GammaLevelDescription: "Gamma level" -GammaLevelName: "Gamma" \ No newline at end of file +GammaLevelDescription: "Gamma level." +GammaLevelName: "Gamma" +StrengthLevelName: "Strength" +StrengthLevelDescription: "Strength of the effect." +RadiusLevelName: "Radius" +RadiusLevelDescription: "Radius of the effect." +SkyFactorLevelName: "Sky Factor" +SkyFactorLevelDescription: "Multiplication factor for light coming directly from the sky." +BloomClampLevelName: "Clamp Level" +BloomClampLevelDescription: "Clamp bloom pixels brighter than this value when mixing bloom into scene." +BloomThresholdLevelName: "Threshold" +BloomThresholdLevelDescription: "Ignore pixels with brightnesses below this value when calculating blur. Doesn't affect the sky." diff --git a/files/data/l10n/BuiltInShaders/ru.yaml b/files/data/l10n/BuiltInShaders/ru.yaml index 46fc34b856..b61c61c29b 100644 --- a/files/data/l10n/BuiltInShaders/ru.yaml +++ b/files/data/l10n/BuiltInShaders/ru.yaml @@ -9,4 +9,15 @@ DisplayNormalsName: "Визуализация нормалей" ContrastLevelDescription: "Контрастность изображения" ContrastLevelName: "Контрастность" GammaLevelDescription: "Яркость изображения" -GammaLevelName: "Яркость" \ No newline at end of file +GammaLevelName: "Яркость" +BloomDescription: "Шейдер блума, совершающий вычисления на основе (приблизительно) линейного освещения." +StrengthLevelName: "Сила" +StrengthLevelDescription: "Сила эффекта" +RadiusLevelName: "Радиус" +RadiusLevelDescription: "Радиус эффекта" +SkyFactorLevelName: "Множитель неба" +SkyFactorLevelDescription: "Множитель для освещения напрямую от неба." +BloomClampLevelName: "Уровень привязки" +BloomClampLevelDescription: "Яркость, к которой привязываются более яркие пиксели блума при смешивании со сценой." +BloomThresholdLevelName: "Порог" +BloomThresholdLevelDescription: "Пиксели темнее этого значения при вычислении размытия игнорируются. Не влияет на небо." diff --git a/files/data/shaders/bloomlinear.omwfx b/files/data/shaders/bloomlinear.omwfx new file mode 100644 index 0000000000..8d20a1dc15 --- /dev/null +++ b/files/data/shaders/bloomlinear.omwfx @@ -0,0 +1,231 @@ +uniform_float uGamma { + default = 2.2; + min = 0.1; + max = 4.0; + step = 0.01; + display_name = "#{BuiltInShaders:GammaLevelName}"; + description = "#{BuiltInShaders:GammaLevelDescription}"; +} +uniform_float uThreshold { + default = 0.35; + min = 0.0; + max = 1.0; + step = 0.01; + description = "#{BuiltInShaders:ThresholdLevelName}"; + display_name = "#{BuiltInShaders:ThresholdLevelDescription}"; +} +uniform_float uClamp { + default = 1.0; + min = 0.0; + max = 1.0; + step = 0.01; + description = "#{BuiltInShaders:BloomClampLevelName}"; + display_name = "#{BuiltInShaders:BloomClampLevelDescription}"; +} +uniform_float uSkyFactor { + default = 0.5; + min = 0.0; + max = 2.0; + step = 0.01; + description = "#{BuiltInShaders:SkyFactorLevelName}"; + display_name = "#{BuiltInShaders:SkyFactorLevelDescription}"; +} +uniform_float uRadius { + default = 0.5; + min = 0.0; + max = 1.0; + step = 0.01; + description = "#{BuiltInShaders:RadiusLevelName}"; + display_name = "#{BuiltInShaders:RadiusLevelDescription}"; +} +uniform_float uStrength { + default = 0.25; + min = 0.0; + max = 1.0; + step = 0.01; + display_name = "#{BuiltInShaders:StrengthLevelName}"; + description = "#{BuiltInShaders:StrengthLevelDescription}"; +} + +shared { + float scramblify(float x) + { + x = fract(x); + x = x + 4.0; + x = x*x; + x = x*x; + return fract(x); + } + float scramblev2_inner(vec2 v, float z) + { + return scramblify(v.x*0.6491 + v.y*0.029 + z); + } + + float time = fract(omw.simulationTime); + vec4 scramblev2(vec2 v) + { + v *= 61.12; + vec2 fwup = vec2(scramblev2_inner(v, fract(time)), scramblev2_inner(v, fract(time*fract(v.x)) + 0.18943)); + return vec4(0.5) - vec4(fwup, fwup); + } + + float gauss(float x) + { + return exp(-x*x); + } + float calculate_radius(vec2 texcoord) + { + float radius = uRadius * 0.2; + radius *= omw.resolution.y; + radius = max(radius, 0.1); + // hack: make the radius wider on the screen edges + // (makes things in the corner of the screen look less "wrong" with not-extremely-low FOVs) + radius *= pow(texcoord.x*2.0-1.0, 2)+1.0; + radius *= pow(texcoord.y*2.0-1.0, 2)+1.0; + return radius; + } + vec3 powv(vec3 a, float x) + { + return pow(a, vec3(x)); + } +} + +render_target RT_NoMipmap { + width_ratio = 0.25; + height_ratio = 0.25; + internal_format = rgb16f; + source_type = float; + source_format = rgb; + mipmaps = false; + min_filter = nearest; + mag_filter = nearest; +} + +render_target RT_Horizontal { + width_ratio = 0.25; + height_ratio = 0.25; + internal_format = rgb16f; + source_type = float; + source_format = rgb; + mipmaps = false; + min_filter = nearest; + mag_filter = nearest; +} + +render_target RT_Vertical { + width_ratio = 0.25; + height_ratio = 0.25; + internal_format = rgb16f; + source_type = float; + source_format = rgb; + mipmaps = false; + min_filter = linear; + mag_filter = linear; +} + +fragment nomipmap(target=RT_NoMipmap) { + omw_In vec2 omw_TexCoord; + + void main() + { + // downsample into a smaller buffer with mipmapping disabled (no need for it + might interfere with the blurring process) + // do the gamma compression step while we're at it + vec3 sample = omw_GetLastShader(omw_TexCoord).rgb; + bool is_sky = (omw_GetLinearDepth(omw_TexCoord) > omw.far*0.999); + float factor = is_sky ? uSkyFactor : 1.0; + vec3 ret_sample = powv(sample, uGamma); + factor *= (!is_sky && (dot(sample, vec3(1.0/3.0)) < uThreshold)) ? 0.0 : 1.0; + ret_sample *= factor; + omw_FragColor = vec4(ret_sample, 1.0); + } +} + +fragment horizontal(target=RT_Horizontal, rt1=RT_NoMipmap) { + omw_In vec2 omw_TexCoord; + + void main() + { + // gaussian blur, horizontal step + float radius = calculate_radius(omw_TexCoord); + int radius_i = int(ceil(radius)); + vec3 sum = vec3(0.0); + float normalize = 0.0; + for(int x = -radius_i; x <= radius_i; x += 1) + { + float strength = gauss(float(x)/radius*2.0); + normalize += strength; + vec2 coord = omw_TexCoord + vec2(float(x), 0.0) / omw.resolution.xy; + vec3 sample = omw_Texture2D(RT_NoMipmap, coord).rgb; + sum += strength * sample; + } + sum /= normalize; + + omw_FragColor = vec4(sum, 1.0); + } +} + +fragment vertical(target=RT_Vertical, rt1=RT_Horizontal) { + omw_In vec2 omw_TexCoord; + + void main() + { + // gaussian blur, vertical step + float radius = calculate_radius(omw_TexCoord); + int radius_i = int(ceil(radius)); + vec3 sum = vec3(0.0); + float normalize = 0.0; + for(int y = -radius_i; y <= radius_i; y += 1) + { + float strength = gauss(float(y)/radius*2.0); + normalize += strength; + vec2 coord = omw_TexCoord + vec2(0.0, float(y)) / omw.resolution.xy; + vec3 sample = omw_Texture2D(RT_Horizontal, coord).rgb; + sum += strength * sample; + } + sum /= normalize; + + omw_FragColor = vec4(sum, 1.0); + } +} + +fragment final(rt1=RT_Vertical) { + omw_In vec2 omw_TexCoord; + + float clampify(float x, float clamp) + { + if(x < clamp) + return x; + return ((x-clamp)*0.5)+clamp; + } + + void main() + { + vec3 color = vec3(0.0); + color = omw_Texture2D(RT_Vertical, omw_TexCoord).rgb; + // add dithering (in gamma-compressed light, because monitors are sRGB) + color = powv(color, 1.0/uGamma); + color += (scramblev2(omw_TexCoord).rgb/255.0 - vec3(0.5/255.0))*2.0; + color = max(vec3(0.0), color); + // also do clamping in gamma-compressed light + float color_luma = dot(color, vec3(1.0/3.0)); + if(uClamp == 0.0) + color *= 0.0; + else if(color_luma > uClamp) + color /= color_luma/uClamp; + color = powv(color, uGamma); + + // add bloom to base color in linear light + vec3 base_color = powv(omw_GetLastShader(omw_TexCoord).rgb, uGamma); + vec3 add_color = base_color + color * uStrength * 0.5; + omw_FragColor = vec4(powv(add_color, 1.0/uGamma), 1.0); + //omw_FragColor = vec4(powv(color, 1.0/uGamma), 1.0); + } +} + +technique { + passes = nomipmap, horizontal, vertical, final; + description = "#{BuiltInShaders:BloomDescription}"; + author = "OpenMW"; + version = "1.0"; +} +