Skip to content

Commit

Permalink
Added drago tonemapping, fix preview bake, use optimised cineon mappi…
Browse files Browse the repository at this point in the history
…ng and fix typos
  • Loading branch information
MBCX Debian Laptop committed Aug 4, 2024
1 parent 97ea4b7 commit d50114f
Show file tree
Hide file tree
Showing 9 changed files with 100 additions and 37 deletions.
7 changes: 5 additions & 2 deletions doc/classes/Environment.xml
Original file line number Diff line number Diff line change
Expand Up @@ -422,10 +422,10 @@
Reinhard tonemapper operator. Performs a variation on rendered pixels' colors by this formula: [code]color = color / (1 + color)[/code]. This avoids clipping bright highlights, but the resulting image can look a bit dull.
</constant>
<constant name="TONE_MAPPER_FILMIC" value="2" enum="ToneMapper">
Filmic tonemapper operator. This avoids clipping bright highlights, with a resulting image that usually looks more vivid than [constant TONE_MAPPER_REINHARDT].
Filmic tonemapper operator. This avoids clipping bright highlights, with a resulting image that usually looks more vivid than [constant TONE_MAPPER_REINHARD].
</constant>
<constant name="TONE_MAPPER_ACES" value="3" enum="ToneMapper">
Use the Academy Color Encoding System tonemapper. ACES is slightly more expensive than other options, but it handles bright lighting in a more realistic fashion by desaturating it as it becomes brighter. ACES typically has a more contrasted output compared to [constant TONE_MAPPER_REINHARDT] and [constant TONE_MAPPER_FILMIC].
Use the Academy Color Encoding System tonemapper. ACES is slightly more expensive than other options, but it handles bright lighting in a more realistic fashion by desaturating it as it becomes brighter. ACES typically has a more contrasted output compared to [constant TONE_MAPPER_REINHARD] and [constant TONE_MAPPER_FILMIC].
[b]Note:[/b] This tonemapping operator is called "ACES Fitted" in Godot 3.x.
</constant>
<constant name="TONE_MAPPER_AGX" value="4" enum="ToneMapper">
Expand All @@ -443,6 +443,9 @@
<constant name="TONE_MAPPER_CINEON" value="8" enum="ToneMapper">
Use the Cineon film response curve tonemapper. This method simulates the response of traditional film, providing a cinematic look with rich shadows and controlled highlights. It's particularly effective for preserving details in high-contrast scenes and achieving a classic film aesthetic. Cineon can produce more natural-looking results in some scenarios compared to [constant TONE_MAPPER_FILMIC], especially for scenes with a wide dynamic range.
</constant>
<constant name="TONE_MAPPER_DRAGO" value="9" enum="ToneMapper">
Use Drago's adaptive logarithmic mapping tonemapper (2003). This operator provides good compression of high dynamic range images, preserving details in both dark and bright areas. It adaptively adjusts the logarithmic basis to improve local contrast. Drago's method is particularly effective for scenes with extreme luminance variations and can produce natural-looking results without the need for manual parameter tuning.
</constant>
<constant name="GLOW_BLEND_MODE_ADDITIVE" value="0" enum="GlowBlendMode">
Additive glow blending mode. Mostly used for particles, glows (bloom), lens flare, bright sources.
</constant>
Expand Down
3 changes: 3 additions & 0 deletions doc/classes/RenderingServer.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5148,6 +5148,9 @@
<constant name="ENV_TONE_MAPPER_CINEON" value="8" enum="EnvironmentToneMapper">
Use the Cineon film response curve tonemapper. This method simulates the response of traditional film, providing a cinematic look with rich shadows and controlled highlights. It's effective for preserving details in high-contrast scenes and achieving a classic film aesthetic. Cineon can produce more natural-looking results in some scenarios compared to [constant ENV_TONE_MAPPER_FILMIC], especially for scenes with a wide dynamic range.
</constant>
<constant name="ENV_TONE_MAPPER_DRAGO" value="9" enum="EnvironmentToneMapper">
Use Drago's adaptive logarithmic mapping tonemapper (2003). This method compresses high dynamic range images while preserving details across the luminance range. It adaptively adjusts the logarithmic basis to enhance local contrast. Drago's operator is well-suited for scenes with extreme brightness variations, often producing natural-looking results without requiring manual parameter adjustments.
</constant>
<constant name="ENV_SSR_ROUGHNESS_QUALITY_DISABLED" value="0" enum="EnvironmentSSRRoughnessQuality">
Lowest quality of roughness filter for screen-space reflections. Rough materials will not have blurrier screen-space reflections compared to smooth (non-rough) materials. This is the fastest option.
</constant>
Expand Down
52 changes: 35 additions & 17 deletions drivers/gles3/shaders/tonemap_inc.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -119,28 +119,43 @@ vec3 tonemap_hable(vec3 color, float white) {
vec3 curr = hable_tonemap_partial(color * EXPOSURE_BIAS);

vec3 W = vec3(11.2f);
vec3 white_scale = vec3(white) / hable_tonemap_partial(W);
float white_padding = white;
if (white >= 1.0) {
white_padding = white + 1.0;
}
vec3 white_scale = vec3(white_padding) / hable_tonemap_partial(W);
return curr * white_scale;
}

