Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bloom #12791

Merged
merged 25 commits into from
Sep 29, 2022
Merged

Bloom #12791

Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
698f4b2
Introduce technical texture names
x2048 Aug 31, 2022
b9eddf5
Add uniform for texture0 texel size
x2048 Aug 31, 2022
2c37ee3
Add multiple texture support to TextureBufferOutput
x2048 Sep 17, 2022
f74b08a
Add box blur shaders
x2048 Aug 31, 2022
830bbed
Add bloom effect
x2048 Aug 31, 2022
b3429ee
TextureBuffer is no longer a RenderTarget
x2048 Sep 17, 2022
254db1b
Use linear color values for all calculations
x2048 Sep 19, 2022
abe8a9d
Apply exposure factor before extracting bloom
x2048 Sep 11, 2022
0cf4e9f
Use downscaled textures for bloom
x2048 Sep 17, 2022
fd8f9f7
Add user configuration for exposure
x2048 Sep 18, 2022
348afac
Add parameter to control bloom effect
x2048 Sep 18, 2022
236700e
Add parameters for bloom threshold and boost
x2048 Sep 19, 2022
d1ba786
Replace bloom boost with bloom intensity parameter
x2048 Sep 19, 2022
5c4b14e
Add a parameter for bloom radius
x2048 Sep 19, 2022
0a8c9b6
Change blur equation for more realistic bloom at large kernels
x2048 Sep 19, 2022
bd4405b
Implement physically based bloom
x2048 Sep 20, 2022
9f87010
Compensate exposure when tonemapping is off
x2048 Sep 20, 2022
9aa1cbe
Use fixed value for exposure compensation
x2048 Sep 20, 2022
31d88fa
Fix documentation for bloom parameters
x2048 Sep 21, 2022
9989516
Clamp color values before applying gamma
x2048 Sep 22, 2022
a9fbc73
Add bloom debugging setting
x2048 Sep 24, 2022
56e9f3d
Use medium precision in blur shaders
x2048 Sep 24, 2022
082dfd4
Add flag to use dedicated texture in bloom
x2048 Sep 24, 2022
cc46fab
Document correct default value for bloom_intensity
x2048 Sep 25, 2022
133f102
Align style of doxygen comments
x2048 Sep 25, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions builtin/settingtypes.txt
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,32 @@ 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 the intensity of bloom
# Smaller values make bloom more subtle
# Range: from 0.01 to 1.0, default: 1.0
bloom_intensity (Bloom Intensity) float 0.05 0.01 1.0
x2048 marked this conversation as resolved.
Show resolved Hide resolved

# 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 lowp 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
lowp float n = 2. * bloomRadius + 1.;

vec2 uv = varTexCoord.st - vec2(bloomRadius * texelSize0.x, 0.);
vec4 color = vec4(0.);
lowp float sum = 0.;
for (lowp float i = 0.; i < n; i++) {
lowp 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 lowp float bloomRadius = 3.0;

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

void main(void)
x2048 marked this conversation as resolved.
Show resolved Hide resolved
{
// kernel distance and linear size
lowp float n = 2. * bloomRadius + 1.;

vec2 uv = varTexCoord.st - vec2(0., bloomRadius * texelSize0.y);
vec4 color = vec4(0.);
lowp float sum = 0.;
for (lowp float i = 0.; i < n; i++) {
lowp 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;
}
37 changes: 31 additions & 6 deletions client/shaders/second_stage/opengl_fragment.glsl
Original file line number Diff line number Diff line change
@@ -1,13 +1,27 @@
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)
{
color.rgb = mix(color.rgb, texture2D(bloom, uv).rgb, bloomIntensity);
return color;
}

#endif

#if ENABLE_TONE_MAPPING

/* Hable's UC2 Tone mapping parameters
Expand All @@ -28,26 +42,37 @@ 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

void main(void)
{
vec2 uv = varTexCoord.st;
vec4 color = texture2D(rendered, uv).rgba;
// translate to linear colorspace (approximate) and apply exposure
color.rgb = pow(color.rgb, vec3(2.2)) * exposureFactor;

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

#if ENABLE_TONE_MAPPING
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
Loading