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

Add a new high quality tonemapper: ACES Fitted (3.x) #52477

Merged
merged 1 commit into from
Sep 13, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 4 additions & 1 deletion doc/classes/Environment.xml
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,10 @@
Filmic tonemapper operator.
</constant>
<constant name="TONE_MAPPER_ACES" value="3" enum="ToneMapper">
Academy Color Encoding System tonemapper operator.
Academy Color Encoding System tonemapper operator. Performs an aproximation of the ACES tonemapping curve.
</constant>
<constant name="TONE_MAPPER_ACES_FITTED" value="4" enum="ToneMapper">
High quality Academy Color Encoding System tonemapper operator that matches the industry standard. Performs a more physically accurate curve fit which better simulates how light works in the real world. The color of lights and emissive materials will become lighter as the emissive energy increases, and will eventually become white if the light is bright enough to saturate the camera sensor.
</constant>
<constant name="DOF_BLUR_QUALITY_LOW" value="0" enum="DOFBlurQuality">
Low depth-of-field blur quality (fastest).
Expand Down
3 changes: 3 additions & 0 deletions doc/classes/VisualServer.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3798,6 +3798,9 @@
<constant name="ENV_TONE_MAPPER_ACES" value="3" enum="EnvironmentToneMapper">
Use the ACES tonemapper.
</constant>
<constant name="ENV_TONE_MAPPER_ACES_FITTED" value="4" enum="EnvironmentToneMapper">
Use the ACES Fitted tonemapper.
</constant>
<constant name="ENV_SSAO_QUALITY_LOW" value="0" enum="EnvironmentSSAOQuality">
Lowest quality of screen space ambient occlusion.
</constant>
Expand Down
2 changes: 2 additions & 0 deletions drivers/gles3/rasterizer_scene_gles3.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3863,6 +3863,7 @@ void RasterizerSceneGLES3::_post_process(Environment *env, const CameraMatrix &p
if (env) {
state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_FILMIC_TONEMAPPER, env->tone_mapper == VS::ENV_TONE_MAPPER_FILMIC);
state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_ACES_TONEMAPPER, env->tone_mapper == VS::ENV_TONE_MAPPER_ACES);
state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_ACES_FITTED_TONEMAPPER, env->tone_mapper == VS::ENV_TONE_MAPPER_ACES_FITTED);
state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_REINHARD_TONEMAPPER, env->tone_mapper == VS::ENV_TONE_MAPPER_REINHARD);
state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_AUTO_EXPOSURE, env->auto_exposure);
state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_GLOW_FILTER_BICUBIC, env->glow_bicubic_upscale);
Expand Down Expand Up @@ -3964,6 +3965,7 @@ void RasterizerSceneGLES3::_post_process(Environment *env, const CameraMatrix &p
state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_AUTO_EXPOSURE, false);
state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_FILMIC_TONEMAPPER, false);
state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_ACES_TONEMAPPER, false);
state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_ACES_FITTED_TONEMAPPER, false);
state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_REINHARD_TONEMAPPER, false);
state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_GLOW_LEVEL1, false);
state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_GLOW_LEVEL2, false);
Expand Down
45 changes: 42 additions & 3 deletions drivers/gles3/shaders/tonemap.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,37 @@ vec3 tonemap_aces(vec3 color, float white) {
return clamp(color_tonemapped / white_tonemapped, vec3(0.0f), vec3(1.0f));
}

// Adapted from https://github.com/TheRealMJP/BakingLab/blob/master/BakingLab/ACES.hlsl
// (MIT License).
vec3 tonemap_aces_fitted(vec3 color, float white) {
const float exposure_bias = 1.8f;
const float A = 0.0245786f;
const float B = 0.000090537f;
const float C = 0.983729f;
const float D = 0.432951f;
const float E = 0.238081f;

// Exposure bias baked into transform to save shader instructions. Equivalent to `color *= exposure_bias`
const mat3 rgb_to_rrt = mat3(
vec3(0.59719f * exposure_bias, 0.35458f * exposure_bias, 0.04823f * exposure_bias),
vec3(0.07600f * exposure_bias, 0.90834f * exposure_bias, 0.01566f * exposure_bias),
vec3(0.02840f * exposure_bias, 0.13383f * exposure_bias, 0.83777f * exposure_bias));

const mat3 odt_to_rgb = mat3(
vec3(1.60475f, -0.53108f, -0.07367f),
vec3(-0.10208f, 1.10813f, -0.00605f),
vec3(-0.00327f, -0.07276f, 1.07602f));

color *= rgb_to_rrt;
vec3 color_tonemapped = (color * (color + A) - B) / (color * (C * color + D) + E);
color_tonemapped *= odt_to_rgb;

white *= exposure_bias;
float white_tonemapped = (white * (white + A) - B) / (white * (C * white + D) + E);

return clamp(color_tonemapped / white_tonemapped, vec3(0.0f), vec3(1.0f));
}

