Skip to content

Commit

Permalink
Bloom (minetest#12791)
Browse files Browse the repository at this point in the history
Adds configurable light exposure control and bloom effect (light bleeding) with client-side settings.
  • Loading branch information
x2048 committed Sep 29, 2022
1 parent 3978b9b commit 9df79a4
Show file tree
Hide file tree
Showing 16 changed files with 422 additions and 118 deletions.
38 changes: 38 additions & 0 deletions builtin/settingtypes.txt
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,44 @@ shadow_soft_radius (Soft shadow radius) float 5.0 1.0 15.0
# Minimum value: 0.0; maximum value: 60.0
shadow_sky_body_orbit_tilt (Sky Body Orbit Tilt) float 0.0 0.0 60.0

[**Post processing]

# Set the exposure compensation factor.
# This factor is applied to linear color value
# before all other post-processing effects.
# Value of 1.0 (default) means no exposure compensation.
# Range: from 0.1 to 10.0
exposure_factor (Exposure Factor) float 1.0 0.1 10.0

[**Bloom]

# Set to true to enable bloom effect.
# Bright colors will bleed over the neighboring objects.
enable_bloom (Enable Bloom) bool false

# Set to true to render debugging breakdown of the bloom effect.
# In debug mode, the screen is split into 4 quadrants:
# top-left - processed base image, top-right - final image
# bottom-left - raw base image, bottom-right - bloom texture.
enable_bloom_debug (Enable Bloom Debug) bool false

# Set to true to use dedicated texture at each step of bloom effect.
# This is a compatibility setting to avoid visual artifacts
# on certain GPUs and video drivers.
enable_bloom_dedicated_texture (Enable Bloom Dedicated Texture) bool false

# Set the intensity of bloom
# Smaller values make bloom more subtle
# Range: from 0.01 to 1.0, default: 0.05
bloom_intensity (Bloom Intensity) float 0.05 0.01 1.0

# Set the radius of the bloom filter in pixels.
# Larger values render more glow around bright objects
# at the cost of higher resource consumption.
# Range: from 1 to 64, default: 16
bloom_radius (Bloom Radius) int 16 1 64


[*Audio]

# Volume of all sounds.
Expand Down
29 changes: 29 additions & 0 deletions client/shaders/blur_h/opengl_fragment.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#define rendered texture0

uniform sampler2D rendered;
uniform vec2 texelSize0;
uniform mediump float bloomRadius = 3.0;

#ifdef GL_ES
varying mediump vec2 varTexCoord;
#else
centroid varying vec2 varTexCoord;
#endif

void main(void)
{
// kernel distance and linear size
mediump float n = 2. * bloomRadius + 1.;

vec2 uv = varTexCoord.st - vec2(bloomRadius * texelSize0.x, 0.);
vec4 color = vec4(0.);
mediump float sum = 0.;
for (mediump float i = 0.; i < n; i++) {
mediump float weight = pow(1. - (abs(i / bloomRadius - 1.)), 1.3);
color += texture2D(rendered, uv).rgba * weight;
sum += weight;
uv += vec2(texelSize0.x, 0.);
}
color /= sum;
gl_FragColor = vec4(color.rgb, 1.0); // force full alpha to avoid holes in the image.
}
11 changes: 11 additions & 0 deletions client/shaders/blur_h/opengl_vertex.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#ifdef GL_ES
varying mediump vec2 varTexCoord;
#else
centroid varying vec2 varTexCoord;
#endif

void main(void)
{
varTexCoord.st = inTexCoord0.st;
gl_Position = inVertexPosition;
}
29 changes: 29 additions & 0 deletions client/shaders/blur_v/opengl_fragment.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#define rendered texture0

uniform sampler2D rendered;
uniform vec2 texelSize0;
uniform mediump float bloomRadius = 3.0;

#ifdef GL_ES
varying mediump vec2 varTexCoord;
#else
centroid varying vec2 varTexCoord;
#endif

void main(void)
{
// kernel distance and linear size
mediump float n = 2. * bloomRadius + 1.;

vec2 uv = varTexCoord.st - vec2(0., bloomRadius * texelSize0.y);
vec4 color = vec4(0.);
mediump float sum = 0.;
for (mediump float i = 0.; i < n; i++) {
mediump float weight = pow(1. - (abs(i / bloomRadius - 1.)), 1.3);
color += texture2D(rendered, uv).rgba * weight;
sum += weight;
uv += vec2(0., texelSize0.y);
}
color /= sum;
gl_FragColor = vec4(color.rgb, 1.0); // force full alpha to avoid holes in the image.
}
11 changes: 11 additions & 0 deletions client/shaders/blur_v/opengl_vertex.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#ifdef GL_ES
varying mediump vec2 varTexCoord;
#else
centroid varying vec2 varTexCoord;
#endif

void main(void)
{
varTexCoord.st = inTexCoord0.st;
gl_Position = inVertexPosition;
}
21 changes: 21 additions & 0 deletions client/shaders/extract_bloom/opengl_fragment.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#define rendered texture0

uniform sampler2D rendered;
uniform mediump float exposureFactor = 2.5;
uniform float bloomLuminanceThreshold = 1.0;

#ifdef GL_ES
varying mediump vec2 varTexCoord;
#else
centroid varying vec2 varTexCoord;
#endif


void main(void)
{
vec2 uv = varTexCoord.st;
vec4 color = texture2D(rendered, uv).rgba;
// translate to linear colorspace (approximate)
color.rgb = pow(color.rgb, vec3(2.2)) * exposureFactor;
gl_FragColor = vec4(color.rgb, 1.0); // force full alpha to avoid holes in the image.
}
11 changes: 11 additions & 0 deletions client/shaders/extract_bloom/opengl_vertex.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#ifdef GL_ES
varying mediump vec2 varTexCoord;
#else
centroid varying vec2 varTexCoord;
#endif

void main(void)
{
varTexCoord.st = inTexCoord0.st;
gl_Position = inVertexPosition;
}
61 changes: 54 additions & 7 deletions client/shaders/second_stage/opengl_fragment.glsl
Original file line number Diff line number Diff line change
@@ -1,13 +1,35 @@
uniform sampler2D baseTexture;
#define rendered texture0
#define bloom texture1

#define rendered baseTexture
uniform sampler2D rendered;
uniform sampler2D bloom;
uniform mediump float exposureFactor = 2.5;
uniform lowp float bloomIntensity = 1.0;

#ifdef GL_ES
varying mediump vec2 varTexCoord;
#else
centroid varying vec2 varTexCoord;
#endif

#if ENABLE_BLOOM

vec4 applyBloom(vec4 color, vec2 uv)
{
float bias = bloomIntensity;
vec4 bloom = texture2D(bloom, uv);
#if ENABLE_BLOOM_DEBUG
if (uv.x > 0.5 && uv.y < 0.5)
return vec4(bloom.rgb, color.a);
if (uv.x < 0.5)
return color;
#endif
color.rgb = mix(color.rgb, bloom.rgb, bias);
return color;
}

#endif

#if ENABLE_TONE_MAPPING

/* Hable's UC2 Tone mapping parameters
Expand All @@ -28,15 +50,13 @@ vec3 uncharted2Tonemap(vec3 x)

vec4 applyToneMapping(vec4 color)
{
color = vec4(pow(color.rgb, vec3(2.2)), color.a);
const float gamma = 1.6;
const float exposureBias = 5.5;
const float exposureBias = 2.0;
color.rgb = uncharted2Tonemap(exposureBias * color.rgb);
// Precalculated white_scale from
//vec3 whiteScale = 1.0 / uncharted2Tonemap(vec3(W));
vec3 whiteScale = vec3(1.036015346);
color.rgb *= whiteScale;
return vec4(pow(color.rgb, vec3(1.0 / gamma)), color.a);
return color;
}
#endif

Expand All @@ -45,9 +65,36 @@ void main(void)
vec2 uv = varTexCoord.st;
vec4 color = texture2D(rendered, uv).rgba;

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

#if ENABLE_BLOOM_DEBUG
if (uv.x > 0.5 || uv.y > 0.5)
#endif
{
color.rgb *= exposureFactor;
}


#if ENABLE_BLOOM
color = applyBloom(color, uv);
#endif

#if ENABLE_BLOOM_DEBUG
if (uv.x > 0.5 || uv.y > 0.5)
#endif
{
#if ENABLE_TONE_MAPPING
color = applyToneMapping(color);
color = applyToneMapping(color);
#else
color.rgb /= 2.5; // default exposure factor, see also RenderingEngine::DEFAULT_EXPOSURE_FACTOR;
#endif
}

color.rgb = clamp(color.rgb, vec3(0.), vec3(1.));

// return to sRGB colorspace (approximate)
color.rgb = pow(color.rgb, vec3(1.0 / 2.2));

gl_FragColor = vec4(color.rgb, 1.0); // force full alpha to avoid holes in the image.
}
85 changes: 71 additions & 14 deletions src/client/game.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,7 @@ typedef s32 SamplerLayer_t;
class GameGlobalShaderConstantSetter : public IShaderConstantSetter
{
Sky *m_sky;
Client *m_client;
bool *m_force_fog_off;
f32 *m_fog_range;
bool m_fog_enabled;
Expand All @@ -419,16 +420,31 @@ class GameGlobalShaderConstantSetter : public IShaderConstantSetter
CachedPixelShaderSetting<float, 3> m_minimap_yaw;
CachedPixelShaderSetting<float, 3> m_camera_offset_pixel;
CachedPixelShaderSetting<float, 3> m_camera_offset_vertex;
CachedPixelShaderSetting<SamplerLayer_t> m_base_texture;
CachedPixelShaderSetting<SamplerLayer_t> m_normal_texture;
CachedPixelShaderSetting<SamplerLayer_t> m_texture_flags;
Client *m_client;
CachedPixelShaderSetting<SamplerLayer_t> m_texture0;
CachedPixelShaderSetting<SamplerLayer_t> m_texture1;
CachedPixelShaderSetting<SamplerLayer_t> m_texture2;
CachedPixelShaderSetting<SamplerLayer_t> m_texture3;
CachedPixelShaderSetting<float, 2> m_texel_size0;
std::array<float, 2> m_texel_size0_values;
CachedPixelShaderSetting<float> m_exposure_factor_pixel;
float m_user_exposure_factor;
bool m_bloom_enabled;
CachedPixelShaderSetting<float> m_bloom_intensity_pixel;
float m_bloom_intensity;
CachedPixelShaderSetting<float> m_bloom_radius_pixel;
float m_bloom_radius;

public:
void onSettingsChange(const std::string &name)
{
if (name == "enable_fog")
m_fog_enabled = g_settings->getBool("enable_fog");
if (name == "exposure_factor")
m_user_exposure_factor = g_settings->getFloat("exposure_factor", 0.1f, 10.0f);
if (name == "bloom_intensity")
m_bloom_intensity = g_settings->getFloat("bloom_intensity", 0.01f, 1.0f);
if (name == "bloom_radius")
m_bloom_radius = g_settings->getFloat("bloom_radius", 1.0f, 64.0f);
}

static void settingsCallback(const std::string &name, void *userdata)
Expand All @@ -441,6 +457,7 @@ class GameGlobalShaderConstantSetter : public IShaderConstantSetter
GameGlobalShaderConstantSetter(Sky *sky, bool *force_fog_off,
f32 *fog_range, Client *client) :
m_sky(sky),
m_client(client),
m_force_fog_off(force_fog_off),
m_fog_range(fog_range),
m_sky_bg_color("skyBgColor"),
Expand All @@ -454,13 +471,24 @@ class GameGlobalShaderConstantSetter : public IShaderConstantSetter
m_minimap_yaw("yawVec"),
m_camera_offset_pixel("cameraOffset"),
m_camera_offset_vertex("cameraOffset"),
m_base_texture("baseTexture"),
m_normal_texture("normalTexture"),
m_texture_flags("textureFlags"),
m_client(client)
m_texture0("texture0"),
m_texture1("texture1"),
m_texture2("texture2"),
m_texture3("texture3"),
m_texel_size0("texelSize0"),
m_exposure_factor_pixel("exposureFactor"),
m_bloom_intensity_pixel("bloomIntensity"),
m_bloom_radius_pixel("bloomRadius")
{
g_settings->registerChangedCallback("enable_fog", settingsCallback, this);
g_settings->registerChangedCallback("exposure_factor", settingsCallback, this);
g_settings->registerChangedCallback("bloom_intensity", settingsCallback, this);
g_settings->registerChangedCallback("bloom_radius", settingsCallback, this);
m_fog_enabled = g_settings->getBool("enable_fog");
m_user_exposure_factor = g_settings->getFloat("exposure_factor", 0.1f, 10.0f);
m_bloom_enabled = g_settings->getBool("enable_bloom");
m_bloom_intensity = g_settings->getFloat("bloom_intensity", 0.01f, 1.0f);
m_bloom_radius = g_settings->getFloat("bloom_radius", 1.0f, 64.0f);
}

~GameGlobalShaderConstantSetter()
Expand Down Expand Up @@ -526,12 +554,41 @@ class GameGlobalShaderConstantSetter : public IShaderConstantSetter
m_camera_offset_pixel.set(camera_offset_array, services);
m_camera_offset_vertex.set(camera_offset_array, services);

SamplerLayer_t base_tex = 0,
normal_tex = 1,
flags_tex = 2;
m_base_texture.set(&base_tex, services);
m_normal_texture.set(&normal_tex, services);
m_texture_flags.set(&flags_tex, services);
SamplerLayer_t tex_id;
tex_id = 0;
m_texture0.set(&tex_id, services);
tex_id = 1;
m_texture1.set(&tex_id, services);
tex_id = 2;
m_texture2.set(&tex_id, services);
tex_id = 3;
m_texture3.set(&tex_id, services);

m_texel_size0.set(m_texel_size0_values.data(), services);

float exposure_factor = RenderingEngine::DEFAULT_EXPOSURE_FACTOR * m_user_exposure_factor;
if (std::isnan(exposure_factor))
exposure_factor = RenderingEngine::DEFAULT_EXPOSURE_FACTOR;
m_exposure_factor_pixel.set(&exposure_factor, services);

if (m_bloom_enabled) {
m_bloom_intensity_pixel.set(&m_bloom_intensity, services);
m_bloom_radius_pixel.set(&m_bloom_radius, services);
}
}

void onSetMaterial(const video::SMaterial &material)
{
video::ITexture *texture = material.getTexture(0);
if (texture) {
core::dimension2du size = texture->getSize();
m_texel_size0_values[0] = 1.f / size.Width;
m_texel_size0_values[1] = 1.f / size.Height;
}
else {
m_texel_size0_values[0] = 0.f;
m_texel_size0_values[1] = 0.f;
}
}
};

Expand Down

0 comments on commit 9df79a4

Please sign in to comment.