Add random shader utils, fix cluster_debug_visualization (#11956)

# Objective
- Partially addresses https://github.com/bevyengine/bevy/issues/11470
(I'd like to add Spatiotemporal Blue Noise in the future, but that's a
bit more controversial).
- Fix cluster_debug_visualization which has not compiled for a while

---

## Changelog
- Added random white noise shader functions to `bevy_pbr::utils`

## Migration Guide
- The `bevy_pbr::utils::random1D` shader function has been replaced by
the similar `bevy_pbr::utils::rand_f`.
This commit is contained in:
JMS55 2024-02-26 07:59:44 -08:00 committed by GitHub
parent ebdda09fc3
commit 40bfce556a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 42 additions and 12 deletions

View file

@ -2,13 +2,13 @@
#import bevy_pbr::{
mesh_view_bindings as bindings,
utils::hsv2rgb,
utils::{hsv2rgb, rand_f},
}
// NOTE: Keep in sync with bevy_pbr/src/light.rs
fn view_z_to_z_slice(view_z: f32, is_orthographic: bool) -> u32 {
var z_slice: u32 = 0u;
if (is_orthographic) {
if is_orthographic {
// NOTE: view_z is correct in the orthographic case
z_slice = u32(floor((view_z - bindings::lights.cluster_factors.z) * bindings::lights.cluster_factors.w));
} else {
@ -35,7 +35,7 @@ fn fragment_cluster_index(frag_coord: vec2<f32>, view_z: f32, is_orthographic: b
const CLUSTER_COUNT_SIZE = 9u;
fn unpack_offset_and_counts(cluster_index: u32) -> vec3<u32> {
#if AVAILABLE_STORAGE_BUFFER_BINDINGS >= 3
return bindings::cluster_offsets_and_counts.data[cluster_index].xyz;
return bindings::cluster_offsets_and_counts.data[cluster_index].xyz;
#else
let offset_and_counts = bindings::cluster_offsets_and_counts.data[cluster_index >> 2u][cluster_index & ((1u << 2u) - 1u)];
// [ 31 .. 18 | 17 .. 9 | 8 .. 0 ]
@ -61,19 +61,21 @@ fn get_light_id(index: u32) -> u32 {
}
fn cluster_debug_visualization(
output_color: vec4<f32>,
input_color: vec4<f32>,
view_z: f32,
is_orthographic: bool,
offset_and_counts: vec3<u32>,
cluster_index: u32,
) -> vec4<f32> {
var output_color = input_color;
// Cluster allocation debug (using 'over' alpha blending)
#ifdef CLUSTERED_FORWARD_DEBUG_Z_SLICES
// NOTE: This debug mode visualises the z-slices
let cluster_overlay_alpha = 0.1;
var z_slice: u32 = view_z_to_z_slice(view_z, is_orthographic);
// A hack to make the colors alternate a bit more
if ((z_slice & 1u) == 1u) {
if (z_slice & 1u) == 1u {
z_slice = z_slice + bindings::lights.cluster_dimensions.z / 2u;
}
let slice_color = hsv2rgb(f32(z_slice) / f32(bindings::lights.cluster_dimensions.z + 1u), 1.0, 0.5);
@ -87,15 +89,14 @@ fn cluster_debug_visualization(
// the fragment. It shows a sort of lighting complexity measure.
let cluster_overlay_alpha = 0.1;
let max_light_complexity_per_cluster = 64.0;
output_color.r = (1.0 - cluster_overlay_alpha) * output_color.r
+ cluster_overlay_alpha * smoothStep(0.0, max_light_complexity_per_cluster, f32(offset_and_counts[1] + offset_and_counts[2]));
output_color.g = (1.0 - cluster_overlay_alpha) * output_color.g
+ cluster_overlay_alpha * (1.0 - smoothStep(0.0, max_light_complexity_per_cluster, f32(offset_and_counts[1] + offset_and_counts[2])));
output_color.r = (1.0 - cluster_overlay_alpha) * output_color.r + cluster_overlay_alpha * smoothStep(0.0, max_light_complexity_per_cluster, f32(offset_and_counts[1] + offset_and_counts[2]));
output_color.g = (1.0 - cluster_overlay_alpha) * output_color.g + cluster_overlay_alpha * (1.0 - smoothStep(0.0, max_light_complexity_per_cluster, f32(offset_and_counts[1] + offset_and_counts[2])));
#endif // CLUSTERED_FORWARD_DEBUG_CLUSTER_LIGHT_COMPLEXITY
#ifdef CLUSTERED_FORWARD_DEBUG_CLUSTER_COHERENCY
// NOTE: Visualizes the cluster to which the fragment belongs
let cluster_overlay_alpha = 0.1;
let cluster_color = hsv2rgb(random1D(f32(cluster_index)), 1.0, 0.5);
var rng = cluster_index;
let cluster_color = hsv2rgb(rand_f(&rng), 1.0, 0.5);
output_color = vec4<f32>(
(1.0 - cluster_overlay_alpha) * output_color.rgb + cluster_overlay_alpha * cluster_color,
output_color.a

View file

@ -1,4 +1,5 @@
#define_import_path bevy_pbr::utils
#import bevy_pbr::rgb9e5
const PI: f32 = 3.141592653589793;
@ -17,8 +18,36 @@ fn hsv2rgb(hue: f32, saturation: f32, value: f32) -> vec3<f32> {
return value * mix(vec3<f32>(1.0), rgb, vec3<f32>(saturation));
}
fn random1D(s: f32) -> f32 {
return fract(sin(s * 12.9898) * 43758.5453123);
// Generates a random u32 in range [0, u32::MAX].
//
// `state` is a mutable reference to a u32 used as the seed.
//
// Values are generated via "white noise", with no correlation between values.
// In shaders, you often want spatial and/or temporal correlation. Use a different RNG method for these use cases.
//
// https://www.pcg-random.org
// https://www.reedbeta.com/blog/hash-functions-for-gpu-rendering
fn rand_u(state: ptr<function, u32>) -> u32 {
*state = *state * 747796405u + 2891336453u;
let word = ((*state >> ((*state >> 28u) + 4u)) ^ *state) * 277803737u;
return (word >> 22u) ^ word;
}
// Generates a random f32 in range [0, 1.0].
fn rand_f(state: ptr<function, u32>) -> f32 {
*state = *state * 747796405u + 2891336453u;
let word = ((*state >> ((*state >> 28u) + 4u)) ^ *state) * 277803737u;
return f32((word >> 22u) ^ word) * bitcast<f32>(0x2f800004u);
}
// Generates a random vec2<f32> where each value is in range [0, 1.0].
fn rand_vec2f(state: ptr<function, u32>) -> vec2<f32> {
return vec2(rand_f(state), rand_f(state));
}
// Generates a random u32 in range [0, n).
fn rand_range_u(n: u32, state: ptr<function, u32>) -> u32 {
return rand_u(state) % n;
}
// returns the (0-1, 0-1) position within the given viewport for the current buffer coords .