bevy_pbr/
contact_shadows.rs1use bevy_app::{App, Plugin};
4use bevy_derive::{Deref, DerefMut};
5use bevy_ecs::{
6 component::Component,
7 entity::Entity,
8 query::{QueryItem, With},
9 reflect::ReflectComponent,
10 resource::Resource,
11 schedule::IntoScheduleConfigs,
12 system::{Commands, Query, Res, ResMut},
13};
14use bevy_reflect::{std_traits::ReflectDefault, Reflect};
15use bevy_render::{
16 extract_component::{ExtractComponent, ExtractComponentPlugin},
17 render_resource::{DynamicUniformBuffer, ShaderType},
18 renderer::{RenderDevice, RenderQueue},
19 sync_component::SyncComponent,
20 view::ExtractedView,
21 GpuResourceAppExt, Render, RenderApp, RenderSystems,
22};
23
24pub struct ContactShadowsPlugin;
26
27#[derive(Clone, Copy, Component, Reflect)]
35#[reflect(Component, Default, Clone)]
36#[require(bevy_core_pipeline::prepass::DepthPrepass)]
37pub struct ContactShadows {
38 pub linear_steps: u32,
41 pub thickness: f32,
46 pub length: f32,
48}
49
50impl Default for ContactShadows {
51 fn default() -> Self {
52 Self {
53 linear_steps: 16,
54 thickness: 0.1,
55 length: 0.3,
56 }
57 }
58}
59
60#[derive(Clone, Copy, ShaderType, Default)]
62pub struct ContactShadowsUniform {
63 pub linear_steps: u32,
64 pub thickness: f32,
65 pub length: f32,
66 #[cfg(feature = "webgl")]
67 pub _padding: f32,
68}
69
70impl From<ContactShadows> for ContactShadowsUniform {
71 fn from(settings: ContactShadows) -> Self {
72 Self {
73 linear_steps: settings.linear_steps,
74 thickness: settings.thickness,
75 length: settings.length,
76 #[cfg(feature = "webgl")]
77 _padding: 0.0,
78 }
79 }
80}
81
82impl SyncComponent for ContactShadows {
83 type Target = (Self, ViewContactShadowsUniformOffset);
84}
85
86impl ExtractComponent for ContactShadows {
87 type QueryData = &'static ContactShadows;
88 type QueryFilter = ();
89 type Out = Self;
90
91 fn extract_component(settings: QueryItem<'_, '_, Self::QueryData>) -> Option<Self::Out> {
92 Some(*settings)
93 }
94}
95
96#[derive(Resource, Default)]
98pub struct ContactShadowsBuffer(pub DynamicUniformBuffer<ContactShadowsUniform>);
99
100impl Plugin for ContactShadowsPlugin {
101 fn build(&self, app: &mut App) {
102 app.register_type::<ContactShadows>()
103 .add_plugins(ExtractComponentPlugin::<ContactShadows>::default());
104
105 let Some(render_app) = app.get_sub_app_mut(RenderApp) else {
106 return;
107 };
108
109 render_app
110 .init_gpu_resource::<ContactShadowsBuffer>()
111 .add_systems(
112 Render,
113 prepare_contact_shadows_settings.in_set(RenderSystems::PrepareResources),
114 );
115 }
116}
117
118fn prepare_contact_shadows_settings(
119 mut commands: Commands,
120 views: Query<(Entity, &ContactShadows), With<ExtractedView>>,
121 mut contact_shadows_buffer: ResMut<ContactShadowsBuffer>,
122 render_device: Res<RenderDevice>,
123 render_queue: Res<RenderQueue>,
124) {
125 let Some(mut writer) =
126 contact_shadows_buffer
127 .0
128 .get_writer(views.iter().len(), &render_device, &render_queue)
129 else {
130 return;
131 };
132 for (entity, settings) in &views {
133 let uniform = ContactShadowsUniform::from(*settings);
134 let offset = writer.write(&uniform);
135 commands
136 .entity(entity)
137 .insert(ViewContactShadowsUniformOffset(offset));
138 }
139}
140
141#[derive(Component, Default, Deref, DerefMut)]
144pub struct ViewContactShadowsUniformOffset(pub u32);