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 crates/bevy_core_pipeline/src/core_2d/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -405,7 +405,7 @@ pub fn extract_core_2d_camera_phases(
}

// This is the main 2D camera, so we use the first subview index (0).
let retained_view_entity = RetainedViewEntity::new(main_entity.into(), None, 0);
let retained_view_entity = RetainedViewEntity::new(main_entity.into(), None, None, 0);

transparent_2d_phases.prepare_for_new_frame(retained_view_entity);
opaque_2d_phases.prepare_for_new_frame(retained_view_entity, GpuPreprocessingMode::None);
Expand Down
4 changes: 2 additions & 2 deletions crates/bevy_core_pipeline/src/core_3d/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -517,7 +517,7 @@ pub fn extract_core_3d_camera_phases(
});

// This is the main 3D camera, so use the first subview index (0).
let retained_view_entity = RetainedViewEntity::new(main_entity.into(), None, 0);
let retained_view_entity = RetainedViewEntity::new(main_entity.into(), None, None, 0);

opaque_3d_phases.prepare_for_new_frame(retained_view_entity, gpu_preprocessing_mode);
alpha_mask_3d_phases.prepare_for_new_frame(retained_view_entity, gpu_preprocessing_mode);
Expand Down Expand Up @@ -587,7 +587,7 @@ pub fn extract_camera_prepass_phase(
});

// This is the main 3D camera, so we use the first subview index (0).
let retained_view_entity = RetainedViewEntity::new(main_entity.into(), None, 0);
let retained_view_entity = RetainedViewEntity::new(main_entity.into(), None, None, 0);

