Skip to content

Commit c09a3a5

Browse files
authored
Add antialiasing filters (FXAA, SSAA) (#13253)
1 parent 442d5fc commit c09a3a5

10 files changed

+230
-17
lines changed

builtin/settingtypes.txt

+21-8
Original file line numberDiff line numberDiff line change
@@ -342,14 +342,27 @@ texture_clean_transparent (Clean transparent textures) bool false
342342
# texture autoscaling.
343343
texture_min_size (Minimum texture size) int 64 1 32768
344344

345-
# Use multi-sample antialiasing (MSAA) to smooth out block edges.
346-
# This algorithm smooths out the 3D viewport while keeping the image sharp,
347-
# but it doesn't affect the insides of textures
348-
# (which is especially noticeable with transparent textures).
349-
# Visible spaces appear between nodes when shaders are disabled.
350-
# If set to 0, MSAA is disabled.
351-
# A restart is required after changing this option.
352-
fsaa (FSAA) enum 0 0,1,2,4,8,16
345+
# Select the antialiasing method to apply.
346+
#
347+
# * None - No antialiasing (default)
348+
#
349+
# * FSAA - Hardware-provided full-screen antialiasing (incompatible with shaders)
350+
# A.K.A multi-sample antialiasing (MSAA)
351+
# Smoothens out block edges but does not affect the insides of textures.
352+
# A restart is required to change this option.
353+
#
354+
# * FXAA - Fast approximate antialiasing (requires shaders)
355+
# Applies a post-processing filter to detect and smoothen high-contrast edges.
356+
# Provides balance between speed and image quality.
357+
#
358+
# * SSAA - Super-sampling antialiasing (requires shaders)
359+
# Renders higher-resolution image of the scene, then scales down to reduce
360+
# the aliasing effects. This is the slowest and the most accurate method.
361+
antialiasing (Antialiasing method) enum none none,fsaa,fxaa,ssaa
362+
363+
# Defines size of the sampling grid for FSAA and SSAA antializasing methods.
364+
# Value of 2 means taking 2x2 = 4 samples.
365+
fsaa (Anti-aliasing scale) enum 2 2,4,8,16
353366

354367
[**Occlusion Culling]
355368

+116
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
#define rendered texture0
2+
3+
uniform sampler2D rendered;
4+
uniform vec2 texelSize0;
5+
6+
varying vec2 sampleNW;
7+
varying vec2 sampleNE;
8+
varying vec2 sampleSW;
9+
varying vec2 sampleSE;
10+
11+
#ifdef GL_ES
12+
varying mediump vec2 varTexCoord;
13+
#else
14+
centroid varying vec2 varTexCoord;
15+
#endif
16+
17+
/**
18+
Basic FXAA implementation based on the code on geeks3d.com with the
19+
modification that the texture2DLod stuff was removed since it's
20+
unsupported by WebGL.
21+
--
22+
From:
23+
https://github.com/mitsuhiko/webgl-meincraft
24+
Copyright (c) 2011 by Armin Ronacher.
25+
Some rights reserved.
26+
Redistribution and use in source and binary forms, with or without
27+
modification, are permitted provided that the following conditions are
28+
met:
29+
* Redistributions of source code must retain the above copyright
30+
notice, this list of conditions and the following disclaimer.
31+
* Redistributions in binary form must reproduce the above
32+
copyright notice, this list of conditions and the following
33+
disclaimer in the documentation and/or other materials provided
34+
with the distribution.
35+
* The names of the contributors may not be used to endorse or
36+
promote products derived from this software without specific
37+
prior written permission.
38+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
39+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
40+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
41+
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
42+
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
43+
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
44+
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
45+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
46+
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
47+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
48+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
49+
*/
50+
51+
#ifndef FXAA_REDUCE_MIN
52+
#define FXAA_REDUCE_MIN (1.0/ 128.0)
53+
#endif
54+
#ifndef FXAA_REDUCE_MUL
55+
#define FXAA_REDUCE_MUL (1.0 / 8.0)
56+
#endif
57+
#ifndef FXAA_SPAN_MAX
58+
#define FXAA_SPAN_MAX 8.0
59+
#endif
60+
61+
//optimized version for mobile, where dependent
62+
//texture reads can be a bottleneck
63+
vec4 fxaa(sampler2D tex, vec2 fragCoord, vec2 inverseVP,
64+
vec2 v_rgbNW, vec2 v_rgbNE,
65+
vec2 v_rgbSW, vec2 v_rgbSE,
66+
vec2 v_rgbM) {
67+
vec4 color;
68+
vec3 rgbNW = texture2D(tex, v_rgbNW).xyz;
69+
vec3 rgbNE = texture2D(tex, v_rgbNE).xyz;
70+
vec3 rgbSW = texture2D(tex, v_rgbSW).xyz;
71+
vec3 rgbSE = texture2D(tex, v_rgbSE).xyz;
72+
vec4 texColor = texture2D(tex, v_rgbM);
73+
vec3 rgbM = texColor.xyz;
74+
vec3 luma = vec3(0.299, 0.587, 0.114);
75+
float lumaNW = dot(rgbNW, luma);
76+
float lumaNE = dot(rgbNE, luma);
77+
float lumaSW = dot(rgbSW, luma);
78+
float lumaSE = dot(rgbSE, luma);
79+
float lumaM = dot(rgbM, luma);
80+
float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE)));
81+
float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE)));
82+
83+
mediump vec2 dir;
84+
dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE));
85+
dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE));
86+
87+
float dirReduce = max((lumaNW + lumaNE + lumaSW + lumaSE) *
88+
(0.25 * FXAA_REDUCE_MUL), FXAA_REDUCE_MIN);
89+
90+
float rcpDirMin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce);
91+
dir = min(vec2(FXAA_SPAN_MAX, FXAA_SPAN_MAX),
92+
max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX),
93+
dir * rcpDirMin)) * inverseVP;
94+
95+
vec3 rgbA = 0.5 * (
96+
texture2D(tex, fragCoord + dir * (1.0 / 3.0 - 0.5)).xyz +
97+
texture2D(tex, fragCoord + dir * (2.0 / 3.0 - 0.5)).xyz);
98+
vec3 rgbB = rgbA * 0.5 + 0.25 * (
99+
texture2D(tex, fragCoord + dir * -0.5).xyz +
100+
texture2D(tex, fragCoord + dir * 0.5).xyz);
101+
102+
float lumaB = dot(rgbB, luma);
103+
if ((lumaB < lumaMin) || (lumaB > lumaMax))
104+
color = vec4(rgbA, 1.0);
105+
else
106+
color = vec4(rgbB, 1.0);
107+
return color;
108+
}
109+
110+
void main(void)
111+
{
112+
vec2 uv = varTexCoord.st;
113+
114+
gl_FragColor = fxaa(rendered, uv, texelSize0,
115+
sampleNW, sampleNE, sampleSW, sampleSE, uv);
116+
}
+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
uniform vec2 texelSize0;
2+
3+
#ifdef GL_ES
4+
varying mediump vec2 varTexCoord;
5+
#else
6+
centroid varying vec2 varTexCoord;
7+
#endif
8+
9+
varying vec2 sampleNW;
10+
varying vec2 sampleNE;
11+
varying vec2 sampleSW;
12+
varying vec2 sampleSE;
13+
14+
/*
15+
Based on
16+
https://github.com/mattdesl/glsl-fxaa/
17+
Portions Copyright (c) 2011 by Armin Ronacher.
18+
*/
19+
void main(void)
20+
{
21+
varTexCoord.st = inTexCoord0.st;
22+
sampleNW = varTexCoord.st + vec2(-1.0, -1.0) * texelSize0;
23+
sampleNE = varTexCoord.st + vec2(1.0, -1.0) * texelSize0;
24+
sampleSW = varTexCoord.st + vec2(-1.0, 1.0) * texelSize0;
25+
sampleSE = varTexCoord.st + vec2(1.0, 1.0) * texelSize0;
26+
gl_Position = inVertexPosition;
27+
}

