mirror of
https://github.com/bevyengine/bevy
synced 2025-02-16 14:08:32 +00:00
Meshlet prep (#11442)
# Objective - Prep for https://github.com/bevyengine/bevy/pull/10164 - Make deferred_lighting_pass_id a ColorAttachment - Correctly extract shadow view frusta so that the view uniforms get populated - Make some needed things public - Misc formatting
This commit is contained in:
parent
2165793ff0
commit
a796d53a05
14 changed files with 75 additions and 45 deletions
|
@ -805,7 +805,7 @@ pub fn prepare_prepass_textures(
|
|||
.clone()
|
||||
});
|
||||
|
||||
let deferred_lighting_pass_id_texture = deferred_prepass.then(|| {
|
||||
let cached_deferred_lighting_pass_id_texture = deferred_prepass.then(|| {
|
||||
deferred_lighting_id_textures
|
||||
.entry(camera.target.clone())
|
||||
.or_insert_with(|| {
|
||||
|
@ -836,7 +836,8 @@ pub fn prepare_prepass_textures(
|
|||
motion_vectors: cached_motion_vectors_texture
|
||||
.map(|t| ColorAttachment::new(t, None, Color::BLACK)),
|
||||
deferred: cached_deferred_texture.map(|t| ColorAttachment::new(t, None, Color::BLACK)),
|
||||
deferred_lighting_pass_id: deferred_lighting_pass_id_texture,
|
||||
deferred_lighting_pass_id: cached_deferred_lighting_pass_id_texture
|
||||
.map(|t| ColorAttachment::new(t, None, Color::BLACK)),
|
||||
size,
|
||||
});
|
||||
}
|
||||
|
|
|
@ -94,7 +94,7 @@ impl ViewNode for CopyDeferredLightingIdNode {
|
|||
let bind_group = render_context.render_device().create_bind_group(
|
||||
"copy_deferred_lighting_id_bind_group",
|
||||
©_deferred_lighting_id_pipeline.layout,
|
||||
&BindGroupEntries::single(&deferred_lighting_pass_id_texture.default_view),
|
||||
&BindGroupEntries::single(&deferred_lighting_pass_id_texture.texture.default_view),
|
||||
);
|
||||
|
||||
let mut render_pass = render_context.begin_tracked_render_pass(RenderPassDescriptor {
|
||||
|
|
|
@ -5,10 +5,9 @@ use bevy_render::render_graph::ViewNode;
|
|||
use bevy_render::render_resource::StoreOp;
|
||||
use bevy_render::{
|
||||
camera::ExtractedCamera,
|
||||
prelude::Color,
|
||||
render_graph::{NodeRunError, RenderGraphContext},
|
||||
render_phase::RenderPhase,
|
||||
render_resource::{LoadOp, Operations, RenderPassColorAttachment, RenderPassDescriptor},
|
||||
render_resource::RenderPassDescriptor,
|
||||
renderer::RenderContext,
|
||||
view::ViewDepthTexture,
|
||||
};
|
||||
|
@ -83,11 +82,11 @@ impl ViewNode for DeferredGBufferPrepassNode {
|
|||
.map(|deferred_texture| {
|
||||
#[cfg(all(feature = "webgl", target_arch = "wasm32"))]
|
||||
{
|
||||
RenderPassColorAttachment {
|
||||
bevy_render::render_resource::RenderPassColorAttachment {
|
||||
view: &deferred_texture.texture.default_view,
|
||||
resolve_target: None,
|
||||
ops: Operations {
|
||||
load: LoadOp::Load,
|
||||
ops: bevy_render::render_resource::Operations {
|
||||
load: bevy_render::render_resource::LoadOp::Load,
|
||||
store: StoreOp::Store,
|
||||
},
|
||||
}
|
||||
|
@ -101,14 +100,7 @@ impl ViewNode for DeferredGBufferPrepassNode {
|
|||
view_prepass_textures
|
||||
.deferred_lighting_pass_id
|
||||
.as_ref()
|
||||
.map(|deferred_lighting_pass_id| RenderPassColorAttachment {
|
||||
view: &deferred_lighting_pass_id.default_view,
|
||||
resolve_target: None,
|
||||
ops: Operations {
|
||||
load: LoadOp::Clear(Color::BLACK.into()),
|
||||
store: StoreOp::Store,
|
||||
},
|
||||
}),
|
||||
.map(|deferred_lighting_pass_id| deferred_lighting_pass_id.get_attachment()),
|
||||
);
|
||||
|
||||
if color_attachments.iter().all(Option::is_none) {
|
||||
|
|
|
@ -34,7 +34,7 @@ use bevy_reflect::Reflect;
|
|||
use bevy_render::{
|
||||
render_phase::{CachedRenderPipelinePhaseItem, DrawFunctionId, PhaseItem},
|
||||
render_resource::{CachedRenderPipelineId, Extent3d, TextureFormat, TextureView},
|
||||
texture::{CachedTexture, ColorAttachment},
|
||||
texture::ColorAttachment,
|
||||
};
|
||||
use bevy_utils::{nonmax::NonMaxU32, FloatOrd};
|
||||
|
||||
|
@ -78,7 +78,7 @@ pub struct ViewPrepassTextures {
|
|||
pub deferred: Option<ColorAttachment>,
|
||||
/// A texture that specifies the deferred lighting pass id for a material.
|
||||
/// Exists only if [`DeferredPrepass`] is added to the `ViewTarget`
|
||||
pub deferred_lighting_pass_id: Option<CachedTexture>,
|
||||
pub deferred_lighting_pass_id: Option<ColorAttachment>,
|
||||
/// The size of the textures.
|
||||
pub size: Extent3d,
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
// Creates the deferred gbuffer from a PbrInput.
|
||||
fn deferred_gbuffer_from_pbr_input(in: PbrInput) -> vec4<u32> {
|
||||
// Only monochrome occlusion supported. May not be worth including at all.
|
||||
// Some models have baked occlusion, GLTF only supports monochrome.
|
||||
// Some models have baked occlusion, GLTF only supports monochrome.
|
||||
// Real time occlusion is applied in the deferred lighting pass.
|
||||
// Deriving luminance via Rec. 709. coefficients
|
||||
// https://en.wikipedia.org/wiki/Rec._709
|
||||
|
@ -27,7 +27,7 @@ fn deferred_gbuffer_from_pbr_input(in: PbrInput) -> vec4<u32> {
|
|||
var props = deferred_types::pack_unorm3x4_plus_unorm_20_(vec4(
|
||||
in.material.reflectance,
|
||||
in.material.metallic,
|
||||
diffuse_occlusion,
|
||||
diffuse_occlusion,
|
||||
in.frag_coord.z));
|
||||
#else
|
||||
var props = deferred_types::pack_unorm4x8_(vec4(
|
||||
|
@ -79,7 +79,7 @@ fn pbr_input_from_deferred_gbuffer(frag_coord: vec4<f32>, gbuffer: vec4<u32>) ->
|
|||
#ifdef WEBGL2 // More crunched for webgl so we can also fit depth.
|
||||
let props = deferred_types::unpack_unorm3x4_plus_unorm_20_(gbuffer.b);
|
||||
// Bias to 0.5 since that's the value for almost all materials.
|
||||
pbr.material.reflectance = saturate(props.r - 0.03333333333);
|
||||
pbr.material.reflectance = saturate(props.r - 0.03333333333);
|
||||
#else
|
||||
let props = deferred_types::unpack_unorm4x8_(gbuffer.b);
|
||||
pbr.material.reflectance = props.r;
|
||||
|
@ -92,9 +92,9 @@ fn pbr_input_from_deferred_gbuffer(frag_coord: vec4<f32>, gbuffer: vec4<u32>) ->
|
|||
let world_position = vec4(position_ndc_to_world(frag_coord_to_ndc(frag_coord)), 1.0);
|
||||
let is_orthographic = view.projection[3].w == 1.0;
|
||||
let V = pbr_functions::calculate_view(world_position, is_orthographic);
|
||||
|
||||
|
||||
pbr.frag_coord = frag_coord;
|
||||
pbr.world_normal = N;
|
||||
pbr.world_normal = N;
|
||||
pbr.world_position = world_position;
|
||||
pbr.N = N;
|
||||
pbr.V = V;
|
||||
|
|
|
@ -639,8 +639,8 @@ pub fn prepare_previous_view_projection_uniforms(
|
|||
|
||||
#[derive(Default, Resource)]
|
||||
pub struct PrepassViewBindGroup {
|
||||
motion_vectors: Option<BindGroup>,
|
||||
no_motion_vectors: Option<BindGroup>,
|
||||
pub motion_vectors: Option<BindGroup>,
|
||||
pub no_motion_vectors: Option<BindGroup>,
|
||||
}
|
||||
|
||||
pub fn prepare_prepass_view_bind_group<M: Material>(
|
||||
|
|
|
@ -149,7 +149,7 @@ fn fragment(in: VertexOutput) -> FragmentOutput {
|
|||
#ifdef DEFERRED_PREPASS
|
||||
// There isn't any material info available for this default prepass shader so we are just writing
|
||||
// emissive magenta out to the deferred gbuffer to be rendered by the first deferred lighting pass layer.
|
||||
// The is here so if the default prepass fragment is used for deferred magenta will be rendered, and also
|
||||
// This is here so if the default prepass fragment is used for deferred magenta will be rendered, and also
|
||||
// as an example to show that a user could write to the deferred gbuffer if they were to start from this shader.
|
||||
out.deferred = vec4(0u, bevy_pbr::rgb9e5::vec3_to_rgb9e5_(vec3(1.0, 0.0, 1.0)), 0u, 0u);
|
||||
out.deferred_lighting_pass_id = 1u;
|
||||
|
|
|
@ -5,6 +5,7 @@ use bevy_render::{
|
|||
camera::Camera,
|
||||
color::Color,
|
||||
mesh::Mesh,
|
||||
primitives::{CascadesFrusta, CubemapFrusta, Frustum},
|
||||
render_asset::RenderAssets,
|
||||
render_graph::{Node, NodeRunError, RenderGraphContext},
|
||||
render_phase::*,
|
||||
|
@ -48,6 +49,7 @@ pub struct ExtractedDirectionalLight {
|
|||
shadow_normal_bias: f32,
|
||||
cascade_shadow_config: CascadeShadowConfig,
|
||||
cascades: EntityHashMap<Entity, Vec<Cascade>>,
|
||||
frusta: EntityHashMap<Entity, Vec<Frustum>>,
|
||||
render_layers: RenderLayers,
|
||||
}
|
||||
|
||||
|
@ -296,6 +298,7 @@ pub fn extract_lights(
|
|||
&CubemapVisibleEntities,
|
||||
&GlobalTransform,
|
||||
&ViewVisibility,
|
||||
&CubemapFrusta,
|
||||
)>,
|
||||
>,
|
||||
spot_lights: Extract<
|
||||
|
@ -304,6 +307,7 @@ pub fn extract_lights(
|
|||
&VisibleEntities,
|
||||
&GlobalTransform,
|
||||
&ViewVisibility,
|
||||
&Frustum,
|
||||
)>,
|
||||
>,
|
||||
directional_lights: Extract<
|
||||
|
@ -314,6 +318,7 @@ pub fn extract_lights(
|
|||
&CascadesVisibleEntities,
|
||||
&Cascades,
|
||||
&CascadeShadowConfig,
|
||||
&CascadesFrusta,
|
||||
&GlobalTransform,
|
||||
&ViewVisibility,
|
||||
Option<&RenderLayers>,
|
||||
|
@ -343,7 +348,7 @@ pub fn extract_lights(
|
|||
|
||||
let mut point_lights_values = Vec::with_capacity(*previous_point_lights_len);
|
||||
for entity in global_point_lights.iter().copied() {
|
||||
let Ok((point_light, cubemap_visible_entities, transform, view_visibility)) =
|
||||
let Ok((point_light, cubemap_visible_entities, transform, view_visibility, frusta)) =
|
||||
point_lights.get(entity)
|
||||
else {
|
||||
continue;
|
||||
|
@ -373,7 +378,11 @@ pub fn extract_lights(
|
|||
};
|
||||
point_lights_values.push((
|
||||
entity,
|
||||
(extracted_point_light, render_cubemap_visible_entities),
|
||||
(
|
||||
extracted_point_light,
|
||||
render_cubemap_visible_entities,
|
||||
(*frusta).clone(),
|
||||
),
|
||||
));
|
||||
}
|
||||
*previous_point_lights_len = point_lights_values.len();
|
||||
|
@ -381,7 +390,7 @@ pub fn extract_lights(
|
|||
|
||||
let mut spot_lights_values = Vec::with_capacity(*previous_spot_lights_len);
|
||||
for entity in global_point_lights.iter().copied() {
|
||||
if let Ok((spot_light, visible_entities, transform, view_visibility)) =
|
||||
if let Ok((spot_light, visible_entities, transform, view_visibility, frustum)) =
|
||||
spot_lights.get(entity)
|
||||
{
|
||||
if !view_visibility.get() {
|
||||
|
@ -417,6 +426,7 @@ pub fn extract_lights(
|
|||
spot_light_angles: Some((spot_light.inner_angle, spot_light.outer_angle)),
|
||||
},
|
||||
render_visible_entities,
|
||||
*frustum,
|
||||
),
|
||||
));
|
||||
}
|
||||
|
@ -430,6 +440,7 @@ pub fn extract_lights(
|
|||
visible_entities,
|
||||
cascades,
|
||||
cascade_config,
|
||||
frusta,
|
||||
transform,
|
||||
view_visibility,
|
||||
maybe_layers,
|
||||
|
@ -452,6 +463,7 @@ pub fn extract_lights(
|
|||
shadow_normal_bias: directional_light.shadow_normal_bias * std::f32::consts::SQRT_2,
|
||||
cascade_shadow_config: cascade_config.clone(),
|
||||
cascades: cascades.cascades.clone(),
|
||||
frusta: frusta.frusta.clone(),
|
||||
render_layers: maybe_layers.copied().unwrap_or_default(),
|
||||
},
|
||||
render_visible_entities,
|
||||
|
@ -656,7 +668,11 @@ pub fn prepare_lights(
|
|||
directional_light_shadow_map: Res<DirectionalLightShadowMap>,
|
||||
mut max_directional_lights_warning_emitted: Local<bool>,
|
||||
mut max_cascades_per_light_warning_emitted: Local<bool>,
|
||||
point_lights: Query<(Entity, &ExtractedPointLight)>,
|
||||
point_lights: Query<(
|
||||
Entity,
|
||||
&ExtractedPointLight,
|
||||
AnyOf<(&CubemapFrusta, &Frustum)>,
|
||||
)>,
|
||||
directional_lights: Query<(Entity, &ExtractedDirectionalLight)>,
|
||||
) {
|
||||
let views_iter = views.iter();
|
||||
|
@ -733,7 +749,7 @@ pub fn prepare_lights(
|
|||
|
||||
let spot_light_shadow_maps_count = point_lights
|
||||
.iter()
|
||||
.filter(|(_, light)| light.shadows_enabled && light.spot_light_angles.is_some())
|
||||
.filter(|(_, light, _)| light.shadows_enabled && light.spot_light_angles.is_some())
|
||||
.count()
|
||||
.min(max_texture_array_layers - directional_shadow_enabled_count * MAX_CASCADES_PER_LIGHT);
|
||||
|
||||
|
@ -742,7 +758,7 @@ pub fn prepare_lights(
|
|||
// - then those with shadows enabled first, so that the index can be used to render at most `point_light_shadow_maps_count`
|
||||
// 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)| {
|
||||
point_lights.sort_by(|(entity_1, light_1, _), (entity_2, light_2, _)| {
|
||||
point_light_order(
|
||||
(
|
||||
entity_1,
|
||||
|
@ -775,7 +791,7 @@ pub fn prepare_lights(
|
|||
}
|
||||
|
||||
let mut gpu_point_lights = Vec::new();
|
||||
for (index, &(entity, light)) in point_lights.iter().enumerate() {
|
||||
for (index, &(entity, light, _)) in point_lights.iter().enumerate() {
|
||||
let mut flags = PointLightFlags::NONE;
|
||||
|
||||
// Lights are sorted, shadow enabled lights are first
|
||||
|
@ -952,11 +968,11 @@ pub fn prepare_lights(
|
|||
};
|
||||
|
||||
// TODO: this should select lights based on relevance to the view instead of the first ones that show up in a query
|
||||
for &(light_entity, light) in point_lights
|
||||
for &(light_entity, light, (point_light_frusta, _)) in point_lights
|
||||
.iter()
|
||||
// Lights are sorted, shadow enabled lights are first
|
||||
.take(point_light_shadow_maps_count)
|
||||
.filter(|(_, light)| light.shadows_enabled)
|
||||
.filter(|(_, light, _)| light.shadows_enabled)
|
||||
{
|
||||
let light_index = *global_light_meta
|
||||
.entity_to_index
|
||||
|
@ -967,7 +983,11 @@ pub fn prepare_lights(
|
|||
// and ignore rotation because we want the shadow map projections to align with the axes
|
||||
let view_translation = GlobalTransform::from_translation(light.transform.translation());
|
||||
|
||||
for (face_index, view_rotation) in cube_face_rotations.iter().enumerate() {
|
||||
for (face_index, (view_rotation, frustum)) in cube_face_rotations
|
||||
.iter()
|
||||
.zip(&point_light_frusta.unwrap().frusta)
|
||||
.enumerate()
|
||||
{
|
||||
let depth_texture_view =
|
||||
point_light_depth_texture
|
||||
.texture
|
||||
|
@ -1005,6 +1025,7 @@ pub fn prepare_lights(
|
|||
hdr: false,
|
||||
color_grading: Default::default(),
|
||||
},
|
||||
*frustum,
|
||||
RenderPhase::<Shadow>::default(),
|
||||
LightEntity::Point {
|
||||
light_entity,
|
||||
|
@ -1017,7 +1038,7 @@ pub fn prepare_lights(
|
|||
}
|
||||
|
||||
// spot lights
|
||||
for (light_index, &(light_entity, light)) in point_lights
|
||||
for (light_index, &(light_entity, light, (_, spot_light_frustum))) in point_lights
|
||||
.iter()
|
||||
.skip(point_light_count)
|
||||
.take(spot_light_shadow_maps_count)
|
||||
|
@ -1063,6 +1084,7 @@ pub fn prepare_lights(
|
|||
hdr: false,
|
||||
color_grading: Default::default(),
|
||||
},
|
||||
*spot_light_frustum.unwrap(),
|
||||
RenderPhase::<Shadow>::default(),
|
||||
LightEntity::Spot { light_entity },
|
||||
))
|
||||
|
@ -1078,12 +1100,20 @@ pub fn prepare_lights(
|
|||
.enumerate()
|
||||
.take(directional_shadow_enabled_count)
|
||||
{
|
||||
for (cascade_index, (cascade, bound)) in light
|
||||
let cascades = light
|
||||
.cascades
|
||||
.get(&entity)
|
||||
.unwrap()
|
||||
.iter()
|
||||
.take(MAX_CASCADES_PER_LIGHT)
|
||||
.take(MAX_CASCADES_PER_LIGHT);
|
||||
let frusta = light
|
||||
.frusta
|
||||
.get(&entity)
|
||||
.unwrap()
|
||||
.iter()
|
||||
.take(MAX_CASCADES_PER_LIGHT);
|
||||
for (cascade_index, ((cascade, frusta), bound)) in cascades
|
||||
.zip(frusta)
|
||||
.zip(&light.cascade_shadow_config.bounds)
|
||||
.enumerate()
|
||||
{
|
||||
|
@ -1129,6 +1159,7 @@ pub fn prepare_lights(
|
|||
hdr: false,
|
||||
color_grading: Default::default(),
|
||||
},
|
||||
*frusta,
|
||||
RenderPhase::<Shadow>::default(),
|
||||
LightEntity::Directional {
|
||||
light_entity,
|
||||
|
|
|
@ -678,6 +678,13 @@ pub struct InnerMeshVertexBufferLayout {
|
|||
}
|
||||
|
||||
impl InnerMeshVertexBufferLayout {
|
||||
pub fn new(attribute_ids: Vec<MeshVertexAttributeId>, layout: VertexBufferLayout) -> Self {
|
||||
Self {
|
||||
attribute_ids,
|
||||
layout,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn contains(&self, attribute_id: impl Into<MeshVertexAttributeId>) -> bool {
|
||||
self.attribute_ids.contains(&attribute_id.into())
|
||||
|
|
|
@ -303,7 +303,7 @@ impl Frustum {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Component, Debug, Default, Reflect)]
|
||||
#[derive(Component, Clone, Debug, Default, Reflect)]
|
||||
#[reflect(Component)]
|
||||
pub struct CubemapFrusta {
|
||||
#[reflect(ignore)]
|
||||
|
|
|
@ -32,7 +32,7 @@ pub use uniform_buffer::*;
|
|||
|
||||
// TODO: decide where re-exports should go
|
||||
pub use wgpu::{
|
||||
util::{BufferInitDescriptor, DrawIndexedIndirect},
|
||||
util::{BufferInitDescriptor, DrawIndexedIndirect, DrawIndirect},
|
||||
AdapterInfo as WgpuAdapterInfo, AddressMode, BindGroupDescriptor, BindGroupEntry,
|
||||
BindGroupLayoutDescriptor, BindGroupLayoutEntry, BindingResource, BindingType, BlendComponent,
|
||||
BlendFactor, BlendOperation, BlendState, BufferAddress, BufferAsyncError, BufferBinding,
|
||||
|
|
|
@ -457,7 +457,7 @@ struct MainTargetTextures {
|
|||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn prepare_view_targets(
|
||||
pub fn prepare_view_targets(
|
||||
mut commands: Commands,
|
||||
windows: Res<ExtractedWindows>,
|
||||
images: Res<RenderAssets<Image>>,
|
||||
|
|
|
@ -17,7 +17,6 @@ fn main() {
|
|||
DefaultPlugins,
|
||||
FrameTimeDiagnosticsPlugin,
|
||||
LogDiagnosticsPlugin::default(),
|
||||
bevy_internal::core_pipeline::experimental::taa::TemporalAntiAliasPlugin,
|
||||
))
|
||||
.add_systems(Startup, setup)
|
||||
.add_systems(Update, (light_sway, movement))
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
//! Update a scene from a glTF file, either by spawning the scene as a child of another entity,
|
||||
//! or by accessing the entities of the scene.
|
||||
|
||||
use bevy::prelude::*;
|
||||
use bevy::{pbr::DirectionalLightShadowMap, prelude::*};
|
||||
|
||||
fn main() {
|
||||
App::new()
|
||||
.insert_resource(bevy_internal::pbr::DirectionalLightShadowMap { size: 4096 })
|
||||
.insert_resource(DirectionalLightShadowMap { size: 4096 })
|
||||
.add_plugins(DefaultPlugins)
|
||||
.add_systems(Startup, setup)
|
||||
.add_systems(Update, move_scene_entities)
|
||||
|
|
Loading…
Add table
Reference in a new issue