// Optimised cineon tonemapping.
// Adapted from Three.js (MIT)
vec3 tonemap_cineon(vec3 color, float white) {
const float A = 0.22;
const float B = 0.30;
const float C = 0.10;
const float D = 0.20;
const float E = 0.01;
const float F = 0.30;

color *= white;
color = max(vec3(0.0), color - 0.004);
return pow(
(color * (6.2 * color + 0.5)) /
(color * (6.2 * color + 1.7) + 0.06),
vec3(2.2)
);
}

// Cineon formula
vec3 x = max(vec3(0.0), color - 0.004);
vec3 cineon_curve = (x * (6.2 * x + 0.5)) / (x * (6.2 * x + 1.7) + 0.06);
float luminance_drago(float L, float b) {
const float LMax = 1.0;
float Ld = b / (log(LMax + 1.0) / log(10.0));
Ld *= log(L + 1.0) / log(2.0 + 8.0 * pow((L / LMax), log(b) / log(0.5)));
return Ld;
}

// Based on the paper: "Adaptive Logarithmic Mapping For Displaying High Contrast Scenes"
// https://resources.mpi-inf.mpg.de/tmo/logmap/logmap.pdf
vec3 tonemap_drago(vec3 color, float white) {
const float BIAS = 0.85;

// Apply white point adjustment
float white_scale = 1.0 / ((white * (6.2 * white + 0.5)) / (white * (6.2 * white + 1.7) + 0.06));
cineon_curve *= white_scale;
return clamp(cineon_curve, 0.0, 1.0);
float luminance = dot(color, vec3(0.2126, 0.7152, 0.0722));
float Ld = luminance_drago(luminance, BIAS);
color = color * (Ld / luminance);
color *= white;
return clamp(color, 0.0, 1.0);
}

// Mean error^2: 3.6705141e-06
Expand Down Expand Up @@ -223,6 +238,7 @@ vec3 tonemap_agx(vec3 color, float white, bool punchy) {
#define TONEMAPPER_PBR_NEUTRAL 6
#define TONEMAPPER_HABLE 7
#define TONEMAPPER_CINEON 8
#define TONEMAPPER_DRAGO 9

vec3 apply_tonemapping(vec3 color, float p_white) { // inputs are LINEAR, always outputs clamped [0;1] color
// Ensure color values passed to tonemappers are positive.
Expand All @@ -243,8 +259,10 @@ vec3 apply_tonemapping(vec3 color, float p_white) { // inputs are LINEAR, always
return tonemap_pbr_neutral(max(vec3(0.0f), color));
} else if (tonemapper == TONEMAPPER_HABLE) {
return tonemap_hable(max(vec3(0.0f), color), p_white);
} else { // TONEMAPPER_CINEON
return tonemap_cineon(max(vec3(0.0f), color), p_white);
} else if (tonemapper == TONEMAPPER_CINEON) {
return tonemap_cineon(max(vec3(0.0f), color), white);
} else { // TONEMAPPER_DRAGO
return tonemap_drago(max(vec3(0.0f), color), white);
}
}

Expand Down
19 changes: 18 additions & 1 deletion scene/3d/lightmap_gi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1163,7 +1163,24 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa
}
}