vec3 tonemap_reinhard(vec3 color, float white) {
return clamp((white * color + color) / (color * white + white), vec3(0.0f), vec3(1.0f));
}
Expand All @@ -174,6 +205,12 @@ vec3 linear_to_srgb(vec3 color) { // convert linear rgb to srgb, assumes clamped

// inputs are LINEAR, If Linear tonemapping is selected no transform is performed else outputs are clamped [0, 1] color
vec3 apply_tonemapping(vec3 color, float white) {
// Ensure color values are positive.
// They can be negative in the case of negative lights, which leads to undesired behavior.
#if defined(USE_REINHARD_TONEMAPPER) || defined(USE_FILMIC_TONEMAPPER) || defined(USE_ACES_TONEMAPPER) || defined(USE_ACES_FITTED_TONEMAPPER)
color = max(vec3(0.0f), color);
#endif

#ifdef USE_REINHARD_TONEMAPPER
return tonemap_reinhard(color, white);
#endif
Expand All @@ -186,6 +223,10 @@ vec3 apply_tonemapping(vec3 color, float white) {
return tonemap_aces(color, white);
#endif

#ifdef USE_ACES_FITTED_TONEMAPPER
return tonemap_aces_fitted(color, white);
#endif

return color; // no other selected -> linear: no color transform applied
}

Expand Down Expand Up @@ -401,9 +442,7 @@ void main() {
#endif

// Early Tonemap & SRGB Conversion; note that Linear tonemapping does not clamp to [0, 1]; some operations below expect a [0, 1] range and will clamp
// Ensure color values are positive.
// They can be negative in the case of negative lights, which leads to undesired behavior.
color = apply_tonemapping(max(vec3(0.0), color), white);
color = apply_tonemapping(color, white);

#ifdef KEEP_3D_LINEAR
// leave color as is (-> don't convert to SRGB)
Expand Down
3 changes: 2 additions & 1 deletion scene/resources/environment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -919,7 +919,7 @@ void Environment::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_tonemap_auto_exposure_grey"), &Environment::get_tonemap_auto_exposure_grey);

ADD_GROUP("Tonemap", "tonemap_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "tonemap_mode", PROPERTY_HINT_ENUM, "Linear,Reinhard,Filmic,ACES"), "set_tonemapper", "get_tonemapper");
ADD_PROPERTY(PropertyInfo(Variant::INT, "tonemap_mode", PROPERTY_HINT_ENUM, "Linear,Reinhard,Filmic,ACES,ACES Fitted"), "set_tonemapper", "get_tonemapper");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "tonemap_exposure", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_tonemap_exposure", "get_tonemap_exposure");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "tonemap_white", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_tonemap_white", "get_tonemap_white");
ADD_GROUP("Auto Exposure", "auto_exposure_");
Expand Down Expand Up @@ -1138,6 +1138,7 @@ void Environment::_bind_methods() {
BIND_ENUM_CONSTANT(TONE_MAPPER_REINHARDT);
BIND_ENUM_CONSTANT(TONE_MAPPER_FILMIC);
BIND_ENUM_CONSTANT(TONE_MAPPER_ACES);
BIND_ENUM_CONSTANT(TONE_MAPPER_ACES_FITTED);

BIND_ENUM_CONSTANT(DOF_BLUR_QUALITY_LOW);
BIND_ENUM_CONSTANT(DOF_BLUR_QUALITY_MEDIUM);
Expand Down
3 changes: 2 additions & 1 deletion scene/resources/environment.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ class Environment : public Resource {
TONE_MAPPER_LINEAR,
TONE_MAPPER_REINHARDT,
TONE_MAPPER_FILMIC,
TONE_MAPPER_ACES
TONE_MAPPER_ACES,
TONE_MAPPER_ACES_FITTED
};

enum GlowBlendMode {
Expand Down
1 change: 1 addition & 0 deletions servers/visual_server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2504,6 +2504,7 @@ void VisualServer::_bind_methods() {
BIND_ENUM_CONSTANT(ENV_TONE_MAPPER_REINHARD);
BIND_ENUM_CONSTANT(ENV_TONE_MAPPER_FILMIC);
BIND_ENUM_CONSTANT(ENV_TONE_MAPPER_ACES);
BIND_ENUM_CONSTANT(ENV_TONE_MAPPER_ACES_FITTED);

BIND_ENUM_CONSTANT(ENV_SSAO_QUALITY_LOW);
BIND_ENUM_CONSTANT(ENV_SSAO_QUALITY_MEDIUM);
Expand Down
3 changes: 2 additions & 1 deletion servers/visual_server.h
Original file line number Diff line number Diff line change
Expand Up @@ -778,7 +778,8 @@ class VisualServer : public Object {
ENV_TONE_MAPPER_LINEAR,
ENV_TONE_MAPPER_REINHARD,
ENV_TONE_MAPPER_FILMIC,
ENV_TONE_MAPPER_ACES
ENV_TONE_MAPPER_ACES,
ENV_TONE_MAPPER_ACES_FITTED
};

virtual void environment_set_tonemap(RID p_env, EnvironmentToneMapper p_tone_mapper, float p_exposure, float p_white, bool p_auto_exposure, float p_min_luminance, float p_max_luminance, float p_auto_exp_speed, float p_auto_exp_grey) = 0;
Expand Down