client/shaders/second_stage/opengl_fragment.glsl

+10
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ struct ExposureParams {
88
uniform sampler2D rendered;
99
uniform sampler2D bloom;
1010

11+
uniform vec2 texelSize0;
12+
1113
uniform ExposureParams exposureParams;
1214
uniform lowp float bloomIntensity;
1315
uniform lowp float saturation;
@@ -80,7 +82,15 @@ vec3 applySaturation(vec3 color, float factor)
8082
void main(void)
8183
{
8284
vec2 uv = varTexCoord.st;
85+
#ifdef ENABLE_SSAA
86+
vec4 color = vec4(0.);
87+
for (float dx = 1.; dx < SSAA_SCALE; dx += 2.)
88+
for (float dy = 1.; dy < SSAA_SCALE; dy += 2.)
89+
color += texture2D(rendered, uv + texelSize0 * vec2(dx, dy)).rgba;
90+
color /= SSAA_SCALE * SSAA_SCALE / 4.;
91+
#else
8392
vec4 color = texture2D(rendered, uv).rgba;
93+
#endif
8494

8595
// translate to linear colorspace (approximate)
8696
color.rgb = pow(color.rgb, vec3(2.2));

src/client/game.cpp

+6-3
Original file line numberDiff line numberDiff line change
@@ -387,7 +387,8 @@ class GameGlobalShaderConstantSetter : public IShaderConstantSetter
387387
CachedPixelShaderSetting<SamplerLayer_t> m_texture1;
388388
CachedPixelShaderSetting<SamplerLayer_t> m_texture2;
389389
CachedPixelShaderSetting<SamplerLayer_t> m_texture3;
390-
CachedPixelShaderSetting<float, 2> m_texel_size0;
390+
CachedVertexShaderSetting<float, 2> m_texel_size0_vertex;
391+
CachedPixelShaderSetting<float, 2> m_texel_size0_pixel;
391392
std::array<float, 2> m_texel_size0_values;
392393
CachedStructPixelShaderSetting<float, 7> m_exposure_params_pixel;
393394
float m_user_exposure_compensation;
@@ -445,7 +446,8 @@ class GameGlobalShaderConstantSetter : public IShaderConstantSetter
445446
m_texture1("texture1"),
446447
m_texture2("texture2"),
447448
m_texture3("texture3"),
448-
m_texel_size0("texelSize0"),
449+
m_texel_size0_vertex("texelSize0"),
450+
m_texel_size0_pixel("texelSize0"),
449451
m_exposure_params_pixel("exposureParams",
450452
std::array<const char*, 7> {
451453
"luminanceMin", "luminanceMax", "exposureCorrection",
@@ -547,7 +549,8 @@ class GameGlobalShaderConstantSetter : public IShaderConstantSetter
547549
tex_id = 3;
548550
m_texture3.set(&tex_id, services);
549551

550-
m_texel_size0.set(m_texel_size0_values.data(), services);
552+
m_texel_size0_vertex.set(m_texel_size0_values.data(), services);
553+
m_texel_size0_pixel.set(m_texel_size0_values.data(), services);
551554

552555
const AutoExposure &exposure_params = m_client->getEnv().getLocalPlayer()->getLighting().exposure;
553556
std::array<float, 7> exposure_buffer = {

src/client/render/plain.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,11 @@ RenderStep* addUpscaling(RenderPipeline *pipeline, RenderStep *previousStep, v2f
130130
if (downscale_factor.X == 1.0f && downscale_factor.Y == 1.0f)
131131
return previousStep;
132132

133+
// When shaders are enabled, post-processing pipeline takes care of rescaling
134+
if (g_settings->getBool("enable_shaders"))
135+
return previousStep;
136+
137+
133138
// Initialize buffer
134139
TextureBuffer *buffer = pipeline->createOwned<TextureBuffer>();
135140
buffer->setTexture(TEXTURE_UPSCALE, downscale_factor, "upscale", video::ECF_A8R8G8B8);

src/client/render/secondstage.cpp

+36-5
Original file line numberDiff line numberDiff line change
@@ -118,9 +118,23 @@ RenderStep *addPostProcessing(RenderPipeline *pipeline, RenderStep *previousStep
118118
static const u8 TEXTURE_BLOOM = 2;
119119
static const u8 TEXTURE_EXPOSURE_1 = 3;
120120
static const u8 TEXTURE_EXPOSURE_2 = 4;
121+
static const u8 TEXTURE_FXAA = 5;
121122
static const u8 TEXTURE_BLOOM_DOWN = 10;
122123
static const u8 TEXTURE_BLOOM_UP = 20;
123124

125+
// Super-sampling is simply rendering into a larger texture.
126+
// Downscaling is done by the final step when rendering to the screen.
127+
const std::string antialiasing = g_settings->get("antialiasing");
128+
const bool enable_bloom = g_settings->getBool("enable_bloom");
129+
const bool enable_auto_exposure = g_settings->getBool("enable_auto_exposure");
130+
const bool enable_ssaa = antialiasing == "ssaa";
131+
const bool enable_fxaa = antialiasing == "fxaa";
132+
133+
if (enable_ssaa) {
134+
u16 ssaa_scale = MYMAX(2, g_settings->getU16("fsaa"));
135+
scale *= ssaa_scale;
136+
}
137+
124138
buffer->setTexture(TEXTURE_COLOR, scale, "3d_render", color_format);
125139
buffer->setTexture(TEXTURE_EXPOSURE_1, core::dimension2du(1,1), "exposure_1", color_format, /*clear:*/ true);
126140
buffer->setTexture(TEXTURE_EXPOSURE_2, core::dimension2du(1,1), "exposure_2", color_format, /*clear:*/ true);
@@ -135,8 +149,6 @@ RenderStep *addPostProcessing(RenderPipeline *pipeline, RenderStep *previousStep
135149
// Number of mipmap levels of the bloom downsampling texture
136150
const u8 MIPMAP_LEVELS = 4;
137151

138-
const bool enable_bloom = g_settings->getBool("enable_bloom");
139-
const bool enable_auto_exposure = g_settings->getBool("enable_auto_exposure");
140152

141153
// post-processing stage
142154

@@ -175,6 +187,7 @@ RenderStep *addPostProcessing(RenderPipeline *pipeline, RenderStep *previousStep
175187
}
176188
}
177189

190+
// Bloom pt 2
178191
if (enable_bloom) {
179192
// upsample
180193
shader_id = client->getShaderSource()->getShader("bloom_upsample", TILE_MATERIAL_PLAIN, NDT_MESH);
@@ -188,6 +201,7 @@ RenderStep *addPostProcessing(RenderPipeline *pipeline, RenderStep *previousStep
188201
}
189202
}
190203

204+
// Dynamic Exposure pt2
191205
if (enable_auto_exposure) {
192206
shader_id = client->getShaderSource()->getShader("update_exposure", TILE_MATERIAL_PLAIN, NDT_MESH);
193207
auto update_exposure = pipeline->addStep<PostProcessingStep>(shader_id, std::vector<u8> { TEXTURE_EXPOSURE_1, u8(TEXTURE_BLOOM_DOWN + MIPMAP_LEVELS - 1) });
@@ -196,11 +210,28 @@ RenderStep *addPostProcessing(RenderPipeline *pipeline, RenderStep *previousStep
196210
update_exposure->setRenderTarget(pipeline->createOwned<TextureBufferOutput>(buffer, TEXTURE_EXPOSURE_2));
197211
}
198212

199-
// final post-processing
213+
// FXAA
214+
u8 final_stage_source = TEXTURE_COLOR;
215+
216+
if (enable_fxaa) {
217+
final_stage_source = TEXTURE_FXAA;
218+
219+
buffer->setTexture(TEXTURE_FXAA, scale, "fxaa", color_format);
220+
shader_id = client->getShaderSource()->getShader("fxaa", TILE_MATERIAL_PLAIN);
221+
PostProcessingStep *effect = pipeline->createOwned<PostProcessingStep>(shader_id, std::vector<u8> { TEXTURE_COLOR });
222+
pipeline->addStep(effect);
223+
effect->setBilinearFilter(0, true);
224+
effect->setRenderSource(buffer);
225+
effect->setRenderTarget(pipeline->createOwned<TextureBufferOutput>(buffer, TEXTURE_FXAA));
226+
}
227+
228+
// final merge
200229
shader_id = client->getShaderSource()->getShader("second_stage", TILE_MATERIAL_PLAIN, NDT_MESH);
201-
PostProcessingStep *effect = pipeline->createOwned<PostProcessingStep>(shader_id, std::vector<u8> { TEXTURE_COLOR, TEXTURE_BLOOM_UP, TEXTURE_EXPOSURE_2 });
230+
PostProcessingStep *effect = pipeline->createOwned<PostProcessingStep>(shader_id, std::vector<u8> { final_stage_source, TEXTURE_BLOOM_UP, TEXTURE_EXPOSURE_2 });
202231
pipeline->addStep(effect);
203-
effect->setBilinearFilter(1, true); // apply filter to the bloom
232+
if (enable_ssaa)
233+
effect->setBilinearFilter(0, true);
234+
effect->setBilinearFilter(1, true);
204235
effect->setRenderSource(buffer);
205236

206237
if (enable_auto_exposure) {

src/client/renderingengine.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,8 @@ RenderingEngine::RenderingEngine(IEventReceiver *receiver)
122122

123123
// bpp, fsaa, vsync
124124
bool vsync = g_settings->getBool("vsync");
125-
u16 fsaa = g_settings->getU16("fsaa");
125+
bool enable_fsaa = g_settings->get("antialiasing") == "fsaa";
126+
u16 fsaa = enable_fsaa ? g_settings->getU16("fsaa") : 0;
126127

127128
// Determine driver
128129
auto driverType = chooseVideoDriver();

src/client/shader.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -780,6 +780,12 @@ ShaderInfo ShaderSource::generateShader(const std::string &name,
780780
if (g_settings->getBool("enable_auto_exposure"))
781781
shaders_header << "#define ENABLE_AUTO_EXPOSURE 1\n";
782782

783+
if (g_settings->get("antialiasing") == "ssaa") {
784+
shaders_header << "#define ENABLE_SSAA 1\n";
785+
u16 ssaa_scale = MYMAX(2, g_settings->getU16("fsaa"));
786+
shaders_header << "#define SSAA_SCALE " << ssaa_scale << ".\n";
787+
}
788+
783789
shaders_header << "#line 0\n"; // reset the line counter for meaningful diagnostics
784790

785791
std::string common_header = shaders_header.str();

src/defaultsettings.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,7 @@ void set_default_settings()
264264
settings->setDefault("enable_waving_plants", "false");
265265
settings->setDefault("exposure_compensation", "0.0");
266266
settings->setDefault("enable_auto_exposure", "false");
267+
settings->setDefault("antialiasing", "none");
267268
settings->setDefault("enable_bloom", "false");
268269
settings->setDefault("enable_bloom_debug", "false");
269270
settings->setDefault("bloom_strength_factor", "1.0");

0 commit comments

Comments
 (0)