From f29b1da5833a5fbc739a22899fe9b1c5d8f9d5a9 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Tue, 25 Oct 2022 21:46:55 +0100 Subject: [PATCH 1/4] Implemented FxUpscale --- assets/voxygen/shaders/antialias/fxaa.glsl | 134 +---------------- .../voxygen/shaders/antialias/fxupscale.glsl | 24 +++ assets/voxygen/shaders/include/fxaa.glsl | 139 ++++++++++++++++++ assets/voxygen/shaders/postprocess-frag.glsl | 1 - voxygen/src/hud/settings_window/video.rs | 2 + voxygen/src/render/mod.rs | 9 +- .../src/render/renderer/pipeline_creation.rs | 3 + voxygen/src/render/renderer/shaders.rs | 2 + 8 files changed, 179 insertions(+), 135 deletions(-) create mode 100644 assets/voxygen/shaders/antialias/fxupscale.glsl create mode 100644 assets/voxygen/shaders/include/fxaa.glsl diff --git a/assets/voxygen/shaders/antialias/fxaa.glsl b/assets/voxygen/shaders/antialias/fxaa.glsl index 0b1a85272b..baf2e3af1c 100644 --- a/assets/voxygen/shaders/antialias/fxaa.glsl +++ b/assets/voxygen/shaders/antialias/fxaa.glsl @@ -1,119 +1,4 @@ -/** -Basic FXAA implementation based on the code on geeks3d.com with the -modification that the texture2DLod stuff was removed since it's -unsupported by WebGL. - --- - -From: -https://github.com/mitsuhiko/webgl-meincraft - -Copyright (c) 2011 by Armin Ronacher. - -Some rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - - * The names of the contributors may not be used to endorse or - promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef FXAA_REDUCE_MIN - #define FXAA_REDUCE_MIN (1.0/ 128.0) -#endif -#ifndef FXAA_REDUCE_MUL - #define FXAA_REDUCE_MUL (1.0 / 8.0) -#endif -#ifndef FXAA_SPAN_MAX - #define FXAA_SPAN_MAX 8.0 -#endif - -//optimized version for mobile, where dependent -//texture reads can be a bottleneck -vec4 fxaa(texture2D tex, sampler smplr, vec2 fragCoord, vec2 resolution, - vec2 v_rgbNW, vec2 v_rgbNE, - vec2 v_rgbSW, vec2 v_rgbSE, - vec2 v_rgbM) { - vec4 color; - mediump vec2 inverseVP = vec2(1.0 / resolution.x, 1.0 / resolution.y); - vec3 rgbNW = texture(sampler2D(tex, smplr), v_rgbNW).xyz; - vec3 rgbNE = texture(sampler2D(tex, smplr), v_rgbNE).xyz; - vec3 rgbSW = texture(sampler2D(tex, smplr), v_rgbSW).xyz; - vec3 rgbSE = texture(sampler2D(tex, smplr), v_rgbSE).xyz; - vec4 texColor = texture(sampler2D(tex, smplr), v_rgbM); - vec3 rgbM = texColor.xyz; - vec3 luma = vec3(0.299, 0.587, 0.114); - float lumaNW = dot(rgbNW, luma); - float lumaNE = dot(rgbNE, luma); - float lumaSW = dot(rgbSW, luma); - float lumaSE = dot(rgbSE, luma); - float lumaM = dot(rgbM, luma); - float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE))); - float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE))); - - mediump vec2 dir; - dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE)); - dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE)); - - float dirReduce = max((lumaNW + lumaNE + lumaSW + lumaSE) * - (0.25 * FXAA_REDUCE_MUL), FXAA_REDUCE_MIN); - - float rcpDirMin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce); - dir = min(vec2(FXAA_SPAN_MAX, FXAA_SPAN_MAX), - max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX), - dir * rcpDirMin)) * inverseVP; - - vec3 rgbA = 0.5 * ( - texture(sampler2D(tex, smplr), fragCoord * inverseVP + dir * (1.0 / 3.0 - 0.5)).xyz + - texture(sampler2D(tex, smplr), fragCoord * inverseVP + dir * (2.0 / 3.0 - 0.5)).xyz); - vec3 rgbB = rgbA * 0.5 + 0.25 * ( - texture(sampler2D(tex, smplr), fragCoord * inverseVP + dir * -0.5).xyz + - texture(sampler2D(tex, smplr), fragCoord * inverseVP + dir * 0.5).xyz); - - float lumaB = dot(rgbB, luma); - if ((lumaB < lumaMin) || (lumaB > lumaMax)) - color = vec4(rgbA, texColor.a); - else - color = vec4(rgbB, texColor.a); - return color; -} - - -void texcoords(vec2 fragCoord, vec2 resolution, - out vec2 v_rgbNW, out vec2 v_rgbNE, - out vec2 v_rgbSW, out vec2 v_rgbSE, - out vec2 v_rgbM) { - vec2 inverseVP = 1.0 / resolution.xy; - v_rgbNW = (fragCoord + vec2(-1.0, -1.0)) * inverseVP; - v_rgbNE = (fragCoord + vec2(1.0, -1.0)) * inverseVP; - v_rgbSW = (fragCoord + vec2(-1.0, 1.0)) * inverseVP; - v_rgbSE = (fragCoord + vec2(1.0, 1.0)) * inverseVP; - v_rgbM = vec2(fragCoord * inverseVP); -} - +#include vec4 aa_apply( texture2D tex, sampler smplr, @@ -121,20 +6,5 @@ vec4 aa_apply( vec2 fragCoord, vec2 resolution ) { - mediump vec2 v_rgbNW; - mediump vec2 v_rgbNE; - mediump vec2 v_rgbSW; - mediump vec2 v_rgbSE; - mediump vec2 v_rgbM; - - float fxaa_scale = textureSize(sampler2D(tex, smplr), 0).x * 1.25 / resolution.x; - - vec2 scaled_fc = fragCoord * fxaa_scale; - vec2 scaled_res = resolution * fxaa_scale; - - //compute the texture coords - texcoords(scaled_fc, scaled_res, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); - - //compute FXAA - return fxaa(tex, smplr, scaled_fc, scaled_res, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); + return fxaa_apply(tex, smplr, fragCoord, resolution); } diff --git a/assets/voxygen/shaders/antialias/fxupscale.glsl b/assets/voxygen/shaders/antialias/fxupscale.glsl new file mode 100644 index 0000000000..a27ae66326 --- /dev/null +++ b/assets/voxygen/shaders/antialias/fxupscale.glsl @@ -0,0 +1,24 @@ +#include + +vec4 aa_apply( + texture2D tex, sampler smplr, + texture2D depth_tex, sampler depth_smplr, + vec2 fragCoord, + vec2 resolution +) { + vec4 aa_color = fxaa_apply(tex, smplr, fragCoord, resolution); + + vec2 sz = textureSize(sampler2D(tex, smplr), 0).xy; + vec4 closest = vec4(1000); + float closest_dist = 1000.0; + ivec2 dirs[] = { ivec2(-1, 0), ivec2(1, 0), ivec2(0, -1), ivec2(0, 1), /*ivec2(-1, -1), ivec2(-1, 1), ivec2(1, -1), ivec2(1, 1)*/ }; + for (uint i = 0u; i < dirs.length(); i ++) { + vec4 col_at = texelFetch(sampler2D(tex, smplr), ivec2(fragCoord / screen_res.xy * sz) + dirs[i], 0); + float dist = dot(pow(aa_color.rgb - col_at.rgb, ivec3(2)), vec3(1)); + if (dist < closest_dist) { + closest = col_at; + closest_dist = dist; + } + } + return mix(aa_color, closest, clamp(1.0 - sqrt(closest_dist), 0, 1)); +} diff --git a/assets/voxygen/shaders/include/fxaa.glsl b/assets/voxygen/shaders/include/fxaa.glsl new file mode 100644 index 0000000000..e11ad9738f --- /dev/null +++ b/assets/voxygen/shaders/include/fxaa.glsl @@ -0,0 +1,139 @@ +/** +Basic FXAA implementation based on the code on geeks3d.com with the +modification that the texture2DLod stuff was removed since it's +unsupported by WebGL. + +-- + +From: +https://github.com/mitsuhiko/webgl-meincraft + +Copyright (c) 2011 by Armin Ronacher. + +Some rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + + * The names of the contributors may not be used to endorse or + promote products derived from this software without specific + prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef FXAA_REDUCE_MIN + #define FXAA_REDUCE_MIN (1.0/ 128.0) +#endif +#ifndef FXAA_REDUCE_MUL + #define FXAA_REDUCE_MUL (1.0 / 8.0) +#endif +#ifndef FXAA_SPAN_MAX + #define FXAA_SPAN_MAX 8.0 +#endif + +//optimized version for mobile, where dependent +//texture reads can be a bottleneck +vec4 fxaa(texture2D tex, sampler smplr, vec2 fragCoord, vec2 resolution, + vec2 v_rgbNW, vec2 v_rgbNE, + vec2 v_rgbSW, vec2 v_rgbSE, + vec2 v_rgbM) { + vec4 color; + mediump vec2 inverseVP = vec2(1.0 / resolution.x, 1.0 / resolution.y); + vec3 rgbNW = texture(sampler2D(tex, smplr), v_rgbNW).xyz; + vec3 rgbNE = texture(sampler2D(tex, smplr), v_rgbNE).xyz; + vec3 rgbSW = texture(sampler2D(tex, smplr), v_rgbSW).xyz; + vec3 rgbSE = texture(sampler2D(tex, smplr), v_rgbSE).xyz; + vec4 texColor = texture(sampler2D(tex, smplr), v_rgbM); + vec3 rgbM = texColor.xyz; + vec3 luma = vec3(0.299, 0.587, 0.114); + float lumaNW = dot(rgbNW, luma); + float lumaNE = dot(rgbNE, luma); + float lumaSW = dot(rgbSW, luma); + float lumaSE = dot(rgbSE, luma); + float lumaM = dot(rgbM, luma); + float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE))); + float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE))); + + mediump vec2 dir; + dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE)); + dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE)); + + float dirReduce = max((lumaNW + lumaNE + lumaSW + lumaSE) * + (0.25 * FXAA_REDUCE_MUL), FXAA_REDUCE_MIN); + + float rcpDirMin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce); + dir = min(vec2(FXAA_SPAN_MAX, FXAA_SPAN_MAX), + max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX), + dir * rcpDirMin)) * inverseVP; + + vec3 rgbA = 0.5 * ( + texture(sampler2D(tex, smplr), fragCoord * inverseVP + dir * (1.0 / 3.0 - 0.5)).xyz + + texture(sampler2D(tex, smplr), fragCoord * inverseVP + dir * (2.0 / 3.0 - 0.5)).xyz); + vec3 rgbB = rgbA * 0.5 + 0.25 * ( + texture(sampler2D(tex, smplr), fragCoord * inverseVP + dir * -0.5).xyz + + texture(sampler2D(tex, smplr), fragCoord * inverseVP + dir * 0.5).xyz); + + float lumaB = dot(rgbB, luma); + if ((lumaB < lumaMin) || (lumaB > lumaMax)) + color = vec4(rgbA, texColor.a); + else + color = vec4(rgbB, texColor.a); + return color; +} + + +void texcoords(vec2 fragCoord, vec2 resolution, + out vec2 v_rgbNW, out vec2 v_rgbNE, + out vec2 v_rgbSW, out vec2 v_rgbSE, + out vec2 v_rgbM) { + vec2 inverseVP = 1.0 / resolution.xy; + const float scale = 0.75; + v_rgbNW = (fragCoord + vec2(-scale, -scale)) * inverseVP; + v_rgbNE = (fragCoord + vec2(scale, -scale)) * inverseVP; + v_rgbSW = (fragCoord + vec2(-scale, scale)) * inverseVP; + v_rgbSE = (fragCoord + vec2(scale, scale)) * inverseVP; + v_rgbM = vec2(fragCoord * inverseVP); +} + +vec4 fxaa_apply( + texture2D tex, sampler smplr, + vec2 fragCoord, + vec2 resolution +) { + mediump vec2 v_rgbNW; + mediump vec2 v_rgbNE; + mediump vec2 v_rgbSW; + mediump vec2 v_rgbSE; + mediump vec2 v_rgbM; + + float fxaa_scale = textureSize(sampler2D(tex, smplr), 0).x / resolution.x; + + vec2 scaled_fc = fragCoord * fxaa_scale; + vec2 scaled_res = resolution * fxaa_scale; + + //compute the texture coords + texcoords(scaled_fc, scaled_res, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); + + //compute FXAA + return fxaa(tex, smplr, scaled_fc, scaled_res, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); +} diff --git a/assets/voxygen/shaders/postprocess-frag.glsl b/assets/voxygen/shaders/postprocess-frag.glsl index 89863db99b..98c1d1b182 100644 --- a/assets/voxygen/shaders/postprocess-frag.glsl +++ b/assets/voxygen/shaders/postprocess-frag.glsl @@ -217,7 +217,6 @@ void main() { vec4 aa_color = aa_apply(t_src_color, s_src_color, t_src_depth, s_src_depth, sample_uv * screen_res.xy, screen_res.xy); - #ifdef EXPERIMENTAL_SOBEL vec3 s[8]; s[0] = aa_sample(uv, vec2(-1, 1)); diff --git a/voxygen/src/hud/settings_window/video.rs b/voxygen/src/hud/settings_window/video.rs index 7c9950adf5..c548c3cea3 100644 --- a/voxygen/src/hud/settings_window/video.rs +++ b/voxygen/src/hud/settings_window/video.rs @@ -806,6 +806,7 @@ impl<'a> Widget for Video<'a> { /* AaMode::MsaaX4, AaMode::MsaaX8, AaMode::MsaaX16, */ + AaMode::FxUpscale, AaMode::Hqx, ]; let mode_label_list = [ @@ -814,6 +815,7 @@ impl<'a> Widget for Video<'a> { /* "MSAA x4", "MSAA x8", "MSAA x16 (experimental)", */ + "FXUpscale", "HQX", ]; diff --git a/voxygen/src/render/mod.rs b/voxygen/src/render/mod.rs index 2ce83b4c31..7ad00203eb 100644 --- a/voxygen/src/render/mod.rs +++ b/voxygen/src/render/mod.rs @@ -93,12 +93,17 @@ pub enum AaMode { /// also struggle in the future with deferred shading, so they may be /// removed in the future. MsaaX16, - /// Fast upscaling re-aliasing. + /// Fast edge-detecting upscaling. /// /// Screen-space technique that attempts to reconstruct lines and edges /// in the original image. Useless at internal resolutions higher than 1.0x, /// but potentially very effective at much lower internal resolutions. Hqx, + /// Fast upscaling informed by FXAA. + /// + /// Screen-space technique that uses a combination of FXAA and + /// nearest-neighbour sample retargeting to produce crisp, clean upscaling. + FxUpscale, #[serde(other)] None, } @@ -106,7 +111,7 @@ pub enum AaMode { impl AaMode { pub fn samples(&self) -> u32 { match self { - AaMode::None | AaMode::Fxaa | AaMode::Hqx => 1, + AaMode::None | AaMode::Fxaa | AaMode::Hqx | AaMode::FxUpscale => 1, AaMode::MsaaX4 => 4, AaMode::MsaaX8 => 8, AaMode::MsaaX16 => 16, diff --git a/voxygen/src/render/renderer/pipeline_creation.rs b/voxygen/src/render/renderer/pipeline_creation.rs index 0da02dfb2d..5a34791be8 100644 --- a/voxygen/src/render/renderer/pipeline_creation.rs +++ b/voxygen/src/render/renderer/pipeline_creation.rs @@ -164,6 +164,7 @@ impl ShaderModules { let shadows = shaders.get("include.shadows").unwrap(); let rain_occlusion = shaders.get("include.rain_occlusion").unwrap(); let point_glow = shaders.get("include.point_glow").unwrap(); + let fxaa = shaders.get("include.fxaa").unwrap(); // We dynamically add extra configuration settings to the constants file. let mut constants = format!( @@ -255,6 +256,7 @@ impl ShaderModules { AaMode::MsaaX8 => "antialias.msaa-x8", AaMode::MsaaX16 => "antialias.msaa-x16", AaMode::Hqx => "antialias.hqx", + AaMode::FxUpscale => "antialias.fxupscale", }) .unwrap(); @@ -285,6 +287,7 @@ impl ShaderModules { "anti-aliasing.glsl" => anti_alias.0.to_owned(), "cloud.glsl" => cloud.0.to_owned(), "point_glow.glsl" => point_glow.0.to_owned(), + "fxaa.glsl" => fxaa.0.to_owned(), other => { return Err(format!( "Include {} in {} is not defined", diff --git a/voxygen/src/render/renderer/shaders.rs b/voxygen/src/render/renderer/shaders.rs index 15cd46a21c..a735bd88d5 100644 --- a/voxygen/src/render/renderer/shaders.rs +++ b/voxygen/src/render/renderer/shaders.rs @@ -36,12 +36,14 @@ impl assets::Compound for Shaders { "include.shadows", "include.rain_occlusion", "include.point_glow", + "include.fxaa", "antialias.none", "antialias.fxaa", "antialias.msaa-x4", "antialias.msaa-x8", "antialias.msaa-x16", "antialias.hqx", + "antialias.fxupscale", "include.cloud.none", "include.cloud.regular", "figure-vert", From 589f59b771161ea0d3e2dcab4135d6f166f2946b Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Wed, 26 Oct 2022 00:51:23 +0100 Subject: [PATCH 2/4] Improve FxUpscale quality for distant objects --- assets/voxygen/shaders/antialias/fxaa.glsl | 2 +- .../voxygen/shaders/antialias/fxupscale.glsl | 18 +++++++++++++++--- assets/voxygen/shaders/include/fxaa.glsl | 5 +++-- 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/assets/voxygen/shaders/antialias/fxaa.glsl b/assets/voxygen/shaders/antialias/fxaa.glsl index baf2e3af1c..8b7f94b3a9 100644 --- a/assets/voxygen/shaders/antialias/fxaa.glsl +++ b/assets/voxygen/shaders/antialias/fxaa.glsl @@ -6,5 +6,5 @@ vec4 aa_apply( vec2 fragCoord, vec2 resolution ) { - return fxaa_apply(tex, smplr, fragCoord, resolution); + return fxaa_apply(tex, smplr, fragCoord, resolution, 1.0); } diff --git a/assets/voxygen/shaders/antialias/fxupscale.glsl b/assets/voxygen/shaders/antialias/fxupscale.glsl index a27ae66326..c8c1fdfcc0 100644 --- a/assets/voxygen/shaders/antialias/fxupscale.glsl +++ b/assets/voxygen/shaders/antialias/fxupscale.glsl @@ -6,19 +6,31 @@ vec4 aa_apply( vec2 fragCoord, vec2 resolution ) { - vec4 aa_color = fxaa_apply(tex, smplr, fragCoord, resolution); + ivec2 dirs[] = { ivec2(-1, 0), ivec2(1, 0), ivec2(0, -1), ivec2(0, 1), /*ivec2(-1, -1), ivec2(-1, 1), ivec2(1, -1), ivec2(1, 1)*/ }; vec2 sz = textureSize(sampler2D(tex, smplr), 0).xy; + + float min_depth = 1000; + float max_depth = 0; + for (uint i = 0u; i < dirs.length(); i ++) { + float d = texelFetch(sampler2D(depth_tex, depth_smplr), ivec2(fragCoord / screen_res.xy * sz) + dirs[i], 0).x; + min_depth = min(min_depth, d); + max_depth = max(max_depth, d); + } + + vec4 aa_color = fxaa_apply(tex, smplr, fragCoord, resolution, 1.0 + 1.0 / (min_depth * 0 + 0.001 + (max_depth - min_depth) * 500) * 0.001); + vec4 closest = vec4(1000); float closest_dist = 1000.0; - ivec2 dirs[] = { ivec2(-1, 0), ivec2(1, 0), ivec2(0, -1), ivec2(0, 1), /*ivec2(-1, -1), ivec2(-1, 1), ivec2(1, -1), ivec2(1, 1)*/ }; for (uint i = 0u; i < dirs.length(); i ++) { vec4 col_at = texelFetch(sampler2D(tex, smplr), ivec2(fragCoord / screen_res.xy * sz) + dirs[i], 0); + //float depth_at = texelFetch(sampler2D(depth_tex, depth_smplr), ivec2(fragCoord / screen_res.xy * sz) + dirs[i], 0).x; float dist = dot(pow(aa_color.rgb - col_at.rgb, ivec3(2)), vec3(1)); if (dist < closest_dist) { closest = col_at; closest_dist = dist; } } - return mix(aa_color, closest, clamp(1.0 - sqrt(closest_dist), 0, 1)); + //return texelFetch(sampler2D(tex, smplr), ivec2(fragCoord / screen_res.xy * sz), 0); + return closest;//mix(aa_color, closest, clamp(1.0 - sqrt(closest_dist) / length(aa_color.rgb) * 0.25, 0, 1)); } diff --git a/assets/voxygen/shaders/include/fxaa.glsl b/assets/voxygen/shaders/include/fxaa.glsl index e11ad9738f..54e12e7735 100644 --- a/assets/voxygen/shaders/include/fxaa.glsl +++ b/assets/voxygen/shaders/include/fxaa.glsl @@ -118,7 +118,8 @@ void texcoords(vec2 fragCoord, vec2 resolution, vec4 fxaa_apply( texture2D tex, sampler smplr, vec2 fragCoord, - vec2 resolution + vec2 resolution, + float sampleScale ) { mediump vec2 v_rgbNW; mediump vec2 v_rgbNE; @@ -126,7 +127,7 @@ vec4 fxaa_apply( mediump vec2 v_rgbSE; mediump vec2 v_rgbM; - float fxaa_scale = textureSize(sampler2D(tex, smplr), 0).x / resolution.x; + float fxaa_scale = textureSize(sampler2D(tex, smplr), 0).x / resolution.x * sampleScale; vec2 scaled_fc = fragCoord * fxaa_scale; vec2 scaled_res = resolution * fxaa_scale; From 4db88bb22c00674a48828c63280085663fc359b2 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Wed, 26 Oct 2022 21:10:43 +0100 Subject: [PATCH 3/4] Better sampling of noisy regions --- assets/voxygen/shaders/antialias/fxupscale.glsl | 12 ++++++++---- assets/voxygen/shaders/include/fxaa.glsl | 2 +- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/assets/voxygen/shaders/antialias/fxupscale.glsl b/assets/voxygen/shaders/antialias/fxupscale.glsl index c8c1fdfcc0..39262bf63d 100644 --- a/assets/voxygen/shaders/antialias/fxupscale.glsl +++ b/assets/voxygen/shaders/antialias/fxupscale.glsl @@ -6,10 +6,12 @@ vec4 aa_apply( vec2 fragCoord, vec2 resolution ) { - ivec2 dirs[] = { ivec2(-1, 0), ivec2(1, 0), ivec2(0, -1), ivec2(0, 1), /*ivec2(-1, -1), ivec2(-1, 1), ivec2(1, -1), ivec2(1, 1)*/ }; + ivec2 dirs[] = { ivec2(-1, 0), ivec2(1, 0), ivec2(0, -1), ivec2(0, 1) }; vec2 sz = textureSize(sampler2D(tex, smplr), 0).xy; + //float center_d = texelFetch(sampler2D(depth_tex, depth_smplr), ivec2(fragCoord / screen_res.xy * sz), 0).x; + float min_depth = 1000; float max_depth = 0; for (uint i = 0u; i < dirs.length(); i ++) { @@ -19,18 +21,20 @@ vec4 aa_apply( } vec4 aa_color = fxaa_apply(tex, smplr, fragCoord, resolution, 1.0 + 1.0 / (min_depth * 0 + 0.001 + (max_depth - min_depth) * 500) * 0.001); + vec4 lerped = texture(sampler2D(tex, smplr), fragCoord / screen_res.xy); + //aa_color = lerped; - vec4 closest = vec4(1000); + vec4 closest = aa_color; float closest_dist = 1000.0; for (uint i = 0u; i < dirs.length(); i ++) { vec4 col_at = texelFetch(sampler2D(tex, smplr), ivec2(fragCoord / screen_res.xy * sz) + dirs[i], 0); //float depth_at = texelFetch(sampler2D(depth_tex, depth_smplr), ivec2(fragCoord / screen_res.xy * sz) + dirs[i], 0).x; float dist = dot(pow(aa_color.rgb - col_at.rgb, ivec3(2)), vec3(1)); if (dist < closest_dist) { - closest = col_at; + closest = mix(col_at, lerped, min(length(lerped.rgb - col_at.rgb) * 0.25, 1)); closest_dist = dist; } } //return texelFetch(sampler2D(tex, smplr), ivec2(fragCoord / screen_res.xy * sz), 0); - return closest;//mix(aa_color, closest, clamp(1.0 - sqrt(closest_dist) / length(aa_color.rgb) * 0.25, 0, 1)); + return closest;//mix(aa_color, closest, clamp(1.0 - sqrt(closest_dist) / length(aa_color.rgb) * 0.75, 0, 1)); } diff --git a/assets/voxygen/shaders/include/fxaa.glsl b/assets/voxygen/shaders/include/fxaa.glsl index 54e12e7735..045840bc07 100644 --- a/assets/voxygen/shaders/include/fxaa.glsl +++ b/assets/voxygen/shaders/include/fxaa.glsl @@ -48,7 +48,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define FXAA_REDUCE_MUL (1.0 / 8.0) #endif #ifndef FXAA_SPAN_MAX - #define FXAA_SPAN_MAX 8.0 + #define FXAA_SPAN_MAX 12.0 #endif //optimized version for mobile, where dependent From 29d40cf50944830b7a86b2061ebb6fa334184ca2 Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Wed, 26 Oct 2022 23:15:07 +0100 Subject: [PATCH 4/4] Added graphics presets --- CHANGELOG.md | 2 + assets/voxygen/i18n/en/hud/settings.ftl | 5 + assets/voxygen/shaders/include/light.glsl | 2 +- voxygen/src/hud/mod.rs | 1 + voxygen/src/hud/settings_window/video.rs | 107 ++++++++++++---- voxygen/src/render/mod.rs | 2 +- voxygen/src/session/settings_change.rs | 59 +++++---- voxygen/src/settings/graphics.rs | 141 ++++++++++++++++++++++ 8 files changed, 270 insertions(+), 49 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1c8f39b70d..163566091b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added screen-space reflection and refraction shaders - Added reflection quality setting - UI: Added a poise indicator to the player's status bars +- FxUpscale AA mode for higher quality graphics at reduced internal resolutions +- Graphics presets ### Changed - Use fluent for translations diff --git a/assets/voxygen/i18n/en/hud/settings.ftl b/assets/voxygen/i18n/en/hud/settings.ftl index e60754abd1..c64b5693c3 100644 --- a/assets/voxygen/i18n/en/hud/settings.ftl +++ b/assets/voxygen/i18n/en/hud/settings.ftl @@ -111,6 +111,11 @@ hud-settings-rain_occlusion-resolution = Rain Occlusion Resolution hud-settings-lod_detail = LoD Detail hud-settings-save_window_size = Save window size hud-settings-reset_graphics = Reset to Defaults +hud-settings-minimal_graphics = Minimal +hud-settings-low_graphics = Low +hud-settings-medium_graphics = Medium +hud-settings-high_graphics = High +hud-settings-ultra_graphics = Ultra hud-settings-bloom = Bloom hud-settings-point_glow = Point Glow hud-settings-master_volume = Master Volume diff --git a/assets/voxygen/shaders/include/light.glsl b/assets/voxygen/shaders/include/light.glsl index 213ad56551..999cf2cdb5 100644 --- a/assets/voxygen/shaders/include/light.glsl +++ b/assets/voxygen/shaders/include/light.glsl @@ -110,7 +110,7 @@ float shadow_at(vec3 wpos, vec3 wnorm) { diff.z = -sign(diff.z) * diff.z * 0.1; } - float shade = max(pow(diff.x * diff.x + diff.y * diff.y + diff.z * diff.z, 0.25) / pow(radius * radius * 0.5, 0.25), 0.5); + float shade = max(pow(diff.x * diff.x + diff.y * diff.y + diff.z * diff.z, 0.35) / pow(radius * radius * 0.5, 0.5), 0.5); // float shade = max(pow(dot(diff, diff) / (radius * radius * 0.5), 0.25), 0.5); // float shade = dot(diff, diff) / (radius * radius * 0.5); diff --git a/voxygen/src/hud/mod.rs b/voxygen/src/hud/mod.rs index 3424fbdefb..3c594a3857 100644 --- a/voxygen/src/hud/mod.rs +++ b/voxygen/src/hud/mod.rs @@ -193,6 +193,7 @@ const DEFAULT_NPC: Color = Color::Rgba(1.0, 1.0, 1.0, 1.0); // UI Color-Theme const UI_MAIN: Color = Color::Rgba(0.61, 0.70, 0.70, 1.0); // Greenish Blue +const UI_SUBTLE: Color = Color::Rgba(0.2, 0.24, 0.24, 1.0); // Dark Greenish Blue //const UI_MAIN: Color = Color::Rgba(0.1, 0.1, 0.1, 0.97); // Dark const UI_HIGHLIGHT_0: Color = Color::Rgba(0.79, 1.09, 1.09, 1.0); // Pull-Down menu BG color diff --git a/voxygen/src/hud/settings_window/video.rs b/voxygen/src/hud/settings_window/video.rs index c548c3cea3..a53b73b597 100644 --- a/voxygen/src/hud/settings_window/video.rs +++ b/voxygen/src/hud/settings_window/video.rs @@ -3,14 +3,14 @@ use super::{RESET_BUTTONS_HEIGHT, RESET_BUTTONS_WIDTH}; use crate::{ hud::{ img_ids::Imgs, CRITICAL_HP_COLOR, HP_COLOR, LOW_HP_COLOR, MENU_BG, STAMINA_COLOR, - TEXT_COLOR, + TEXT_COLOR, UI_HIGHLIGHT_0, UI_MAIN, UI_SUBTLE, }, render::{ AaMode, BloomConfig, BloomFactor, BloomMode, CloudMode, FluidMode, LightingMode, PresentMode, ReflectionMode, RenderMode, ShadowMapMode, ShadowMode, UpscaleMode, }, session::settings_change::Graphics as GraphicsChange, - settings::Fps, + settings::{Fps, GraphicsSettings}, ui::{fonts::Fonts, ImageSlider, ToggleButton}, window::{FullScreenSettings, FullscreenMode}, GlobalState, @@ -25,7 +25,7 @@ use core::convert::TryFrom; use i18n::Localization; use itertools::Itertools; -use std::iter::once; +use std::{iter::once, rc::Rc}; use winit::monitor::VideoMode; widget_ids! { @@ -34,6 +34,11 @@ widget_ids! { window_r, window_scrollbar, reset_graphics_button, + minimal_graphics_button, + low_graphics_button, + medium_graphics_button, + high_graphics_button, + ultra_graphics_button, fps_counter, pipeline_recreation_text, terrain_vd_slider, @@ -284,9 +289,81 @@ impl<'a> Widget for Video<'a> { .set(state.ids.pipeline_recreation_text, ui); } + // Reset the graphics settings to the default settings + if Button::image(self.imgs.button) + .w_h(RESET_BUTTONS_WIDTH, RESET_BUTTONS_HEIGHT) + .hover_image(self.imgs.button_hover) + .press_image(self.imgs.button_press) + .top_left_with_margins_on(state.ids.window, 10.0, 10.0) + .label( + &self + .localized_strings + .get_msg("hud-settings-reset_graphics"), + ) + .label_font_size(self.fonts.cyri.scale(14)) + .label_color(TEXT_COLOR) + .label_font_id(self.fonts.cyri.conrod_id) + .label_y(Relative::Scalar(2.0)) + .set(state.ids.reset_graphics_button, ui) + .was_clicked() + { + events.push(GraphicsChange::ResetGraphicsSettings); + } + + // Graphics presets buttons + let preset_buttons: [(_, _, fn(_) -> _); 5] = [ + ( + "hud-settings-minimal_graphics", + state.ids.minimal_graphics_button, + GraphicsSettings::into_minimal, + ), + ( + "hud-settings-low_graphics", + state.ids.low_graphics_button, + GraphicsSettings::into_low, + ), + ( + "hud-settings-medium_graphics", + state.ids.medium_graphics_button, + GraphicsSettings::into_medium, + ), + ( + "hud-settings-high_graphics", + state.ids.high_graphics_button, + GraphicsSettings::into_high, + ), + ( + "hud-settings-ultra_graphics", + state.ids.ultra_graphics_button, + GraphicsSettings::into_ultra, + ), + ]; + + let mut lhs = state.ids.reset_graphics_button; + + for (msg, id, change_fn) in preset_buttons { + if Button::new() + .label(&self.localized_strings.get_msg(msg)) + .w_h(80.0, 34.0) + .color(UI_SUBTLE) + .hover_color(UI_MAIN) + .press_color(UI_HIGHLIGHT_0) + .right_from(lhs, 12.0) + .label_font_size(self.fonts.cyri.scale(14)) + .label_color(TEXT_COLOR) + .label_font_id(self.fonts.cyri.conrod_id) + .label_y(Relative::Scalar(2.0)) + .set(id, ui) + .was_clicked() + { + events.push(GraphicsChange::ChangeGraphicsSettings(Rc::new(change_fn))); + } + lhs = id; + } + // View Distance Text::new(&self.localized_strings.get_msg("hud-settings-view_distance")) - .top_left_with_margins_on(state.ids.window, 10.0, 10.0) + .down_from(state.ids.reset_graphics_button, 10.0) .font_size(self.fonts.cyri.scale(14)) .font_id(self.fonts.cyri.conrod_id) .color(TEXT_COLOR) @@ -1671,28 +1748,6 @@ impl<'a> Widget for Video<'a> { )); } - // Reset the graphics settings to the default settings - if Button::image(self.imgs.button) - .w_h(RESET_BUTTONS_WIDTH, RESET_BUTTONS_HEIGHT) - .hover_image(self.imgs.button_hover) - .press_image(self.imgs.button_press) - .down_from(state.ids.fullscreen_mode_list, 12.0) - .right_from(state.ids.save_window_size_button, 12.0) - .label( - &self - .localized_strings - .get_msg("hud-settings-reset_graphics"), - ) - .label_font_size(self.fonts.cyri.scale(14)) - .label_color(TEXT_COLOR) - .label_font_id(self.fonts.cyri.conrod_id) - .label_y(Relative::Scalar(2.0)) - .set(state.ids.reset_graphics_button, ui) - .was_clicked() - { - events.push(GraphicsChange::ResetGraphicsSettings); - } - events } } diff --git a/voxygen/src/render/mod.rs b/voxygen/src/render/mod.rs index 7ad00203eb..6ed5d44831 100644 --- a/voxygen/src/render/mod.rs +++ b/voxygen/src/render/mod.rs @@ -199,7 +199,7 @@ pub enum ReflectionMode { } impl Default for ReflectionMode { - fn default() -> Self { ReflectionMode::Medium } + fn default() -> Self { ReflectionMode::High } } /// Lighting modes diff --git a/voxygen/src/session/settings_change.rs b/voxygen/src/session/settings_change.rs index 7c3afcde43..356580215f 100644 --- a/voxygen/src/session/settings_change.rs +++ b/voxygen/src/session/settings_change.rs @@ -15,6 +15,7 @@ use crate::{ GlobalState, }; use i18n::{LanguageMetadata, LocalizationHandle}; +use std::rc::Rc; #[derive(Clone)] pub enum Audio { @@ -98,6 +99,7 @@ pub enum Graphics { AdjustWindowSize([u16; 2]), ResetGraphicsSettings, + ChangeGraphicsSettings(Rc GraphicsSettings>), } #[derive(Clone)] pub enum Interface { @@ -410,6 +412,8 @@ impl SettingsChange { } }, SettingsChange::Graphics(graphics_change) => { + let mut change_all = false; + match graphics_change { Graphics::AdjustTerrainViewDistance(terrain_vd) => { adjust_terrain_view_distance(terrain_vd, settings, session_state) @@ -486,28 +490,41 @@ impl SettingsChange { }, Graphics::ResetGraphicsSettings => { settings.graphics = GraphicsSettings::default(); - let graphics = &settings.graphics; - // View distance - client_set_view_distance(settings, session_state); - // FOV - session_state.scene.camera_mut().set_fov_deg(graphics.fov); - session_state - .scene - .camera_mut() - .compute_dependents(&session_state.client.borrow().state().terrain()); - // LoD - session_state.scene.lod.set_detail(graphics.lod_detail); - // Render mode - global_state - .window - .renderer_mut() - .set_render_mode(graphics.render_mode.clone()) - .unwrap(); - // Fullscreen mode - global_state.window.set_fullscreen_mode(graphics.fullscreen); - // Window size - global_state.window.set_size(graphics.window_size.into()); + change_all = true; }, + Graphics::ChangeGraphicsSettings(f) => { + settings.graphics = f(settings.graphics.clone()); + change_all = true; + }, + } + + if change_all { + let graphics = &settings.graphics; + // View distance + client_set_view_distance(settings, session_state); + // FOV + session_state.scene.camera_mut().set_fov_deg(graphics.fov); + session_state + .scene + .camera_mut() + .compute_dependents(&session_state.client.borrow().state().terrain()); + // LoD + session_state.scene.lod.set_detail(graphics.lod_detail); + // LoD distance + session_state + .client + .borrow_mut() + .set_lod_distance(graphics.lod_distance); + // Render mode + global_state + .window + .renderer_mut() + .set_render_mode(graphics.render_mode.clone()) + .unwrap(); + // Fullscreen mode + global_state.window.set_fullscreen_mode(graphics.fullscreen); + // Window size + global_state.window.set_size(graphics.window_size.into()); } }, SettingsChange::Interface(interface_change) => { diff --git a/voxygen/src/settings/graphics.rs b/voxygen/src/settings/graphics.rs index c8919a5a76..904b8815e2 100644 --- a/voxygen/src/settings/graphics.rs +++ b/voxygen/src/settings/graphics.rs @@ -71,3 +71,144 @@ impl Default for GraphicsSettings { } } } + +impl GraphicsSettings { + pub fn into_minimal(self) -> Self { + use crate::render::*; + Self { + terrain_view_distance: 4, + entity_view_distance: 4, + lod_distance: 0, + sprite_render_distance: 80, + figure_lod_render_distance: 100, + lod_detail: 80, + render_mode: RenderMode { + aa: AaMode::FxUpscale, + cloud: CloudMode::Minimal, + reflection: ReflectionMode::Low, + fluid: FluidMode::Low, + lighting: LightingMode::Lambertian, + shadow: ShadowMode::None, + rain_occlusion: ShadowMapMode { resolution: 0.25 }, + bloom: BloomMode::Off, + point_glow: 0.0, + upscale_mode: UpscaleMode { factor: 0.35 }, + ..self.render_mode + }, + ..self + } + } + + pub fn into_low(self) -> Self { + use crate::render::*; + Self { + terrain_view_distance: 7, + entity_view_distance: 7, + lod_distance: 75, + sprite_render_distance: 125, + figure_lod_render_distance: 200, + lod_detail: 200, + render_mode: RenderMode { + aa: AaMode::FxUpscale, + cloud: CloudMode::Low, + reflection: ReflectionMode::Medium, + fluid: FluidMode::Low, + lighting: LightingMode::Lambertian, + shadow: ShadowMode::Cheap, + rain_occlusion: ShadowMapMode { resolution: 0.25 }, + bloom: BloomMode::Off, + point_glow: 0.35, + upscale_mode: UpscaleMode { factor: 0.65 }, + ..self.render_mode + }, + ..self + } + } + + pub fn into_medium(self) -> Self { + use crate::render::*; + Self { + terrain_view_distance: 10, + entity_view_distance: 10, + lod_distance: 150, + sprite_render_distance: 250, + figure_lod_render_distance: 350, + lod_detail: 300, + render_mode: RenderMode { + aa: AaMode::Fxaa, + cloud: CloudMode::Medium, + reflection: ReflectionMode::High, + fluid: FluidMode::Medium, + lighting: LightingMode::BlinnPhong, + shadow: ShadowMode::Map(ShadowMapMode { resolution: 0.75 }), + rain_occlusion: ShadowMapMode { resolution: 0.25 }, + bloom: BloomMode::On(BloomConfig { + factor: BloomFactor::Medium, + uniform_blur: false, + }), + point_glow: 0.35, + upscale_mode: UpscaleMode { factor: 0.85 }, + ..self.render_mode + }, + ..self + } + } + + pub fn into_high(self) -> Self { + use crate::render::*; + Self { + terrain_view_distance: 16, + entity_view_distance: 16, + lod_distance: 200, + sprite_render_distance: 350, + figure_lod_render_distance: 450, + lod_detail: 375, + render_mode: RenderMode { + aa: AaMode::Fxaa, + cloud: CloudMode::Medium, + reflection: ReflectionMode::High, + fluid: FluidMode::Medium, + lighting: LightingMode::Ashikhmin, + shadow: ShadowMode::Map(ShadowMapMode { resolution: 1.0 }), + rain_occlusion: ShadowMapMode { resolution: 0.5 }, + bloom: BloomMode::On(BloomConfig { + factor: BloomFactor::Medium, + uniform_blur: true, + }), + point_glow: 0.35, + upscale_mode: UpscaleMode { factor: 1.0 }, + ..self.render_mode + }, + ..self + } + } + + pub fn into_ultra(self) -> Self { + use crate::render::*; + Self { + terrain_view_distance: 16, + entity_view_distance: 16, + lod_distance: 450, + sprite_render_distance: 800, + figure_lod_render_distance: 600, + lod_detail: 500, + render_mode: RenderMode { + aa: AaMode::Fxaa, + cloud: CloudMode::High, + reflection: ReflectionMode::High, + fluid: FluidMode::High, + lighting: LightingMode::Ashikhmin, + shadow: ShadowMode::Map(ShadowMapMode { resolution: 1.75 }), + rain_occlusion: ShadowMapMode { resolution: 0.5 }, + bloom: BloomMode::On(BloomConfig { + factor: BloomFactor::Medium, + uniform_blur: true, + }), + point_glow: 0.35, + upscale_mode: UpscaleMode { factor: 1.25 }, + ..self.render_mode + }, + ..self + } + } +}