Skip to content

Commit

Permalink
Initial tonemapping options (bevyengine#7594)
Browse files Browse the repository at this point in the history
# Objective

Splits tone mapping from bevyengine#6677 into a separate PR.
Address bevyengine#2264.
Adds tone mapping options:
- None: Bypasses tonemapping for instances where users want colors output to match those set.
- Reinhard
- Reinhard Luminance: Bevy's exiting tonemapping
- [ACES](https://github.com/TheRealMJP/BakingLab/blob/master/BakingLab/ACES.hlsl) (Fitted version, based on the same implementation that Godot 4 uses) see bevyengine#2264
- [AgX](https://github.com/sobotka/AgX)
- SomewhatBoringDisplayTransform
- TonyMcMapface
- Blender Filmic

This PR also adds support for EXR images so they can be used to compare tonemapping options with reference images.

## Migration Guide
- Tonemapping is now an enum with NONE and the various tonemappers.
- The DebandDither is now a separate component.




Co-authored-by: JMS55 <[email protected]>
  • Loading branch information
DGriffin91 and JMS55 committed Feb 19, 2023
1 parent d46427b commit 912fb58
Show file tree
Hide file tree
Showing 37 changed files with 1,849 additions and 154 deletions.
16 changes: 16 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ default = [
"x11",
"filesystem_watcher",
"android_shared_stdcxx",
"tonemapping_luts"
]

# Force dynamic linking, which improves iterative compile times
Expand Down Expand Up @@ -78,6 +79,7 @@ trace = ["bevy_internal/trace"]
wgpu_trace = ["bevy_internal/wgpu_trace"]

# Image format support for texture loading (PNG and HDR are enabled by default)
exr = ["bevy_internal/exr"]
hdr = ["bevy_internal/hdr"]
png = ["bevy_internal/png"]
tga = ["bevy_internal/tga"]
Expand Down Expand Up @@ -131,6 +133,9 @@ android_shared_stdcxx = ["bevy_internal/android_shared_stdcxx"]
# These trace events are expensive even when off, thus they require compile time opt-in.
detailed_trace = ["bevy_internal/detailed_trace"]

# Include tonemapping LUT KTX2 files.
tonemapping_luts = ["bevy_internal/tonemapping_luts"]

[dependencies]
bevy_dylib = { path = "crates/bevy_dylib", version = "0.9.0", default-features = false, optional = true }
bevy_internal = { path = "crates/bevy_internal", version = "0.9.0", default-features = false }
Expand Down Expand Up @@ -389,6 +394,17 @@ description = "Loads and renders a glTF file as a scene"
category = "3D Rendering"
wasm = true

[[example]]
name = "tonemapping"
path = "examples/3d/tonemapping.rs"
required-features = ["ktx2", "zstd"]

[package.metadata.example.tonemapping]
name = "Tonemapping"
description = "Compares tonemapping options"
category = "3D Rendering"
wasm = true

[[example]]
name = "fxaa"
path = "examples/3d/fxaa.rs"
Expand Down
64 changes: 64 additions & 0 deletions assets/shaders/tonemapping_test_patterns.wgsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#import bevy_pbr::mesh_view_bindings
#import bevy_pbr::mesh_bindings
#import bevy_pbr::utils

#ifdef TONEMAP_IN_SHADER
#import bevy_core_pipeline::tonemapping
#endif

struct FragmentInput {
@builtin(front_facing) is_front: bool,
@builtin(position) frag_coord: vec4<f32>,
#import bevy_pbr::mesh_vertex_output
};

// Sweep across hues on y axis with value from 0.0 to +15EV across x axis
// quantized into 24 steps for both axis.
fn color_sweep(uv: vec2<f32>) -> vec3<f32> {
var uv = uv;
let steps = 24.0;
uv.y = uv.y * (1.0 + 1.0 / steps);
let ratio = 2.0;

let h = PI * 2.0 * floor(1.0 + steps * uv.y) / steps;
let L = floor(uv.x * steps * ratio) / (steps * ratio) - 0.5;

var color = vec3(0.0);
if uv.y < 1.0 {
color = cos(h + vec3(0.0, 1.0, 2.0) * PI * 2.0 / 3.0);
let maxRGB = max(color.r, max(color.g, color.b));
let minRGB = min(color.r, min(color.g, color.b));
color = exp(15.0 * L) * (color - minRGB) / (maxRGB - minRGB);
} else {
color = vec3(exp(15.0 * L));
}
return color;
}

fn hsv_to_srgb(c: vec3<f32>) -> vec3<f32> {
let K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
let p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
return c.z * mix(K.xxx, clamp(p - K.xxx, vec3(0.0), vec3(1.0)), c.y);
}

// Generates a continuous sRGB sweep.
fn continuous_hue(uv: vec2<f32>) -> vec3<f32> {
return hsv_to_srgb(vec3(uv.x, 1.0, 1.0)) * max(0.0, exp2(uv.y * 9.0) - 1.0);
}

@fragment
fn fragment(in: FragmentInput) -> @location(0) vec4<f32> {
var uv = in.uv;
var out = vec3(0.0);
if uv.y > 0.5 {
uv.y = 1.0 - uv.y;
out = color_sweep(vec2(uv.x, uv.y * 2.0));
} else {
out = continuous_hue(vec2(uv.y * 2.0, uv.x));
}
var color = vec4(out, 1.0);
#ifdef TONEMAP_IN_SHADER
color = tone_mapping(color);
#endif
return color;
}
1 change: 1 addition & 0 deletions crates/bevy_core_pipeline/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ keywords = ["bevy"]
[features]
trace = []
webgl = []
tonemapping_luts = []

[dependencies]
# bevy
Expand Down
9 changes: 7 additions & 2 deletions crates/bevy_core_pipeline/src/core_2d/camera_2d.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use crate::{clear_color::ClearColorConfig, tonemapping::Tonemapping};
use crate::{
clear_color::ClearColorConfig,
tonemapping::{DebandDither, Tonemapping},
};
use bevy_ecs::prelude::*;
use bevy_reflect::Reflect;
use bevy_render::{
Expand Down Expand Up @@ -27,6 +30,7 @@ pub struct Camera2dBundle {
pub global_transform: GlobalTransform,
pub camera_2d: Camera2d,
pub tonemapping: Tonemapping,
pub deband_dither: DebandDither,
}

impl Default for Camera2dBundle {
Expand Down Expand Up @@ -67,7 +71,8 @@ impl Camera2dBundle {
global_transform: Default::default(),
camera: Camera::default(),
camera_2d: Camera2d::default(),
tonemapping: Tonemapping::Disabled,
tonemapping: Tonemapping::None,
deband_dither: DebandDither::Disabled,
}
}
}
15 changes: 10 additions & 5 deletions crates/bevy_core_pipeline/src/core_3d/camera_3d.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
use crate::{clear_color::ClearColorConfig, tonemapping::Tonemapping};
use crate::{
clear_color::ClearColorConfig,
tonemapping::{DebandDither, Tonemapping},
};
use bevy_ecs::prelude::*;
use bevy_reflect::{Reflect, ReflectDeserialize, ReflectSerialize};
use bevy_render::{
camera::{Camera, CameraRenderGraph, Projection},
extract_component::ExtractComponent,
primitives::Frustum,
render_resource::LoadOp,
view::VisibleEntities,
view::{ColorGrading, VisibleEntities},
};
use bevy_transform::prelude::{GlobalTransform, Transform};
use serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -59,23 +62,25 @@ pub struct Camera3dBundle {
pub global_transform: GlobalTransform,
pub camera_3d: Camera3d,
pub tonemapping: Tonemapping,
pub dither: DebandDither,
pub color_grading: ColorGrading,
}

// NOTE: ideally Perspective and Orthographic defaults can share the same impl, but sadly it breaks rust's type inference
impl Default for Camera3dBundle {
fn default() -> Self {
Self {
camera_render_graph: CameraRenderGraph::new(crate::core_3d::graph::NAME),
tonemapping: Tonemapping::Enabled {
deband_dither: true,
},
camera: Default::default(),
projection: Default::default(),
visible_entities: Default::default(),
frustum: Default::default(),
transform: Default::default(),
global_transform: Default::default(),
camera_3d: Default::default(),
tonemapping: Tonemapping::ReinhardLuminance,
dither: DebandDither::Enabled,
color_grading: ColorGrading::default(),
}
}
}
Binary file not shown.
Binary file not shown.
22 changes: 22 additions & 0 deletions crates/bevy_core_pipeline/src/tonemapping/luts/info.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
--- Process for recreating AgX-default_contrast.ktx2 ---
Download:
https://github.com/MrLixm/AgXc/blob/898198e0490b0551ed81412a0c22e0b72fffb7cd/obs/obs-script/AgX-default_contrast.lut.png
Convert to vertical strip exr with:
https://gist.github.com/DGriffin91/fc8e0cfd55aaa175ac10199403bc19b8
Convert exr to 3D ktx2 with:
https://gist.github.com/DGriffin91/49401c43378b58bce32059291097d4ca

--- Process for recreating tony_mc_mapface.ktx2 ---
Download:
https://github.com/h3r2tic/tony-mc-mapface/blob/909e51c8a74251fd828770248476cb084081e08c/tony_mc_mapface.dds
Convert dds to 3D ktx2 with:
https://gist.github.com/DGriffin91/49401c43378b58bce32059291097d4ca

--- Process for recreating Blender_-11_12.ktx2 ---
Create LUT stimulus with:
https://gist.github.com/DGriffin91/e119bf32b520e219f6e102a6eba4a0cf
Open LUT image in Blender's image editor and make sure color space is set to linear.
Export from Blender as 32bit EXR, override color space to Filmic sRGB.
Import EXR back into blender set color space to sRGB, then export as 32bit EXR override color space to linear.
Convert exr to 3D ktx2 with:
https://gist.github.com/DGriffin91/49401c43378b58bce32059291097d4ca
Binary file not shown.
Loading

0 comments on commit 912fb58

Please sign in to comment.