Lightmapper::BakeError bake_err = lightmapper->bake(Lightmapper::BakeQuality(bake_quality), use_denoiser, denoiser_strength, denoiser_range, bounces, bounce_indirect_energy, bias, max_texture_size, directional, use_texture_for_bounces, Lightmapper::GenerateProbes(gen_probes), environment_image, environment_transform, _lightmap_bake_step_function, &bsud, exposure_normalization);
Lightmapper::BakeError bake_err = lightmapper->bake(
Lightmapper::BakeQuality(effective_bake_quality),
use_denoiser,
denoiser_strength,
denoiser_range,
effective_bounces,
bounce_indirect_energy,
bias,
max_texture_size,
directional,
use_texture_for_bounces,
Lightmapper::GenerateProbes(effective_gen_probes),
environment_image,
environment_transform,
_lightmap_bake_step_function,
&bsud,
exposure_normalization
);

if (bake_err == Lightmapper::BAKE_ERROR_TEXTURE_EXCEEDS_MAX_SIZE) {
return BAKE_ERROR_TEXTURE_SIZE_TOO_SMALL;
Expand Down
3 changes: 2 additions & 1 deletion scene/resources/environment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1322,7 +1322,7 @@ void Environment::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_tonemap_white"), &Environment::get_tonemap_white);

ADD_GROUP("Tonemap", "tonemap_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "tonemap_mode", PROPERTY_HINT_ENUM, "Linear,Reinhard,Filmic,ACES,AgX,AgX Punchy,PBR Neutral,Hable Filmic,Cineon"), "set_tonemapper", "get_tonemapper");
ADD_PROPERTY(PropertyInfo(Variant::INT, "tonemap_mode", PROPERTY_HINT_ENUM, "Linear,Reinhard,Filmic,ACES,AgX,AgX Punchy,PBR Neutral,Hable Filmic,Cineon,Drago"), "set_tonemapper", "get_tonemapper");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "tonemap_exposure", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_tonemap_exposure", "get_tonemap_exposure");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "tonemap_white", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_tonemap_white", "get_tonemap_white");

Expand Down Expand Up @@ -1650,6 +1650,7 @@ void Environment::_bind_methods() {
BIND_ENUM_CONSTANT(TONE_MAPPER_PBR_NEUTRAL);
BIND_ENUM_CONSTANT(TONE_MAPPER_HABLE);
BIND_ENUM_CONSTANT(TONE_MAPPER_CINEON);
BIND_ENUM_CONSTANT(TONE_MAPPER_DRAGO);

BIND_ENUM_CONSTANT(GLOW_BLEND_MODE_ADDITIVE);
BIND_ENUM_CONSTANT(GLOW_BLEND_MODE_SCREEN);
Expand Down
1 change: 1 addition & 0 deletions scene/resources/environment.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ class Environment : public Resource {
TONE_MAPPER_PBR_NEUTRAL,
TONE_MAPPER_HABLE,
TONE_MAPPER_CINEON,
TONE_MAPPER_DRAGO,
};

enum DynamicGICascadeFormat {
Expand Down
50 changes: 34 additions & 16 deletions servers/rendering/renderer_rd/shaders/effects/tonemap.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -370,28 +370,43 @@ vec3 tonemap_hable(vec3 color, float white) {
vec3 curr = hable_tonemap_partial(color * EXPOSURE_BIAS);

vec3 W = vec3(11.2f);
vec3 white_scale = vec3(white) / hable_tonemap_partial(W);
float white_padding = white;
if (white >= 1.0) {
white_padding = white + 1.0;
}
vec3 white_scale = vec3(white_padding) / hable_tonemap_partial(W);
return curr * white_scale;
}

// Optimised cineon tonemapping.
// Adapted from Three.js (MIT)
vec3 tonemap_cineon(vec3 color, float white) {
const float A = 0.22;
const float B = 0.30;
const float C = 0.10;
const float D = 0.20;
const float E = 0.01;
const float F = 0.30;

color *= white;
color = max(vec3(0.0), color - 0.004);
return pow(
(color * (6.2 * color + 0.5)) /
(color * (6.2 * color + 1.7) + 0.06),
vec3(2.2)
);
}

// Cineon formula
vec3 x = max(vec3(0.0), color - 0.004);
vec3 cineon_curve = (x * (6.2 * x + 0.5)) / (x * (6.2 * x + 1.7) + 0.06);
float luminance_drago(float L, float b) {
const float LMax = 1.0;
float Ld = b / (log(LMax + 1.0) / log(10.0));
Ld *= log(L + 1.0) / log(2.0 + 8.0 * pow((L / LMax), log(b) / log(0.5)));
return Ld;
}

// Based on the paper: "Adaptive Logarithmic Mapping For Displaying High Contrast Scenes"
// https://resources.mpi-inf.mpg.de/tmo/logmap/logmap.pdf
vec3 tonemap_drago(vec3 color, float white) {
const float BIAS = 0.85;

// Apply white point adjustment
float white_scale = 1.0 / ((white * (6.2 * white + 0.5)) / (white * (6.2 * white + 1.7) + 0.06));
cineon_curve *= white_scale;
return clamp(cineon_curve, 0.0, 1.0);
float luminance = dot(color, vec3(0.2126, 0.7152, 0.0722));
float Ld = luminance_drago(luminance, BIAS);
color = color * (Ld / luminance);
color *= white;
return clamp(color, 0.0, 1.0);
}

vec3 linear_to_srgb(vec3 color) {
Expand All @@ -410,6 +425,7 @@ vec3 linear_to_srgb(vec3 color) {
#define TONEMAPPER_PBR_NEUTRAL 6
#define TONEMAPPER_HABLE 7
#define TONEMAPPER_CINEON 8
#define TONEMAPPER_DRAGO 9

vec3 apply_tonemapping(vec3 color, float white) { // inputs are LINEAR, always outputs clamped [0;1] color
// Ensure color values passed to tonemappers are positive.
Expand All @@ -430,8 +446,10 @@ vec3 apply_tonemapping(vec3 color, float white) { // inputs are LINEAR, always o
return tonemap_pbr_neutral(max(vec3(0.0f), color));
} else if (params.tonemapper == TONEMAPPER_HABLE) {
return tonemap_hable(max(vec3(0.0f), color), white);
} else { // TONEMAPPER_CINEON
} else if (params.tonemapper == TONEMAPPER_CINEON) {
return tonemap_cineon(max(vec3(0.0f), color), white);
} else { // TONEMAPPER_DRAGO
return tonemap_drago(max(vec3(0.0f), color), white);
}
}

Expand Down
1 change: 1 addition & 0 deletions servers/rendering_server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3037,6 +3037,7 @@ void RenderingServer::_bind_methods() {
BIND_ENUM_CONSTANT(ENV_TONE_MAPPER_PBR_NEUTRAL);
BIND_ENUM_CONSTANT(ENV_TONE_MAPPER_HABLE);
BIND_ENUM_CONSTANT(ENV_TONE_MAPPER_CINEON);
BIND_ENUM_CONSTANT(ENV_TONE_MAPPER_DRAGO);

BIND_ENUM_CONSTANT(ENV_SSR_ROUGHNESS_QUALITY_DISABLED);
BIND_ENUM_CONSTANT(ENV_SSR_ROUGHNESS_QUALITY_LOW);
Expand Down
1 change: 1 addition & 0 deletions servers/rendering_server.h
Original file line number Diff line number Diff line change
Expand Up @@ -1165,6 +1165,7 @@ class RenderingServer : public Object {
ENV_TONE_MAPPER_PBR_NEUTRAL,
ENV_TONE_MAPPER_HABLE,
ENV_TONE_MAPPER_CINEON,
ENV_TONE_MAPPER_DRAGO,
};

virtual void environment_set_tonemap(RID p_env, EnvironmentToneMapper p_tone_mapper, float p_exposure, float p_white) = 0;
Expand Down

0 comments on commit d50114f

Please sign in to comment.