wde_pbr/deferred/lights/
lights_binding.rs1use wde_logger::prelude::*;
2
3use bevy::{ecs::system::SystemParamItem, prelude::*};
4use wde_renderer::prelude::*;
5
6use crate::deferred::lights::*;
7
8pub const MAX_LIGHTS: usize = 64;
10
11pub(crate) struct LightsBindingPlugin;
12impl Plugin for LightsBindingPlugin {
13 fn build(&self, app: &mut App) {
14 app.add_plugins(RenderDataRegisterPlugin::<LightsData>::default());
16
17 app.get_sub_app_mut(RenderApp)
19 .unwrap()
20 .init_resource::<ExtractedLights>()
21 .add_systems(Extract, extract)
22 .add_systems(Render, update_lights_buffer.in_set(RenderSet::Prepare));
23 }
24}
25
26#[derive(Asset, Clone, TypePath, Default)]
27pub struct LightsData;
28impl LightsData {
29 pub const LIGHTS_BUFFER_IDX: u32 = 0;
30 pub const LIGHTS_BUFFER_STAGING_IDX: u32 = 1;
31}
32impl RenderData for LightsData {
33 type Params = ();
34
35 fn describe(_params: &mut SystemParamItem<Self::Params>, builder: &mut RenderDataBuilder) {
36 builder
37 .add_buffer(
38 Self::LIGHTS_BUFFER_IDX,
39 Buffer {
40 label: "lights-buffer-gpu".to_string(),
41 size: std::mem::size_of::<LightsStorageElement>() * MAX_LIGHTS,
42 usage: BufferUsage::STORAGE | BufferUsage::COPY_DST,
43 content: None
44 }
45 )
46 .add_buffer(
47 Self::LIGHTS_BUFFER_STAGING_IDX,
48 Buffer {
49 label: "lights-buffer-staging".to_string(),
50 size: std::mem::size_of::<LightsStorageElement>() * MAX_LIGHTS,
51 usage: BufferUsage::COPY_SRC | BufferUsage::COPY_DST,
52 content: None
53 }
54 );
55 }
56}
57
58#[derive(Resource, Default)]
59struct ExtractedLights {
60 pub directional_lights: Vec<DirectionalLight>,
61 pub point_lights: Vec<PointLight>,
62 pub spot_lights: Vec<SpotLight>
63}
64
65fn extract(
66 lights_directional: ExtractWorld<Query<&DirectionalLight>>,
67 lights_point: ExtractWorld<Query<&PointLight>>,
68 lights_spot: ExtractWorld<Query<&SpotLight>>,
69 mut extracted_lights: ResMut<ExtractedLights>
70) {
71 extracted_lights.directional_lights = lights_directional.iter().copied().collect();
73 extracted_lights.point_lights = lights_point.iter().copied().collect();
74 extracted_lights.spot_lights = lights_spot.iter().copied().collect();
75}
76
77fn update_lights_buffer(
78 lights_buffer: ResRenderData<LightsData>,
79 buffers: Res<RenderAssets<GpuBuffer>>,
80 render_instance: Res<RenderInstance>,
81 extracted_lights: Res<ExtractedLights>
82) {
83 let lights_buffer_cpu = match lights_buffer.iter().next() {
85 Some((_, buffer)) => match buffers.get(
86 &buffer
87 .get_buffer(LightsData::LIGHTS_BUFFER_STAGING_IDX)
88 .unwrap()
89 ) {
90 Some(lights_buffer) => lights_buffer,
91 None => return
92 },
93 None => return
94 };
95
96 let render_instance = render_instance.0.read().unwrap();
97 let mut offset = 0;
98 for light in extracted_lights.directional_lights.iter() {
99 let data = LightsStorageElement::from_directional(light);
100 lights_buffer_cpu.buffer.write(
101 &render_instance,
102 bytemuck::bytes_of(&data),
103 offset * std::mem::size_of::<LightsStorageElement>()
104 );
105 offset += 1;
106 }
107 for light in extracted_lights.point_lights.iter() {
108 let data = LightsStorageElement::from_point(light);
109 lights_buffer_cpu.buffer.write(
110 &render_instance,
111 bytemuck::bytes_of(&data),
112 offset * std::mem::size_of::<LightsStorageElement>()
113 );
114 offset += 1;
115 }
116 for light in extracted_lights.spot_lights.iter() {
117 let data = LightsStorageElement::from_spot(light);
118 lights_buffer_cpu.buffer.write(
119 &render_instance,
120 bytemuck::bytes_of(&data),
121 offset * std::mem::size_of::<LightsStorageElement>()
122 );
123 offset += 1;
124 }
125 if offset > MAX_LIGHTS {
126 warn!(
127 "Number of lights exceeded the maximum of {}. Some lights will be ignored in rendering.",
128 MAX_LIGHTS
129 );
130 }
131
132 let lights_buffer_gpu = match buffers.get(
134 &lights_buffer
135 .iter()
136 .next()
137 .unwrap()
138 .1
139 .get_buffer(LightsData::LIGHTS_BUFFER_IDX)
140 .unwrap()
141 ) {
142 Some(buffer) => buffer,
143 None => return
144 };
145 lights_buffer_gpu
146 .buffer
147 .copy_from_buffer(&render_instance, &lights_buffer_cpu.buffer);
148}