diff --git a/assets/shaders/tonemapping_test_patterns.wgsl b/assets/shaders/tonemapping_test_patterns.wgsl index 891a66f3a1..7fe88bf548 100644 --- a/assets/shaders/tonemapping_test_patterns.wgsl +++ b/assets/shaders/tonemapping_test_patterns.wgsl @@ -1,9 +1,10 @@ #import bevy_pbr::{ mesh_view_bindings, forward_io::VertexOutput, - utils::PI, } +#import bevy_render::maths::PI + #ifdef TONEMAP_IN_SHADER #import bevy_core_pipeline::tonemapping::tone_mapping #endif diff --git a/crates/bevy_core_pipeline/src/tonemapping/tonemapping_shared.wgsl b/crates/bevy_core_pipeline/src/tonemapping/tonemapping_shared.wgsl index 929edec67c..62d0c92861 100644 --- a/crates/bevy_core_pipeline/src/tonemapping/tonemapping_shared.wgsl +++ b/crates/bevy_core_pipeline/src/tonemapping/tonemapping_shared.wgsl @@ -1,7 +1,10 @@ #define_import_path bevy_core_pipeline::tonemapping -#import bevy_render::view::ColorGrading -#import bevy_pbr::utils::{PI_2, hsv_to_rgb, rgb_to_hsv}; +#import bevy_render::{ + view::ColorGrading, + color_operations::{hsv_to_rgb, rgb_to_hsv}, + maths::PI_2 +} // hack !! not sure what to do with this #ifdef TONEMAPPING_PASS diff --git a/crates/bevy_pbr/src/render/clustered_forward.wgsl b/crates/bevy_pbr/src/render/clustered_forward.wgsl index ae142f2eb5..5652524896 100644 --- a/crates/bevy_pbr/src/render/clustered_forward.wgsl +++ b/crates/bevy_pbr/src/render/clustered_forward.wgsl @@ -2,7 +2,12 @@ #import bevy_pbr::{ mesh_view_bindings as bindings, - utils::{PI_2, hsv_to_rgb, rand_f}, + utils::rand_f, +} + +#import bevy_render::{ + color_operations::hsv_to_rgb, + maths::PI_2, } // NOTE: Keep in sync with bevy_pbr/src/light.rs diff --git a/crates/bevy_pbr/src/render/pbr_functions.wgsl b/crates/bevy_pbr/src/render/pbr_functions.wgsl index 9f6b5fb240..60db5106f8 100644 --- a/crates/bevy_pbr/src/render/pbr_functions.wgsl +++ b/crates/bevy_pbr/src/render/pbr_functions.wgsl @@ -12,9 +12,10 @@ ambient, irradiance_volume, mesh_types::{MESH_FLAGS_SHADOW_RECEIVER_BIT, MESH_FLAGS_TRANSMITTED_SHADOW_RECEIVER_BIT}, - utils::E, } +#import bevy_render::maths::E + #ifdef ENVIRONMENT_MAP #import bevy_pbr::environment_map #endif diff --git a/crates/bevy_pbr/src/render/pbr_lighting.wgsl b/crates/bevy_pbr/src/render/pbr_lighting.wgsl index bc279ca594..cfb43914ce 100644 --- a/crates/bevy_pbr/src/render/pbr_lighting.wgsl +++ b/crates/bevy_pbr/src/render/pbr_lighting.wgsl @@ -1,11 +1,12 @@ #define_import_path bevy_pbr::lighting #import bevy_pbr::{ - utils::PI, mesh_view_types::POINT_LIGHT_FLAGS_SPOT_LIGHT_Y_NEGATIVE, mesh_view_bindings as view_bindings, } +#import bevy_render::maths::PI + // From the Filament design doc // https://google.github.io/filament/Filament.html#table_symbols // Symbol Definition diff --git a/crates/bevy_pbr/src/render/pbr_transmission.wgsl b/crates/bevy_pbr/src/render/pbr_transmission.wgsl index 65f84c86bb..4a48260ae6 100644 --- a/crates/bevy_pbr/src/render/pbr_transmission.wgsl +++ b/crates/bevy_pbr/src/render/pbr_transmission.wgsl @@ -3,11 +3,13 @@ #import bevy_pbr::{ lighting, prepass_utils, - utils::{PI, interleaved_gradient_noise}, + utils::interleaved_gradient_noise, utils, mesh_view_bindings as view_bindings, }; +#import bevy_render::maths::PI + #import bevy_core_pipeline::tonemapping::{ approximate_inverse_tone_mapping }; diff --git a/crates/bevy_pbr/src/render/shadow_sampling.wgsl b/crates/bevy_pbr/src/render/shadow_sampling.wgsl index 0ced974ebf..ec155cf3fc 100644 --- a/crates/bevy_pbr/src/render/shadow_sampling.wgsl +++ b/crates/bevy_pbr/src/render/shadow_sampling.wgsl @@ -2,10 +2,10 @@ #import bevy_pbr::{ mesh_view_bindings as view_bindings, - utils::{PI, interleaved_gradient_noise}, + utils::interleaved_gradient_noise, utils, } -#import bevy_render::maths::orthonormalize +#import bevy_render::maths::{orthonormalize, PI} // Do the lookup, using HW 2x2 PCF and comparison fn sample_shadow_map_hardware(light_local: vec2, depth: f32, array_index: i32) -> f32 { diff --git a/crates/bevy_pbr/src/render/shadows.wgsl b/crates/bevy_pbr/src/render/shadows.wgsl index bec8b90d26..eed6bf6a40 100644 --- a/crates/bevy_pbr/src/render/shadows.wgsl +++ b/crates/bevy_pbr/src/render/shadows.wgsl @@ -3,10 +3,14 @@ #import bevy_pbr::{ mesh_view_types::POINT_LIGHT_FLAGS_SPOT_LIGHT_Y_NEGATIVE, mesh_view_bindings as view_bindings, - utils::{hsv_to_rgb, PI_2}, shadow_sampling::{SPOT_SHADOW_TEXEL_SIZE, sample_shadow_cubemap, sample_shadow_map} } +#import bevy_render::{ + color_operations::hsv_to_rgb, + maths::PI_2 +} + const flip_z: vec3 = vec3(1.0, 1.0, -1.0); fn fetch_point_shadow(light_id: u32, frag_position: vec4, surface_normal: vec3) -> f32 { diff --git a/crates/bevy_pbr/src/render/utils.wgsl b/crates/bevy_pbr/src/render/utils.wgsl index 057c2f734c..dbee281815 100644 --- a/crates/bevy_pbr/src/render/utils.wgsl +++ b/crates/bevy_pbr/src/render/utils.wgsl @@ -2,55 +2,6 @@ #import bevy_pbr::rgb9e5 -const PI: f32 = 3.141592653589793; // π -const PI_2: f32 = 6.283185307179586; // 2π -const HALF_PI: f32 = 1.57079632679; // π/2 -const FRAC_PI_3: f32 = 1.0471975512; // π/3 -const E: f32 = 2.718281828459045; // exp(1) - -// Converts HSV to RGB. -// -// Input: H ∈ [0, 2π), S ∈ [0, 1], V ∈ [0, 1]. -// Output: R ∈ [0, 1], G ∈ [0, 1], B ∈ [0, 1]. -// -// -fn hsv_to_rgb(hsv: vec3) -> vec3 { - let n = vec3(5.0, 3.0, 1.0); - let k = (n + hsv.x / FRAC_PI_3) % 6.0; - return hsv.z - hsv.z * hsv.y * max(vec3(0.0), min(k, min(4.0 - k, vec3(1.0)))); -} - -// Converts RGB to HSV. -// -// Input: R ∈ [0, 1], G ∈ [0, 1], B ∈ [0, 1]. -// Output: H ∈ [0, 2π), S ∈ [0, 1], V ∈ [0, 1]. -// -// -fn rgb_to_hsv(rgb: vec3) -> vec3 { - let x_max = max(rgb.r, max(rgb.g, rgb.b)); // i.e. V - let x_min = min(rgb.r, min(rgb.g, rgb.b)); - let c = x_max - x_min; // chroma - - var swizzle = vec3(0.0); - if (x_max == rgb.r) { - swizzle = vec3(rgb.gb, 0.0); - } else if (x_max == rgb.g) { - swizzle = vec3(rgb.br, 2.0); - } else { - swizzle = vec3(rgb.rg, 4.0); - } - - let h = FRAC_PI_3 * (((swizzle.x - swizzle.y) / c + swizzle.z) % 6.0); - - // Avoid division by zero. - var s = 0.0; - if (x_max > 0.0) { - s = c / x_max; - } - - return vec3(h, s, x_max); -} - // Generates a random u32 in range [0, u32::MAX]. // // `state` is a mutable reference to a u32 used as the seed. diff --git a/crates/bevy_pbr/src/ssao/gtao.wgsl b/crates/bevy_pbr/src/ssao/gtao.wgsl index be5fea01ee..1fded0b53a 100644 --- a/crates/bevy_pbr/src/ssao/gtao.wgsl +++ b/crates/bevy_pbr/src/ssao/gtao.wgsl @@ -5,13 +5,12 @@ // Source code heavily based on XeGTAO v1.30 from Intel // https://github.com/GameTechDev/XeGTAO/blob/0d177ce06bfa642f64d8af4de1197ad1bcb862d4/Source/Rendering/Shaders/XeGTAO.hlsli -#import bevy_pbr::{ - gtao_utils::fast_acos, - utils::{PI, HALF_PI}, -} +#import bevy_pbr::gtao_utils::fast_acos + #import bevy_render::{ view::View, globals::Globals, + maths::{PI, HALF_PI}, } @group(0) @binding(0) var preprocessed_depth: texture_2d; diff --git a/crates/bevy_pbr/src/ssao/gtao_utils.wgsl b/crates/bevy_pbr/src/ssao/gtao_utils.wgsl index f081393edb..32c46e1d1d 100644 --- a/crates/bevy_pbr/src/ssao/gtao_utils.wgsl +++ b/crates/bevy_pbr/src/ssao/gtao_utils.wgsl @@ -1,6 +1,6 @@ #define_import_path bevy_pbr::gtao_utils -#import bevy_pbr::utils::{PI, HALF_PI} +#import bevy_render::maths::{PI, HALF_PI} // Approximates single-bounce ambient occlusion to multi-bounce ambient occlusion // https://blog.selfshadow.com/publications/s2016-shading-course/activision/s2016_pbs_activision_occlusion.pdf#page=78 diff --git a/crates/bevy_render/src/color_operations.wgsl b/crates/bevy_render/src/color_operations.wgsl new file mode 100644 index 0000000000..b68ad2a3db --- /dev/null +++ b/crates/bevy_render/src/color_operations.wgsl @@ -0,0 +1,47 @@ +#define_import_path bevy_render::color_operations + +#import bevy_render::maths::FRAC_PI_3 + +// Converts HSV to RGB. +// +// Input: H ∈ [0, 2π), S ∈ [0, 1], V ∈ [0, 1]. +// Output: R ∈ [0, 1], G ∈ [0, 1], B ∈ [0, 1]. +// +// +fn hsv_to_rgb(hsv: vec3) -> vec3 { + let n = vec3(5.0, 3.0, 1.0); + let k = (n + hsv.x / FRAC_PI_3) % 6.0; + return hsv.z - hsv.z * hsv.y * max(vec3(0.0), min(k, min(4.0 - k, vec3(1.0)))); +} + +// Converts RGB to HSV. +// +// Input: R ∈ [0, 1], G ∈ [0, 1], B ∈ [0, 1]. +// Output: H ∈ [0, 2π), S ∈ [0, 1], V ∈ [0, 1]. +// +// +fn rgb_to_hsv(rgb: vec3) -> vec3 { + let x_max = max(rgb.r, max(rgb.g, rgb.b)); // i.e. V + let x_min = min(rgb.r, min(rgb.g, rgb.b)); + let c = x_max - x_min; // chroma + + var swizzle = vec3(0.0); + if (x_max == rgb.r) { + swizzle = vec3(rgb.gb, 0.0); + } else if (x_max == rgb.g) { + swizzle = vec3(rgb.br, 2.0); + } else { + swizzle = vec3(rgb.rg, 4.0); + } + + let h = FRAC_PI_3 * (((swizzle.x - swizzle.y) / c + swizzle.z) % 6.0); + + // Avoid division by zero. + var s = 0.0; + if (x_max > 0.0) { + s = c / x_max; + } + + return vec3(h, s, x_max); +} + diff --git a/crates/bevy_render/src/lib.rs b/crates/bevy_render/src/lib.rs index 60d8ef648a..5dd28d4596 100644 --- a/crates/bevy_render/src/lib.rs +++ b/crates/bevy_render/src/lib.rs @@ -236,6 +236,8 @@ pub struct RenderApp; pub const INSTANCE_INDEX_SHADER_HANDLE: Handle = Handle::weak_from_u128(10313207077636615845); pub const MATHS_SHADER_HANDLE: Handle = Handle::weak_from_u128(10665356303104593376); +pub const COLOR_OPERATIONS_SHADER_HANDLE: Handle = + Handle::weak_from_u128(1844674407370955161); impl Plugin for RenderPlugin { /// Initializes the renderer, sets up the [`RenderSet`] and creates the rendering sub-app. @@ -359,6 +361,12 @@ impl Plugin for RenderPlugin { fn finish(&self, app: &mut App) { load_internal_asset!(app, MATHS_SHADER_HANDLE, "maths.wgsl", Shader::from_wgsl); + load_internal_asset!( + app, + COLOR_OPERATIONS_SHADER_HANDLE, + "color_operations.wgsl", + Shader::from_wgsl + ); if let Some(future_renderer_resources) = app.world_mut().remove_resource::() { diff --git a/crates/bevy_render/src/maths.wgsl b/crates/bevy_render/src/maths.wgsl index 720e6bac46..29ea0a8965 100644 --- a/crates/bevy_render/src/maths.wgsl +++ b/crates/bevy_render/src/maths.wgsl @@ -1,5 +1,11 @@ #define_import_path bevy_render::maths +const PI: f32 = 3.141592653589793; // π +const PI_2: f32 = 6.283185307179586; // 2π +const HALF_PI: f32 = 1.57079632679; // π/2 +const FRAC_PI_3: f32 = 1.0471975512; // π/3 +const E: f32 = 2.718281828459045; // exp(1) + fn affine2_to_square(affine: mat3x2) -> mat3x3 { return mat3x3( vec3(affine[0].xy, 0.0),