Skip to content
Open
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
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -445,7 +445,7 @@ android_shared_stdcxx = ["bevy_internal/android_shared_stdcxx"]
# Enable detailed trace event logging. These trace events are expensive even when off, thus they require compile time opt-in
detailed_trace = ["bevy_internal/detailed_trace"]

# Include tonemapping Look Up Tables KTX2 files. If everything is pink, you need to enable this feature or change the `Tonemapping` method for your `Camera2d` or `Camera3d`.
# Include tonemapping Look Up Tables KTX2 files.
tonemapping_luts = ["bevy_internal/tonemapping_luts"]

# Include SMAA Look Up Tables KTX2 Files
Expand Down
106 changes: 50 additions & 56 deletions crates/bevy_core_pipeline/src/tonemapping/mod.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
use bevy_app::prelude::*;
use bevy_asset::{
embedded_asset, load_embedded_asset, AssetServer, Assets, Handle, RenderAssetUsages,
embedded_asset, load_embedded_asset, uuid_handle, AssetServer, Assets, Handle,
RenderAssetUsages,
};
use bevy_camera::Camera;
use bevy_ecs::prelude::*;
use bevy_image::{CompressedImageFormats, Image, ImageSampler, ImageType};
use bevy_reflect::{std_traits::ReflectDefault, Reflect};
#[cfg(feature = "tonemapping_luts")]
use bevy_render::extract_resource::{ExtractResource, ExtractResourcePlugin};
use bevy_render::{
extract_component::{ExtractComponent, ExtractComponentPlugin},
extract_resource::{ExtractResource, ExtractResourcePlugin},
render_asset::RenderAssets,
render_resource::{
binding_types::{sampler, texture_2d, texture_3d, uniform_buffer},
Expand All @@ -21,7 +23,6 @@ use bevy_render::{
};
use bevy_shader::{load_shader_library, Shader, ShaderDefVal};
use bitflags::bitflags;
#[cfg(not(feature = "tonemapping_luts"))]
use tracing::error;

mod node;
Expand All @@ -31,8 +32,12 @@ pub use node::TonemappingNode;

use crate::FullscreenShader;

/// 3D LUT (look up table) textures used for tonemapping
/// 1x1 image used for the Tonemapping methods that do not use LUTs
const PLACEHOLDER_LUTS_IMAGE: Handle<Image> = uuid_handle!("39bd4241-aa05-401a-b5ad-4dd963254fff");

/// 3D LUT (look up table) textures used for tonemapping.
#[derive(Resource, Clone, ExtractResource)]
#[cfg(feature = "tonemapping_luts")]
pub struct TonemappingLuts {
pub blender_filmic: Handle<Image>,
pub agx: Handle<Image>,
Expand All @@ -48,40 +53,33 @@ impl Plugin for TonemappingPlugin {

embedded_asset!(app, "tonemapping.wgsl");

#[cfg(feature = "tonemapping_luts")]
if !app.world().is_resource_added::<TonemappingLuts>() {
let mut images = app.world_mut().resource_mut::<Assets<Image>>();

#[cfg(feature = "tonemapping_luts")]
let tonemapping_luts = {
TonemappingLuts {
blender_filmic: images.add(setup_tonemapping_lut_image(
include_bytes!("luts/Blender_-11_12.ktx2"),
ImageType::Extension("ktx2"),
)),
agx: images.add(setup_tonemapping_lut_image(
include_bytes!("luts/AgX-default_contrast.ktx2"),
ImageType::Extension("ktx2"),
)),
tony_mc_mapface: images.add(setup_tonemapping_lut_image(
include_bytes!("luts/tony_mc_mapface.ktx2"),
ImageType::Extension("ktx2"),
)),
}
};

#[cfg(not(feature = "tonemapping_luts"))]
let tonemapping_luts = {
let placeholder = images.add(lut_placeholder());
TonemappingLuts {
blender_filmic: placeholder.clone(),
agx: placeholder.clone(),
tony_mc_mapface: placeholder,
}
let tonemapping_luts = TonemappingLuts {
blender_filmic: images.add(setup_tonemapping_lut_image(
include_bytes!("luts/Blender_-11_12.ktx2"),
ImageType::Extension("ktx2"),
)),
agx: images.add(setup_tonemapping_lut_image(
include_bytes!("luts/AgX-default_contrast.ktx2"),
ImageType::Extension("ktx2"),
)),
tony_mc_mapface: images.add(setup_tonemapping_lut_image(
include_bytes!("luts/tony_mc_mapface.ktx2"),
ImageType::Extension("ktx2"),
)),
};

app.insert_resource(tonemapping_luts);
}

let mut images = app.world_mut().resource_mut::<Assets<Image>>();
if let Err(err) = images.insert(PLACEHOLDER_LUTS_IMAGE.id(), lut_placeholder()) {
error!("Failed to create Placeholder LUTs due to '{err}'.");
}

#[cfg(feature = "tonemapping_luts")]
app.add_plugins(ExtractResourcePlugin::<TonemappingLuts>::default());

app.add_plugins((
Expand Down Expand Up @@ -111,13 +109,19 @@ pub struct TonemappingPipeline {
}

/// Optionally enables a tonemapping shader that attempts to map linear input stimulus into a perceptually uniform image for a given [`Camera`] entity.
///
/// The default when `tonemapping_luts` is enabled is [`TonyMcMapface`](Tonemapping::TonyMcMapface),
/// otherwise it is [`None`](Tonemapping::None).
#[derive(
Component, Debug, Hash, Clone, Copy, Reflect, Default, ExtractComponent, PartialEq, Eq,
)]
#[extract_component_filter(With<Camera>)]
#[reflect(Component, Debug, Hash, Default, PartialEq)]
pub enum Tonemapping {
/// Bypass tonemapping.
///
/// Default when `tonemapping_luts` is disabled.
#[cfg_attr(not(feature = "tonemapping_luts"), default)]
None,
/// Suffers from lots hue shifting, brights don't desaturate naturally.
/// Bright primaries and secondaries don't desaturate at all.
Expand All @@ -134,7 +138,7 @@ pub enum Tonemapping {
/// <https://github.com/sobotka/AgX>
/// Very neutral. Image is somewhat desaturated when compared to other tonemappers.
/// Little to no hue shifting. Subtle [Abney shifting](https://en.wikipedia.org/wiki/Abney_effect).
/// NOTE: Requires the `tonemapping_luts` cargo feature.
#[cfg(feature = "tonemapping_luts")]
AgX,
/// By Tomasz Stachowiak
/// Has little hue shifting in the darks and mids, but lots in the brights. Brights desaturate across the spectrum.
Expand All @@ -153,12 +157,14 @@ pub enum Tonemapping {
/// Brightness-equivalent luminance of the input stimulus is compressed. The non-linearity resembles Reinhard.
/// Color hues are preserved during compression, except for a deliberate [Bezold–Brücke shift](https://en.wikipedia.org/wiki/Bezold%E2%80%93Br%C3%BCcke_shift).
/// To avoid posterization, selective desaturation is employed, with care to avoid the [Abney effect](https://en.wikipedia.org/wiki/Abney_effect).
/// NOTE: Requires the `tonemapping_luts` cargo feature.
#[default]
///
/// Default when `tonemapping_luts` is enabled.
#[cfg_attr(feature = "tonemapping_luts", default)]
#[cfg(feature = "tonemapping_luts")]
TonyMcMapface,
/// Default Filmic Display Transform from blender.
/// Somewhat neutral. Suffers from hue shifting. Brights desaturate across the spectrum.
/// NOTE: Requires the `tonemapping_luts` cargo feature.
#[cfg(feature = "tonemapping_luts")]
BlenderFilmic,
}

Expand Down Expand Up @@ -234,34 +240,19 @@ impl SpecializedRenderPipeline for TonemappingPipeline {
shader_defs.push("TONEMAP_METHOD_REINHARD_LUMINANCE".into());
}
Tonemapping::AcesFitted => shader_defs.push("TONEMAP_METHOD_ACES_FITTED".into()),
#[cfg(feature = "tonemapping_luts")]
Tonemapping::AgX => {
#[cfg(not(feature = "tonemapping_luts"))]
error!(
"AgX tonemapping requires the `tonemapping_luts` feature.
Either enable the `tonemapping_luts` feature for bevy in `Cargo.toml` (recommended),
or use a different `Tonemapping` method for your `Camera2d`/`Camera3d`."
);
shader_defs.push("TONEMAP_METHOD_AGX".into());
}
Tonemapping::SomewhatBoringDisplayTransform => {
shader_defs.push("TONEMAP_METHOD_SOMEWHAT_BORING_DISPLAY_TRANSFORM".into());
}
#[cfg(feature = "tonemapping_luts")]
Tonemapping::TonyMcMapface => {
#[cfg(not(feature = "tonemapping_luts"))]
error!(
"TonyMcMapFace tonemapping requires the `tonemapping_luts` feature.
Either enable the `tonemapping_luts` feature for bevy in `Cargo.toml` (recommended),
or use a different `Tonemapping` method for your `Camera2d`/`Camera3d`."
);
shader_defs.push("TONEMAP_METHOD_TONY_MC_MAPFACE".into());
}
#[cfg(feature = "tonemapping_luts")]
Tonemapping::BlenderFilmic => {
#[cfg(not(feature = "tonemapping_luts"))]
error!(
"BlenderFilmic tonemapping requires the `tonemapping_luts` feature.
Either enable the `tonemapping_luts` feature for bevy in `Cargo.toml` (recommended),
or use a different `Tonemapping` method for your `Camera2d`/`Camera3d`."
);
shader_defs.push("TONEMAP_METHOD_BLENDER_FILMIC".into());
}
}
Expand Down Expand Up @@ -379,7 +370,7 @@ pub enum DebandDither {

pub fn get_lut_bindings<'a>(
images: &'a RenderAssets<GpuImage>,
tonemapping_luts: &'a TonemappingLuts,
#[cfg(feature = "tonemapping_luts")] tonemapping_luts: &'a TonemappingLuts,
tonemapping: &Tonemapping,
fallback_image: &'a FallbackImage,
) -> (&'a TextureView, &'a Sampler) {
Expand All @@ -389,9 +380,12 @@ pub fn get_lut_bindings<'a>(
| Tonemapping::Reinhard
| Tonemapping::ReinhardLuminance
| Tonemapping::AcesFitted
| Tonemapping::AgX
| Tonemapping::SomewhatBoringDisplayTransform => &tonemapping_luts.agx,
| Tonemapping::SomewhatBoringDisplayTransform => &PLACEHOLDER_LUTS_IMAGE,
#[cfg(feature = "tonemapping_luts")]
Tonemapping::AgX => &tonemapping_luts.agx,
#[cfg(feature = "tonemapping_luts")]
Tonemapping::TonyMcMapface => &tonemapping_luts.tony_mc_mapface,
#[cfg(feature = "tonemapping_luts")]
Tonemapping::BlenderFilmic => &tonemapping_luts.blender_filmic,
};
let lut_image = images.get(image).unwrap_or(&fallback_image.d3);
Expand Down
14 changes: 11 additions & 3 deletions crates/bevy_core_pipeline/src/tonemapping/node.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use std::sync::Mutex;

use crate::tonemapping::{TonemappingLuts, TonemappingPipeline, ViewTonemappingPipeline};
#[cfg(feature = "tonemapping_luts")]
use crate::tonemapping::TonemappingLuts;
use crate::tonemapping::{TonemappingPipeline, ViewTonemappingPipeline};

use bevy_ecs::{prelude::*, query::QueryItem};
use bevy_render::{
Expand Down Expand Up @@ -89,10 +91,16 @@ impl ViewNode for TonemappingNode {
bind_group
}
cached_bind_group => {
#[cfg(feature = "tonemapping_luts")]
let tonemapping_luts = world.resource::<TonemappingLuts>();

let lut_bindings =
get_lut_bindings(gpu_images, tonemapping_luts, tonemapping, fallback_image);
let lut_bindings = get_lut_bindings(
gpu_images,
#[cfg(feature = "tonemapping_luts")]
tonemapping_luts,
tonemapping,
fallback_image,
);

let bind_group = render_context.render_device().create_bind_group(
None,
Expand Down
2 changes: 2 additions & 0 deletions crates/bevy_internal/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ raw_vulkan_init = ["bevy_render/raw_vulkan_init"]
# Include tonemapping LUT KTX2 files.
tonemapping_luts = [
"bevy_core_pipeline?/tonemapping_luts",
"bevy_pbr?/tonemapping_luts",
"bevy_sprite_render?/tonemapping_luts",
"ktx2",
"bevy_image/zstd",
]
Expand Down
1 change: 1 addition & 0 deletions crates/bevy_pbr/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ meshlet_processor = [
"dep:itertools",
"dep:bitvec",
]
tonemapping_luts = ["bevy_core_pipeline/tonemapping_luts"]

[dependencies]
# bevy
Expand Down
18 changes: 12 additions & 6 deletions crates/bevy_pbr/src/deferred/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -270,14 +270,17 @@ impl SpecializedRenderPipeline for DeferredLightingLayout {
shader_defs.push("TONEMAP_METHOD_REINHARD_LUMINANCE".into());
} else if method == MeshPipelineKey::TONEMAP_METHOD_ACES_FITTED {
shader_defs.push("TONEMAP_METHOD_ACES_FITTED".into());
} else if method == MeshPipelineKey::TONEMAP_METHOD_AGX {
shader_defs.push("TONEMAP_METHOD_AGX".into());
} else if method == MeshPipelineKey::TONEMAP_METHOD_SOMEWHAT_BORING_DISPLAY_TRANSFORM {
shader_defs.push("TONEMAP_METHOD_SOMEWHAT_BORING_DISPLAY_TRANSFORM".into());
} else if method == MeshPipelineKey::TONEMAP_METHOD_BLENDER_FILMIC {
shader_defs.push("TONEMAP_METHOD_BLENDER_FILMIC".into());
} else if method == MeshPipelineKey::TONEMAP_METHOD_TONY_MC_MAPFACE {
shader_defs.push("TONEMAP_METHOD_TONY_MC_MAPFACE".into());
} else {
#[cfg(feature = "tonemapping_luts")]
if method == MeshPipelineKey::TONEMAP_METHOD_AGX {
shader_defs.push("TONEMAP_METHOD_AGX".into());
} else if method == MeshPipelineKey::TONEMAP_METHOD_BLENDER_FILMIC {
shader_defs.push("TONEMAP_METHOD_BLENDER_FILMIC".into());
} else if method == MeshPipelineKey::TONEMAP_METHOD_TONY_MC_MAPFACE {
shader_defs.push("TONEMAP_METHOD_TONY_MC_MAPFACE".into());
}
}

// Debanding is tied to tonemapping in the shader, cannot run without it.
Expand Down Expand Up @@ -503,11 +506,14 @@ pub fn prepare_deferred_lighting_pipelines(
MeshPipelineKey::TONEMAP_METHOD_REINHARD_LUMINANCE
}
Tonemapping::AcesFitted => MeshPipelineKey::TONEMAP_METHOD_ACES_FITTED,
#[cfg(feature = "tonemapping_luts")]
Tonemapping::AgX => MeshPipelineKey::TONEMAP_METHOD_AGX,
Tonemapping::SomewhatBoringDisplayTransform => {
MeshPipelineKey::TONEMAP_METHOD_SOMEWHAT_BORING_DISPLAY_TRANSFORM
}
#[cfg(feature = "tonemapping_luts")]
Tonemapping::TonyMcMapface => MeshPipelineKey::TONEMAP_METHOD_TONY_MC_MAPFACE,
#[cfg(feature = "tonemapping_luts")]
Tonemapping::BlenderFilmic => MeshPipelineKey::TONEMAP_METHOD_BLENDER_FILMIC,
};
}
Expand Down
3 changes: 3 additions & 0 deletions crates/bevy_pbr/src/material.rs
Original file line number Diff line number Diff line change
Expand Up @@ -632,11 +632,14 @@ pub const fn tonemapping_pipeline_key(tonemapping: Tonemapping) -> MeshPipelineK
Tonemapping::Reinhard => MeshPipelineKey::TONEMAP_METHOD_REINHARD,
Tonemapping::ReinhardLuminance => MeshPipelineKey::TONEMAP_METHOD_REINHARD_LUMINANCE,
Tonemapping::AcesFitted => MeshPipelineKey::TONEMAP_METHOD_ACES_FITTED,
#[cfg(feature = "tonemapping_luts")]
Tonemapping::AgX => MeshPipelineKey::TONEMAP_METHOD_AGX,
Tonemapping::SomewhatBoringDisplayTransform => {
MeshPipelineKey::TONEMAP_METHOD_SOMEWHAT_BORING_DISPLAY_TRANSFORM
}
#[cfg(feature = "tonemapping_luts")]
Tonemapping::TonyMcMapface => MeshPipelineKey::TONEMAP_METHOD_TONY_MC_MAPFACE,
#[cfg(feature = "tonemapping_luts")]
Tonemapping::BlenderFilmic => MeshPipelineKey::TONEMAP_METHOD_BLENDER_FILMIC,
}
}
Expand Down
18 changes: 12 additions & 6 deletions crates/bevy_pbr/src/render/mesh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2107,9 +2107,12 @@ bitflags::bitflags! {
const TONEMAP_METHOD_REINHARD = 1 << Self::TONEMAP_METHOD_SHIFT_BITS;
const TONEMAP_METHOD_REINHARD_LUMINANCE = 2 << Self::TONEMAP_METHOD_SHIFT_BITS;
const TONEMAP_METHOD_ACES_FITTED = 3 << Self::TONEMAP_METHOD_SHIFT_BITS;
#[cfg(feature = "tonemapping_luts")]
const TONEMAP_METHOD_AGX = 4 << Self::TONEMAP_METHOD_SHIFT_BITS;
const TONEMAP_METHOD_SOMEWHAT_BORING_DISPLAY_TRANSFORM = 5 << Self::TONEMAP_METHOD_SHIFT_BITS;
#[cfg(feature = "tonemapping_luts")]
const TONEMAP_METHOD_TONY_MC_MAPFACE = 6 << Self::TONEMAP_METHOD_SHIFT_BITS;
#[cfg(feature = "tonemapping_luts")]
const TONEMAP_METHOD_BLENDER_FILMIC = 7 << Self::TONEMAP_METHOD_SHIFT_BITS;
Comment on lines 2109 to 2116
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this MeshPipelineKeys be gated?

@DGriffin91

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i am moving forwards with the asumption that yes

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not really sure of all the implications. Who/what all might depend on them existing. I would guess if they have the feature disabled they're being conscious about things like this missing. Not sure how it would affect plugins that expect them to be there or something. Might be better to resolve at runtime.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would at least be nice to use #[doc(cfg)] to make the fact that these are gated behind a feature apparent on docs.rs

const SHADOW_FILTER_METHOD_RESERVED_BITS = Self::SHADOW_FILTER_METHOD_MASK_BITS << Self::SHADOW_FILTER_METHOD_SHIFT_BITS;
const SHADOW_FILTER_METHOD_HARDWARE_2X2 = 0 << Self::SHADOW_FILTER_METHOD_SHIFT_BITS;
Expand Down Expand Up @@ -2491,14 +2494,17 @@ impl SpecializedMeshPipeline for MeshPipeline {
shader_defs.push("TONEMAP_METHOD_REINHARD_LUMINANCE".into());
} else if method == MeshPipelineKey::TONEMAP_METHOD_ACES_FITTED {
shader_defs.push("TONEMAP_METHOD_ACES_FITTED".into());
} else if method == MeshPipelineKey::TONEMAP_METHOD_AGX {
shader_defs.push("TONEMAP_METHOD_AGX".into());
} else if method == MeshPipelineKey::TONEMAP_METHOD_SOMEWHAT_BORING_DISPLAY_TRANSFORM {
shader_defs.push("TONEMAP_METHOD_SOMEWHAT_BORING_DISPLAY_TRANSFORM".into());
} else if method == MeshPipelineKey::TONEMAP_METHOD_BLENDER_FILMIC {
shader_defs.push("TONEMAP_METHOD_BLENDER_FILMIC".into());
} else if method == MeshPipelineKey::TONEMAP_METHOD_TONY_MC_MAPFACE {
shader_defs.push("TONEMAP_METHOD_TONY_MC_MAPFACE".into());
} else {
#[cfg(feature = "tonemapping_luts")]
if method == MeshPipelineKey::TONEMAP_METHOD_AGX {
shader_defs.push("TONEMAP_METHOD_AGX".into());
} else if method == MeshPipelineKey::TONEMAP_METHOD_BLENDER_FILMIC {
shader_defs.push("TONEMAP_METHOD_BLENDER_FILMIC".into());
} else if method == MeshPipelineKey::TONEMAP_METHOD_TONY_MC_MAPFACE {
shader_defs.push("TONEMAP_METHOD_TONY_MC_MAPFACE".into());
}
}

// Debanding is tied to tonemapping in the shader, cannot run without it.
Expand Down
18 changes: 12 additions & 6 deletions crates/bevy_pbr/src/render/mesh_view_bindings.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
use alloc::sync::Arc;
#[cfg(feature = "tonemapping_luts")]
use bevy_core_pipeline::tonemapping::TonemappingLuts;
use bevy_core_pipeline::{
core_3d::ViewTransmissionTexture,
oit::{resolve::is_oit_supported, OitBuffers, OrderIndependentTransparencySettings},
prepass::ViewPrepassTextures,
tonemapping::{
get_lut_bind_group_layout_entries, get_lut_bindings, Tonemapping, TonemappingLuts,
},
tonemapping::{get_lut_bind_group_layout_entries, get_lut_bindings, Tonemapping},
};

use bevy_derive::{Deref, DerefMut};
use bevy_ecs::{
component::Component,
Expand Down Expand Up @@ -566,7 +567,7 @@ pub fn prepare_mesh_view_bind_groups(
Res<FallbackImageZero>,
),
globals_buffer: Res<GlobalsBuffer>,
tonemapping_luts: Res<TonemappingLuts>,
#[cfg(feature = "tonemapping_luts")] tonemapping_luts: Res<TonemappingLuts>,
light_probes_buffer: Res<LightProbesBuffer>,
visibility_ranges: Res<RenderVisibilityRanges>,
ssr_buffer: Res<ScreenSpaceReflectionsBuffer>,
Expand Down Expand Up @@ -653,8 +654,13 @@ pub fn prepare_mesh_view_bind_groups(

entries = entries.extend_with_indices(((17, environment_map_binding.clone()),));

let lut_bindings =
get_lut_bindings(&images, &tonemapping_luts, tonemapping, &fallback_image);
let lut_bindings = get_lut_bindings(
&images,
#[cfg(feature = "tonemapping_luts")]
&tonemapping_luts,
tonemapping,
&fallback_image,
);
entries = entries.extend_with_indices(((18, lut_bindings.0), (19, lut_bindings.1)));

// When using WebGL, we can't have a depth texture with multisampling
Expand Down
Loading
Loading