Skip to content

Commit

Permalink
Rename "point light" to "clusterable object" in cluster contexts. (#1…
Browse files Browse the repository at this point in the history
…3654)

We want to use the clustering infrastructure for light probes and decals
as well, not just point lights. This patch builds on top of #13640 and
performs the rename.

To make this series easier to review, this patch makes no code changes.
Only identifiers and comments are modified.

## Migration Guide

* In the PBR shaders, `point_lights` is now known as
`clusterable_objects`, `PointLight` is now known as `ClusterableObject`,
and `cluster_light_index_lists` is now known as
`clusterable_object_index_lists`.
  • Loading branch information
pcwalton authored Jun 4, 2024
1 parent ab2add6 commit ad68722
Show file tree
Hide file tree
Showing 13 changed files with 439 additions and 355 deletions.
418 changes: 226 additions & 192 deletions crates/bevy_pbr/src/cluster/assign.rs

Large diffs are not rendered by default.

239 changes: 135 additions & 104 deletions crates/bevy_pbr/src/cluster/mod.rs

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions crates/bevy_pbr/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ impl Plugin for PbrPlugin {
.register_type::<FogSettings>()
.register_type::<ShadowFilteringMethod>()
.init_resource::<AmbientLight>()
.init_resource::<GlobalVisiblePointLights>()
.init_resource::<GlobalVisibleClusterableObjects>()
.init_resource::<DirectionalLightShadowMap>()
.init_resource::<PointLightShadowMap>()
.register_type::<DefaultOpaqueRendererMethod>()
Expand Down Expand Up @@ -339,7 +339,7 @@ impl Plugin for PbrPlugin {
PostUpdate,
(
add_clusters.in_set(SimulationLightSystems::AddClusters),
crate::assign_lights_to_clusters
crate::assign_objects_to_clusters
.in_set(SimulationLightSystems::AssignLightsToClusters)
.after(TransformSystem::TransformPropagate)
.after(VisibilitySystems::CheckVisibility)
Expand Down Expand Up @@ -427,7 +427,7 @@ impl Plugin for PbrPlugin {
// Extract the required data from the main world
render_app
.init_resource::<ShadowSamplers>()
.init_resource::<GlobalLightMeta>();
.init_resource::<GlobalClusterableObjectMeta>();
}
}

Expand Down
6 changes: 3 additions & 3 deletions crates/bevy_pbr/src/light/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -561,7 +561,7 @@ pub fn update_directional_light_frusta(

// NOTE: Run this after assign_lights_to_clusters!
pub fn update_point_light_frusta(
global_lights: Res<GlobalVisiblePointLights>,
global_lights: Res<GlobalVisibleClusterableObjects>,
mut views: Query<
(Entity, &GlobalTransform, &PointLight, &mut CubemapFrusta),
Or<(Changed<GlobalTransform>, Changed<PointLight>)>,
Expand Down Expand Up @@ -605,7 +605,7 @@ pub fn update_point_light_frusta(
}

pub fn update_spot_light_frusta(
global_lights: Res<GlobalVisiblePointLights>,
global_lights: Res<GlobalVisibleClusterableObjects>,
mut views: Query<
(Entity, &GlobalTransform, &SpotLight, &mut Frustum),
Or<(Changed<GlobalTransform>, Changed<SpotLight>)>,
Expand Down Expand Up @@ -639,7 +639,7 @@ pub fn update_spot_light_frusta(
}

pub fn check_light_mesh_visibility(
visible_point_lights: Query<&VisiblePointLights>,
visible_point_lights: Query<&VisibleClusterableObjects>,
mut point_lights: Query<(
&PointLight,
&GlobalTransform,
Expand Down
34 changes: 22 additions & 12 deletions crates/bevy_pbr/src/render/clustered_forward.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,14 @@ fn unpack_offset_and_counts(cluster_index: u32) -> vec3<u32> {
#endif
}

fn get_light_id(index: u32) -> u32 {
fn get_clusterable_object_id(index: u32) -> u32 {
#if AVAILABLE_STORAGE_BUFFER_BINDINGS >= 3
return bindings::cluster_light_index_lists.data[index];
return bindings::clusterable_object_index_lists.data[index];
#else
// The index is correct but in cluster_light_index_lists we pack 4 u8s into a u32
// This means the index into cluster_light_index_lists is index / 4
let indices = bindings::cluster_light_index_lists.data[index >> 4u][(index >> 2u) & ((1u << 2u) - 1u)];
// The index is correct but in clusterable_object_index_lists we pack 4 u8s into a u32
// This means the index into clusterable_object_index_lists is index / 4
let indices = bindings::clusterable_object_index_lists.data[index >> 4u][(index >> 2u) &
((1u << 2u) - 1u)];
// And index % 4 gives the sub-index of the u8 within the u32 so we shift by 8 * sub-index
return (indices >> (8u * (index & ((1u << 2u) - 1u)))) & ((1u << 8u) - 1u);
#endif
Expand Down Expand Up @@ -93,14 +94,23 @@ fn cluster_debug_visualization(
output_color.a
);
#endif // CLUSTERED_FORWARD_DEBUG_Z_SLICES
#ifdef CLUSTERED_FORWARD_DEBUG_CLUSTER_LIGHT_COMPLEXITY
// NOTE: This debug mode visualises the number of lights within the cluster that contains
// the fragment. It shows a sort of lighting complexity measure.
#ifdef CLUSTERED_FORWARD_DEBUG_CLUSTER_COMPLEXITY
// NOTE: This debug mode visualises the number of clusterable objects within
// the cluster that contains the fragment. It shows a sort of cluster
// 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])));
#endif // CLUSTERED_FORWARD_DEBUG_CLUSTER_LIGHT_COMPLEXITY
let max_complexity_per_cluster = 64.0;
output_color.r = (1.0 - cluster_overlay_alpha) * output_color.r + cluster_overlay_alpha *
smoothStep(
0.0,
max_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_complexity_per_cluster,
f32(offset_and_counts[1] + offset_and_counts[2])));
#endif // CLUSTERED_FORWARD_DEBUG_CLUSTER_COMPLEXITY
#ifdef CLUSTERED_FORWARD_DEBUG_CLUSTER_COHERENCY
// NOTE: Visualizes the cluster to which the fragment belongs
let cluster_overlay_alpha = 0.1;
Expand Down
14 changes: 8 additions & 6 deletions crates/bevy_pbr/src/render/light.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ pub fn extract_lights(
mut commands: Commands,
point_light_shadow_map: Extract<Res<PointLightShadowMap>>,
directional_light_shadow_map: Extract<Res<DirectionalLightShadowMap>>,
global_point_lights: Extract<Res<GlobalVisiblePointLights>>,
global_point_lights: Extract<Res<GlobalVisibleClusterableObjects>>,
point_lights: Extract<
Query<(
&PointLight,
Expand Down Expand Up @@ -513,7 +513,7 @@ pub fn prepare_lights(
mut texture_cache: ResMut<TextureCache>,
render_device: Res<RenderDevice>,
render_queue: Res<RenderQueue>,
mut global_light_meta: ResMut<GlobalLightMeta>,
mut global_light_meta: ResMut<GlobalClusterableObjectMeta>,
mut light_meta: ResMut<LightMeta>,
views: Query<(
Entity,
Expand Down Expand Up @@ -634,7 +634,7 @@ pub fn prepare_lights(
// point light shadows and `spot_light_shadow_maps_count` spot light shadow maps,
// - then by entity as a stable key to ensure that a consistent set of lights are chosen if the light count limit is exceeded.
point_lights.sort_by(|(entity_1, light_1, _), (entity_2, light_2, _)| {
crate::cluster::point_light_order(
crate::cluster::clusterable_object_order(
(
entity_1,
&light_1.shadows_enabled,
Expand Down Expand Up @@ -714,7 +714,7 @@ pub fn prepare_lights(
}
};

gpu_point_lights.push(GpuPointLight {
gpu_point_lights.push(GpuClusterableObject {
light_custom_data,
// premultiply color by intensity
// we don't use the alpha at all, so no reason to multiply only [0..3]
Expand Down Expand Up @@ -779,9 +779,11 @@ pub fn prepare_lights(
}
}

global_light_meta.gpu_point_lights.set(gpu_point_lights);
global_light_meta
.gpu_point_lights
.gpu_clusterable_objects
.set(gpu_point_lights);
global_light_meta
.gpu_clusterable_objects
.write_buffer(&render_device, &render_queue);

live_shadow_mapping_lights.clear();
Expand Down
33 changes: 20 additions & 13 deletions crates/bevy_pbr/src/render/mesh_view_bindings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,9 @@ use crate::{
self, IrradianceVolume, RenderViewIrradianceVolumeBindGroupEntries,
IRRADIANCE_VOLUMES_ARE_USABLE,
},
prepass, FogMeta, GlobalLightMeta, GpuFog, GpuLights, GpuPointLights, LightMeta,
LightProbesBuffer, LightProbesUniform, MeshPipeline, MeshPipelineKey, RenderViewLightProbes,
ScreenSpaceAmbientOcclusionTextures, ScreenSpaceReflectionsBuffer,
prepass, FogMeta, GlobalClusterableObjectMeta, GpuClusterableObjects, GpuFog, GpuLights,
LightMeta, LightProbesBuffer, LightProbesUniform, MeshPipeline, MeshPipelineKey,
RenderViewLightProbes, ScreenSpaceAmbientOcclusionTextures, ScreenSpaceReflectionsBuffer,
ScreenSpaceReflectionsUniform, ShadowSamplers, ViewClusterBindings, ViewShadowBindings,
CLUSTERED_FORWARD_STORAGE_BUFFER_COUNT,
};
Expand Down Expand Up @@ -229,13 +229,13 @@ fn layout_entries(
),
// Directional Shadow Texture Array Sampler
(5, sampler(SamplerBindingType::Comparison)),
// PointLights
// ClusterableObjects
(
6,
buffer_layout(
clustered_forward_buffer_binding_type,
false,
Some(GpuPointLights::min_size(
Some(GpuClusterableObjects::min_size(
clustered_forward_buffer_binding_type,
)),
),
Expand All @@ -246,9 +246,11 @@ fn layout_entries(
buffer_layout(
clustered_forward_buffer_binding_type,
false,
Some(ViewClusterBindings::min_size_cluster_light_index_lists(
clustered_forward_buffer_binding_type,
)),
Some(
ViewClusterBindings::min_size_clusterable_object_index_lists(
clustered_forward_buffer_binding_type,
),
),
),
),
// ClusterOffsetsAndCounts
Expand Down Expand Up @@ -446,7 +448,7 @@ pub fn prepare_mesh_view_bind_groups(
mesh_pipeline: Res<MeshPipeline>,
shadow_samplers: Res<ShadowSamplers>,
light_meta: Res<LightMeta>,
global_light_meta: Res<GlobalLightMeta>,
global_light_meta: Res<GlobalClusterableObjectMeta>,
fog_meta: Res<FogMeta>,
view_uniforms: Res<ViewUniforms>,
views: Query<(
Expand Down Expand Up @@ -476,7 +478,7 @@ pub fn prepare_mesh_view_bind_groups(
if let (
Some(view_binding),
Some(light_binding),
Some(point_light_binding),
Some(clusterable_objects_binding),
Some(globals),
Some(fog_binding),
Some(light_probes_binding),
Expand All @@ -485,7 +487,7 @@ pub fn prepare_mesh_view_bind_groups(
) = (
view_uniforms.uniforms.binding(),
light_meta.view_gpu_lights.binding(),
global_light_meta.gpu_point_lights.binding(),
global_light_meta.gpu_clusterable_objects.binding(),
globals_buffer.buffer.binding(),
fog_meta.gpu_fogs.binding(),
light_probes_buffer.binding(),
Expand Down Expand Up @@ -524,8 +526,13 @@ pub fn prepare_mesh_view_bind_groups(
(3, &shadow_samplers.point_light_sampler),
(4, &shadow_bindings.directional_light_depth_texture_view),
(5, &shadow_samplers.directional_light_sampler),
(6, point_light_binding.clone()),
(7, cluster_bindings.light_index_lists_binding().unwrap()),
(6, clusterable_objects_binding.clone()),
(
7,
cluster_bindings
.clusterable_object_index_lists_binding()
.unwrap(),
),
(8, cluster_bindings.offsets_and_counts_binding().unwrap()),
(9, globals.clone()),
(10, fog_binding.clone()),
Expand Down
8 changes: 4 additions & 4 deletions crates/bevy_pbr/src/render/mesh_view_bindings.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@
@group(0) @binding(5) var directional_shadow_textures_sampler: sampler_comparison;

#if AVAILABLE_STORAGE_BUFFER_BINDINGS >= 3
@group(0) @binding(6) var<storage> point_lights: types::PointLights;
@group(0) @binding(7) var<storage> cluster_light_index_lists: types::ClusterLightIndexLists;
@group(0) @binding(6) var<storage> clusterable_objects: types::ClusterableObjects;
@group(0) @binding(7) var<storage> clusterable_object_index_lists: types::ClusterLightIndexLists;
@group(0) @binding(8) var<storage> cluster_offsets_and_counts: types::ClusterOffsetsAndCounts;
#else
@group(0) @binding(6) var<uniform> point_lights: types::PointLights;
@group(0) @binding(7) var<uniform> cluster_light_index_lists: types::ClusterLightIndexLists;
@group(0) @binding(6) var<uniform> clusterable_objects: types::ClusterableObjects;
@group(0) @binding(7) var<uniform> clusterable_object_index_lists: types::ClusterLightIndexLists;
@group(0) @binding(8) var<uniform> cluster_offsets_and_counts: types::ClusterOffsetsAndCounts;
#endif

Expand Down
12 changes: 6 additions & 6 deletions crates/bevy_pbr/src/render/mesh_view_types.wgsl
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#define_import_path bevy_pbr::mesh_view_types

struct PointLight {
struct ClusterableObject {
// For point lights: the lower-right 2x2 values of the projection matrix [2][2] [2][3] [3][2] [3][3]
// For spot lights: the direction (x,z), spot_scale and spot_offset
light_custom_data: vec4<f32>,
Expand Down Expand Up @@ -88,8 +88,8 @@ const FOG_MODE_EXPONENTIAL_SQUARED: u32 = 3u;
const FOG_MODE_ATMOSPHERIC: u32 = 4u;

#if AVAILABLE_STORAGE_BUFFER_BINDINGS >= 3
struct PointLights {
data: array<PointLight>,
struct ClusterableObjects {
data: array<ClusterableObject>,
};
struct ClusterLightIndexLists {
data: array<u32>,
Expand All @@ -98,11 +98,11 @@ struct ClusterOffsetsAndCounts {
data: array<vec4<u32>>,
};
#else
struct PointLights {
data: array<PointLight, 256u>,
struct ClusterableObjects {
data: array<ClusterableObject, 256u>,
};
struct ClusterLightIndexLists {
// each u32 contains 4 u8 indices into the PointLights array
// each u32 contains 4 u8 indices into the ClusterableObjects array
data: array<vec4<u32>, 1024u>,
};
struct ClusterOffsetsAndCounts {
Expand Down
12 changes: 6 additions & 6 deletions crates/bevy_pbr/src/render/pbr_functions.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -410,10 +410,10 @@ fn apply_pbr_lighting(

// Point lights (direct)
for (var i: u32 = offset_and_counts[0]; i < offset_and_counts[0] + offset_and_counts[1]; i = i + 1u) {
let light_id = clustering::get_light_id(i);
let light_id = clustering::get_clusterable_object_id(i);
var shadow: f32 = 1.0;
if ((in.flags & MESH_FLAGS_SHADOW_RECEIVER_BIT) != 0u
&& (view_bindings::point_lights.data[light_id].flags & mesh_view_types::POINT_LIGHT_FLAGS_SHADOWS_ENABLED_BIT) != 0u) {
&& (view_bindings::clusterable_objects.data[light_id].flags & mesh_view_types::POINT_LIGHT_FLAGS_SHADOWS_ENABLED_BIT) != 0u) {
shadow = shadows::fetch_point_shadow(light_id, in.world_position, in.world_normal);
}

Expand All @@ -432,7 +432,7 @@ fn apply_pbr_lighting(
// F0 = vec3<f32>(0.0)
var transmitted_shadow: f32 = 1.0;
if ((in.flags & (MESH_FLAGS_SHADOW_RECEIVER_BIT | MESH_FLAGS_TRANSMITTED_SHADOW_RECEIVER_BIT)) == (MESH_FLAGS_SHADOW_RECEIVER_BIT | MESH_FLAGS_TRANSMITTED_SHADOW_RECEIVER_BIT)
&& (view_bindings::point_lights.data[light_id].flags & mesh_view_types::POINT_LIGHT_FLAGS_SHADOWS_ENABLED_BIT) != 0u) {
&& (view_bindings::clusterable_objects.data[light_id].flags & mesh_view_types::POINT_LIGHT_FLAGS_SHADOWS_ENABLED_BIT) != 0u) {
transmitted_shadow = shadows::fetch_point_shadow(light_id, diffuse_transmissive_lobe_world_position, -in.world_normal);
}

Expand All @@ -444,11 +444,11 @@ fn apply_pbr_lighting(

// Spot lights (direct)
for (var i: u32 = offset_and_counts[0] + offset_and_counts[1]; i < offset_and_counts[0] + offset_and_counts[1] + offset_and_counts[2]; i = i + 1u) {
let light_id = clustering::get_light_id(i);
let light_id = clustering::get_clusterable_object_id(i);

var shadow: f32 = 1.0;
if ((in.flags & MESH_FLAGS_SHADOW_RECEIVER_BIT) != 0u
&& (view_bindings::point_lights.data[light_id].flags & mesh_view_types::POINT_LIGHT_FLAGS_SHADOWS_ENABLED_BIT) != 0u) {
&& (view_bindings::clusterable_objects.data[light_id].flags & mesh_view_types::POINT_LIGHT_FLAGS_SHADOWS_ENABLED_BIT) != 0u) {
shadow = shadows::fetch_spot_shadow(light_id, in.world_position, in.world_normal);
}

Expand All @@ -467,7 +467,7 @@ fn apply_pbr_lighting(
// F0 = vec3<f32>(0.0)
var transmitted_shadow: f32 = 1.0;
if ((in.flags & (MESH_FLAGS_SHADOW_RECEIVER_BIT | MESH_FLAGS_TRANSMITTED_SHADOW_RECEIVER_BIT)) == (MESH_FLAGS_SHADOW_RECEIVER_BIT | MESH_FLAGS_TRANSMITTED_SHADOW_RECEIVER_BIT)
&& (view_bindings::point_lights.data[light_id].flags & mesh_view_types::POINT_LIGHT_FLAGS_SHADOWS_ENABLED_BIT) != 0u) {
&& (view_bindings::clusterable_objects.data[light_id].flags & mesh_view_types::POINT_LIGHT_FLAGS_SHADOWS_ENABLED_BIT) != 0u) {
transmitted_shadow = shadows::fetch_spot_shadow(light_id, diffuse_transmissive_lobe_world_position, -in.world_normal);
}

Expand Down
4 changes: 2 additions & 2 deletions crates/bevy_pbr/src/render/pbr_lighting.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -447,7 +447,7 @@ fn point_light(light_id: u32, input: ptr<function, LightingInput>) -> vec3<f32>
let N = (*input).layers[LAYER_BASE].N;
let V = (*input).V;

let light = &view_bindings::point_lights.data[light_id];
let light = &view_bindings::clusterable_objects.data[light_id];
let light_to_frag = (*light).position_radius.xyz - P;
let L = normalize(light_to_frag);
let distance_square = dot(light_to_frag, light_to_frag);
Expand Down Expand Up @@ -540,7 +540,7 @@ fn spot_light(light_id: u32, input: ptr<function, LightingInput>) -> vec3<f32> {
// reuse the point light calculations
let point_light = point_light(light_id, input);

let light = &view_bindings::point_lights.data[light_id];
let light = &view_bindings::clusterable_objects.data[light_id];

// reconstruct spot dir from x/z and y-direction flag
var spot_dir = vec3<f32>((*light).light_custom_data.x, 0.0, (*light).light_custom_data.y);
Expand Down
4 changes: 2 additions & 2 deletions crates/bevy_pbr/src/render/shadows.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
const flip_z: vec3<f32> = vec3<f32>(1.0, 1.0, -1.0);

fn fetch_point_shadow(light_id: u32, frag_position: vec4<f32>, surface_normal: vec3<f32>) -> f32 {
let light = &view_bindings::point_lights.data[light_id];
let light = &view_bindings::clusterable_objects.data[light_id];

// because the shadow maps align with the axes and the frustum planes are at 45 degrees
// we can get the worldspace depth by taking the largest absolute axis
Expand Down Expand Up @@ -47,7 +47,7 @@ fn fetch_point_shadow(light_id: u32, frag_position: vec4<f32>, surface_normal: v
}

fn fetch_spot_shadow(light_id: u32, frag_position: vec4<f32>, surface_normal: vec3<f32>) -> f32 {
let light = &view_bindings::point_lights.data[light_id];
let light = &view_bindings::clusterable_objects.data[light_id];

let surface_to_light = (*light).position_radius.xyz - frag_position.xyz;

Expand Down
4 changes: 2 additions & 2 deletions examples/stress_tests/many_lights.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use bevy::{
color::palettes::css::DEEP_PINK,
diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin},
math::{DVec2, DVec3},
pbr::{ExtractedPointLight, GlobalLightMeta},
pbr::{ExtractedPointLight, GlobalClusterableObjectMeta},
prelude::*,
render::{camera::ScalingMode, Render, RenderApp, RenderSet},
window::{PresentMode, WindowResolution},
Expand Down Expand Up @@ -170,7 +170,7 @@ fn print_visible_light_count(
time: Res<Time>,
mut timer: Local<PrintingTimer>,
visible: Query<&ExtractedPointLight>,
global_light_meta: Res<GlobalLightMeta>,
global_light_meta: Res<GlobalClusterableObjectMeta>,
) {
timer.0.tick(time.delta());

Expand Down

0 comments on commit ad68722

Please sign in to comment.