if depth_prepass || normal_prepass || motion_vector_prepass {
opaque_3d_prepass_phases
Expand Down
92 changes: 51 additions & 41 deletions crates/bevy_pbr/src/render/light.rs
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,7 @@ pub fn extract_lights(
),
>,
>,
aux_render_entity: Extract<Query<RenderEntity>>,
rect_lights: Extract<
Query<
(
Expand Down Expand Up @@ -485,6 +486,7 @@ pub fn extract_lights(
let retained_view_entity = RetainedViewEntity {
main_entity: MainEntity::from(main_entity),
auxiliary_entity: MainEntity::from(Entity::PLACEHOLDER),
render_auxiliary_entity: Entity::PLACEHOLDER,
subview_index: face_index,
};
render_shadow_map_visible_entities
Expand Down Expand Up @@ -596,6 +598,7 @@ pub fn extract_lights(
let retained_view_entity = RetainedViewEntity {
main_entity: MainEntity::from(main_entity),
auxiliary_entity: MainEntity::from(Entity::PLACEHOLDER),
render_auxiliary_entity: Entity::PLACEHOLDER,
subview_index: 0,
};
render_shadow_map_visible_entities
Expand Down Expand Up @@ -738,43 +741,47 @@ pub fn extract_lights(
for (main_auxiliary_entity, visible_mesh_entities_list) in
visible_entities.entities.iter()
{
for subview_index in 0..(cascade_config.bounds.len() as u32) {
let retained_view_entity = RetainedViewEntity {
main_entity: MainEntity::from(main_entity),
auxiliary_entity: MainEntity::from(*main_auxiliary_entity),
subview_index,
};
all_cascades_seen.insert(retained_view_entity);

existing_shadow_map_visible_entities
.subviews
.entry(retained_view_entity)
.or_default();

// Extract the visible CPU culled entities to the list.
let extracted_entities = &mut existing_extracted_shadow_map_visible_entities
.subviews
.entry(retained_view_entity)
.or_default()
.classes
.entry(TypeId::of::<Mesh3d>())
.or_default()
.entities;
extracted_entities.clear();
let Some(visible_mesh_entities) =
visible_mesh_entities_list.get(subview_index as usize)
else {
continue;
};
extracted_entities.extend(visible_mesh_entities.entities.iter().map(
|main_entity| {
let render_entity = match mapper.get(*main_entity) {
Ok(render_entity) => **render_entity,
Err(_) => Entity::PLACEHOLDER,
};
(render_entity, MainEntity::from(*main_entity))
},
));
if let Ok(render_auxiliary_entity) = aux_render_entity.get(*main_auxiliary_entity) {
for subview_index in 0..(cascade_config.bounds.len() as u32) {
let retained_view_entity = RetainedViewEntity {
main_entity: MainEntity::from(main_entity),
auxiliary_entity: MainEntity::from(*main_auxiliary_entity),
render_auxiliary_entity,
subview_index,
};
all_cascades_seen.insert(retained_view_entity);

existing_shadow_map_visible_entities
.subviews
.entry(retained_view_entity)
.or_default();

// Extract the visible CPU culled entities to the list.
let extracted_entities =
&mut existing_extracted_shadow_map_visible_entities
.subviews
.entry(retained_view_entity)
.or_default()
.classes
.entry(TypeId::of::<Mesh3d>())
.or_default()
.entities;
extracted_entities.clear();
let Some(visible_mesh_entities) =
visible_mesh_entities_list.get(subview_index as usize)
else {
continue;
};
extracted_entities.extend(visible_mesh_entities.entities.iter().map(
|main_entity| {
let render_entity = match mapper.get(*main_entity) {
Ok(render_entity) => **render_entity,
Err(_) => Entity::PLACEHOLDER,
};
(render_entity, MainEntity::from(*main_entity))
},
));
}
}
}

Expand Down Expand Up @@ -1526,7 +1533,7 @@ pub fn prepare_lights(
// Point light shadow maps are shared across all cameras,
// so the retained view entity must not include the camera.
let retained_view_entity =
RetainedViewEntity::new(*light_main_entity, None, face_index as u32);
RetainedViewEntity::new(*light_main_entity, None, None, face_index as u32);

commands.entity(view_light_entity).insert((
ShadowView {
Expand Down Expand Up @@ -1584,7 +1591,7 @@ pub fn prepare_lights(
{
let view_light_entity = point_and_spot_light_view_entities.0[face_index];
let retained_view_entity =
RetainedViewEntity::new(*light_main_entity, None, face_index as u32);
RetainedViewEntity::new(*light_main_entity, None, None, face_index as u32);
commands.entity(view_light_entity).insert((
ExtractedView {
retained_view_entity,
Expand All @@ -1610,7 +1617,7 @@ pub fn prepare_lights(
// already created the views in order to clear out old data.
for face_index in 0..6 {
let retained_view_entity =
RetainedViewEntity::new(*light_main_entity, None, face_index);
RetainedViewEntity::new(*light_main_entity, None, None, face_index);
shadow_render_phases.prepare_for_new_frame(
retained_view_entity,
gpu_preprocessing_support.max_supported_mode,
Expand Down Expand Up @@ -1644,7 +1651,7 @@ pub fn prepare_lights(

// Spot light shadow maps are shared across all cameras,
// so the retained view entity must not include the camera.
let retained_view_entity = RetainedViewEntity::new(*light_main_entity, None, 0);
let retained_view_entity = RetainedViewEntity::new(*light_main_entity, None, None, 0);

if point_and_spot_light_view_entities.0.is_empty() {
let spot_world_from_view = spot_light_world_from_view(&light.transform);
Expand Down Expand Up @@ -2021,6 +2028,7 @@ pub fn prepare_lights(
let retained_view_entity = RetainedViewEntity::new(
*light_main_entity,
Some(camera_main_entity.into()),
Some(entity),
cascade_index as u32,
);

Expand Down Expand Up @@ -2854,6 +2862,7 @@ fn get_shadow_map_visible_entities<'w, 's: 'w>(
let retained_view_entity = RetainedViewEntity {
main_entity: extracted_view_light.retained_view_entity.main_entity,
auxiliary_entity: MainEntity::from(Entity::PLACEHOLDER),
render_auxiliary_entity: Entity::PLACEHOLDER,
subview_index: *face_index as u32,
};
shadow_map_visible_entities_query
Expand All @@ -2870,6 +2879,7 @@ fn get_shadow_map_visible_entities<'w, 's: 'w>(
let retained_view_entity = RetainedViewEntity {
main_entity: extracted_view_light.retained_view_entity.main_entity,
auxiliary_entity: MainEntity::from(Entity::PLACEHOLDER),
render_auxiliary_entity: Entity::PLACEHOLDER,
subview_index: 0,
};
shadow_map_visible_entities_query
Expand Down
10 changes: 7 additions & 3 deletions crates/bevy_pbr/src/render/mesh_preprocess.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@
position_world_to_prev_ndc, position_world_to_prev_view, prev_view_z_to_depth_ndc
}
#import bevy_render::maths
#import bevy_render::view::View
#import bevy_render::view::{
View, VIEW_FLAGS_HAS_USABLE_PRIMARY_WORLD_POSITION
}

// Information about each mesh instance needed to cull it on GPU.
//
Expand Down Expand Up @@ -211,7 +213,9 @@ fn main(@builtin(global_invocation_id) global_invocation_id: vec3<u32>) {
let visibility_buffer_array_len = arrayLength(&visibility_ranges);
let visibility_buffer_index =
current_input[input_index].flags & MESH_FLAGS_VISIBILITY_RANGE_INDEX_BITS;
if (visibility_buffer_index < visibility_buffer_array_len) {
if (visibility_buffer_index < visibility_buffer_array_len
&& (view.flags & VIEW_FLAGS_HAS_USABLE_PRIMARY_WORLD_POSITION) != 0u)
{
let lod_range = visibility_ranges[visibility_buffer_index];

// If we're using the AABB as the mesh center, determine its world space position.
Expand All @@ -224,7 +228,7 @@ fn main(@builtin(global_invocation_id) global_invocation_id: vec3<u32>) {
world_pos = world_from_local[3].xyz;
}

let camera_distance = length(position_world_to_view(world_pos));
let camera_distance = length(view.primary_world_position - world_pos);
// `x` is the minimum range; `w` is the largest range.
if (camera_distance < lod_range.x || camera_distance >= lod_range.w) {
return;
Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_pbr/src/transmission/phase.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ pub fn extract_transmissive_camera_phases(
}

// This is the main camera, so use the first subview index (0).
let retained_view_entity = RetainedViewEntity::new(main_entity.into(), None, 0);
let retained_view_entity = RetainedViewEntity::new(main_entity.into(), None, None, 0);

transmissive_3d_phases.prepare_for_new_frame(retained_view_entity);
live_entities.insert(retained_view_entity);
Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_pbr/src/wireframe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1268,7 +1268,7 @@ fn extract_wireframe_3d_camera(
GpuPreprocessingMode::PreprocessingOnly
});

let retained_view_entity = RetainedViewEntity::new(main_entity.into(), None, 0);
let retained_view_entity = RetainedViewEntity::new(main_entity.into(), None, None, 0);
wireframe_3d_phases.prepare_for_new_frame(retained_view_entity, gpu_preprocessing_mode);
live_entities.insert(retained_view_entity);
}
Expand Down
7 changes: 6 additions & 1 deletion crates/bevy_render/src/camera.rs
Original file line number Diff line number Diff line change
Expand Up @@ -640,7 +640,12 @@ pub fn extract_cameras(
compositing_space: compositing_space.copied(),
},
ExtractedView {
retained_view_entity: RetainedViewEntity::new(main_entity.into(), None, 0),
retained_view_entity: RetainedViewEntity::new(
main_entity.into(),
None,
None,
0,
),
clip_from_view: camera.clip_from_view(),
world_from_view: *transform,
clip_from_world: None,
Expand Down
49 changes: 47 additions & 2 deletions crates/bevy_render/src/view/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,12 @@ pub struct RetainedViewEntity {
/// If not present, this will be `MainEntity(Entity::PLACEHOLDER)`.
pub auxiliary_entity: MainEntity,

/// The render entity corresponding to the `auxiliary_entity`.
///
/// This is used to get the auxiliary entity's world position
/// for visibility range culling calculations.
pub render_auxiliary_entity: Entity,

/// The index of the view corresponding to the entity.
///
/// For example, for point lights that cast shadows, this is the index of
Expand All @@ -297,18 +303,20 @@ pub struct RetainedViewEntity {

impl RetainedViewEntity {
/// Creates a new [`RetainedViewEntity`] from the given main world entity,
/// auxiliary main world entity, and subview index.
/// auxiliary main world entity, auxiliary render world entity, and subview index.
///
/// See [`RetainedViewEntity::subview_index`] for an explanation of what
/// `auxiliary_entity` and `subview_index` are.
/// `auxiliary_entity`, `render_auxiliary_entity` and `subview_index` are.
pub fn new(
main_entity: MainEntity,
auxiliary_entity: Option<MainEntity>,
render_auxiliary_entity: Option<Entity>,
subview_index: u32,
) -> Self {
Self {
main_entity,
auxiliary_entity: auxiliary_entity.unwrap_or(Entity::PLACEHOLDER.into()),
render_auxiliary_entity: render_auxiliary_entity.unwrap_or(Entity::PLACEHOLDER),
subview_index,
}
}
Expand Down Expand Up @@ -654,6 +662,27 @@ pub struct ViewUniform {
pub color_grading: ColorGradingUniform,
pub mip_bias: f32,
pub frame_count: u32,
/// The world position of a camera view used for visibility range culling.
///
/// This is useful for directional shadow views, where visibility range culling should
/// be executed in relation to its non-shadow camera's world position.
///
/// If this `ViewUniform` already represents a camera view or has no associated camera view,
/// this field will be set to `world_position`.
pub primary_world_position: Vec3,
/// Flags associated with this View.
pub flags: u32,
}

// NOTE: These must match the bit flags in bevy_pbr/src/view/view.wgsl!
bitflags::bitflags! {
/// Various flags and tightly-packed values on a View.
#[repr(transparent)]
pub struct ViewFlags: u32 {
/// Whether the `primary_world_position` of this `ViewUniform` can be used
/// for visibility range cullling.
const USABLE_PRIMARY_WORLD_POSITION = 1 << 0;
}
}

#[derive(Resource)]
Expand Down Expand Up @@ -997,6 +1026,7 @@ pub fn prepare_view_uniforms(
Option<&MipBias>,
Option<&MainPassResolutionOverride>,
)>,
primary_view: Query<&ExtractedView, With<ExtractedCamera>>,
frame_count: Res<FrameCount>,
) {
let view_iter = views.iter();
Expand Down Expand Up @@ -1049,6 +1079,19 @@ pub fn prepare_view_uniforms(
.map(|frustum| frustum.half_spaces.map(|h| h.normal_d()))
.unwrap_or([Vec4::ZERO; 6]);

let mut view_flags = ViewFlags::empty();
let primary_world_position = if let Ok(primary_extracted_view) =
primary_view.get(extracted_view.retained_view_entity.render_auxiliary_entity)
{
view_flags |= ViewFlags::USABLE_PRIMARY_WORLD_POSITION;
primary_extracted_view.world_from_view.translation()
} else {
if extracted_camera.is_some() {
view_flags |= ViewFlags::USABLE_PRIMARY_WORLD_POSITION;
}
extracted_view.world_from_view.translation()
};

let view_uniforms = ViewUniformOffset {
offset: writer.write(&ViewUniform {
clip_from_world,
Expand All @@ -1068,6 +1111,8 @@ pub fn prepare_view_uniforms(
color_grading: extracted_view.color_grading.clone().into(),
mip_bias: mip_bias.unwrap_or(&MipBias(0.0)).0,
frame_count: frame_count.0,
primary_world_position,
flags: view_flags.bits(),
}),
};

Expand Down
4 changes: 4 additions & 0 deletions crates/bevy_render/src/view/view.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,12 @@ struct View {
color_grading: ColorGrading,
mip_bias: f32,
frame_count: u32,
primary_world_position: vec3<f32>,
flags: u32,
};

const VIEW_FLAGS_HAS_USABLE_PRIMARY_WORLD_POSITION: u32 = 1u << 0u;

/// World space:
/// +y is up

Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_sprite_render/src/mesh2d/wireframe2d.rs
Original file line number Diff line number Diff line change
Expand Up @@ -662,7 +662,7 @@ fn extract_wireframe_2d_camera(
if !camera.is_active {
continue;
}
let retained_view_entity = RetainedViewEntity::new(main_entity.into(), None, 0);
let retained_view_entity = RetainedViewEntity::new(main_entity.into(), None, None, 0);
wireframe_2d_phases.prepare_for_new_frame(retained_view_entity, GpuPreprocessingMode::None);
live_entities.insert(retained_view_entity);
}
Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_ui_render/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -803,7 +803,7 @@ pub fn extract_ui_camera_view(
// We use `UI_CAMERA_SUBVIEW` here so as not to conflict with the
// main 3D or 2D camera, which will have subview index 0.
let retained_view_entity =
RetainedViewEntity::new(main_entity.into(), None, UI_CAMERA_SUBVIEW);
RetainedViewEntity::new(main_entity.into(), None, None, UI_CAMERA_SUBVIEW);
// Creates the UI view.
let ui_camera_view = commands
.spawn((
Expand Down
2 changes: 1 addition & 1 deletion examples/shader_advanced/custom_render_phase.rs
Original file line number Diff line number Diff line change
Expand Up @@ -508,7 +508,7 @@ fn extract_camera_phases(
continue;
}
// This is the main camera, so we use the first subview index (0)
let retained_view_entity = RetainedViewEntity::new(main_entity.into(), None, 0);
let retained_view_entity = RetainedViewEntity::new(main_entity.into(), None, None, 0);

stencil_phases.prepare_for_new_frame(retained_view_entity);
live_entities.insert(retained_view_entity);
Expand Down