1use super::physics::*;
2use crate::core::World;
3use crate::math::{Mat4, Vec3};
4use crate::renderer::{
5 components::{Camera, Material, Mesh, MeshRenderer},
6 Renderer,
7};
8use bytemuck;
9use wgpu;
10
11#[derive(Default)]
12pub struct RenderCache {
13 pub(crate) batches: std::collections::HashMap<BatchKey, BatchData>,
14 pub instances: Vec<crate::renderer::gpu_types::InstanceRaw>,
15 pub draw_items: Vec<DrawItem>,
16}
17
18thread_local! {
19 static RENDER_CACHE: std::cell::RefCell<RenderCache> = std::cell::RefCell::new(RenderCache::default());
20}
21
22pub fn clear_render_cache() {
23 RENDER_CACHE.with(|rc| {
24 let mut cache = rc.borrow_mut();
25 cache.batches.clear();
26 cache.instances.clear();
27 cache.draw_items.clear();
28 });
29}
30
31#[derive(Clone)]
32pub struct DrawItem {
33 vbuf: std::sync::Arc<wgpu::Buffer>,
34 vertex_count: u32,
35 bind_group: std::sync::Arc<wgpu::BindGroup>,
36 unlit: bool,
37 is_skybox: bool,
38 skeleton_bind_group: Option<std::sync::Arc<wgpu::BindGroup>>,
39 first_instance: u32,
40 instance_count: u32,
41}
42
43#[derive(Clone, PartialEq, Eq, Hash)]
44pub(crate) struct BatchKey {
45 vbuf_id: usize,
46 mat_id: usize,
47 skeleton_id: Option<usize>,
48}
49
50pub(crate) struct BatchData {
51 vbuf: std::sync::Arc<wgpu::Buffer>,
52 bind_group: std::sync::Arc<wgpu::BindGroup>,
53 vertex_count: u32,
54 unlit: bool,
55 is_skybox: bool,
56 skeleton_bind_group: Option<std::sync::Arc<wgpu::BindGroup>>,
57 instances: Vec<crate::renderer::gpu_types::InstanceRaw>,
58}
59
60#[tracing::instrument(skip_all, name = "render_system")]
64pub fn default_render_pass(
65 world: &mut World,
66 encoder: &mut wgpu::CommandEncoder,
67 view: &wgpu::TextureView,
68 renderer: &mut Renderer,
69) {
70 let aspect = if renderer.size.height > 0 {
71 renderer.size.width as f32 / renderer.size.height as f32
72 } else {
73 1.0
74 };
75 let mut proj = Mat4::perspective_rh(std::f32::consts::FRAC_PI_4, aspect, 0.1, 2000.0);
76 let mut view_mat = Mat4::from_translation(Vec3::ZERO);
77 let mut cam_pos = Vec3::ZERO;
78 let mut cam_forward = Vec3::new(0.0, 0.0, -1.0);
79
80 gpu_physics_submit_system(world, renderer);
85 gpu_physics_readback_system(world, renderer);
86
87 let cameras = world.borrow::<Camera>();
89 let transforms = world.borrow::<crate::physics::GlobalTransform>();
90 {
91 if let Some((active_cam, _)) = cameras.iter().next() {
94 if let (Some(cam), Some(trans)) = (cameras.get(active_cam), transforms.get(active_cam))
95 {
96 let (_, rot, pos) = trans.matrix.to_scale_rotation_translation();
97 proj = cam.get_projection(aspect);
98 view_mat = cam.get_view(pos);
99 cam_pos = pos;
100 cam_forward = rot * Vec3::new(0.0, 0.0, -1.0);
101 }
102 }
103 }
104
105 let unjittered_proj = proj;
107
108 if let Some(ref taa) = renderer.taa {
110 let jp = crate::renderer::taa::TaaState::get_jitter(taa.frame_index);
111 let jx = jp[0] * 2.0 / renderer.size.width as f32;
113 let jy = jp[1] * 2.0 / renderer.size.height as f32;
114 proj.z_axis.x -= jx;
117 proj.z_axis.y -= jy;
118 }
119
120 let view_proj = proj * view_mat; let unjittered_view_proj = unjittered_proj * view_mat; let mut sun_dir = gizmo_math::Vec3::new(0.0, -1.0, 0.0);
125 let mut sun_col = gizmo_math::Vec4::new(1.0, 1.0, 1.0, 1.0);
126 if let Some(q) = world.query::<(
127 &crate::renderer::components::DirectionalLight,
128 &crate::physics::GlobalTransform,
129 )>() {
130 for (_id, (light, transform)) in q.iter() {
131 if light.role == crate::renderer::components::LightRole::Sun {
132 let (_, rot, _) = transform.matrix.to_scale_rotation_translation();
133 sun_dir = rot
134 .mul_vec3(gizmo_math::Vec3::new(0.0, 0.0, -1.0))
135 .normalize();
136 sun_col = gizmo_math::Vec4::new(
137 light.color.x,
138 light.color.y,
139 light.color.z,
140 light.intensity,
141 );
142 break;
143 }
144 }
145 }
146
147 let cascade_splits = [10.0f32, 50.0, 200.0, 2000.0];
148 let cascade_vp = crate::renderer::directional_cascade_view_projs(
149 cam_pos,
150 cam_forward,
151 aspect,
152 std::f32::consts::FRAC_PI_4,
153 0.1,
154 &cascade_splits,
155 sun_dir,
156 crate::renderer::SHADOW_MAP_RES,
157 );
158 let light_view_projs: [[[f32; 4]; 4]; 4] = cascade_vp.map(|m| m.to_cols_array_2d());
159
160 let mut lights_data = [crate::renderer::gpu_types::LightData {
162 position: [0.0; 4],
163 color: [0.0; 4],
164 direction: [0.0, -1.0, 0.0, 0.0],
165 params: [0.0; 4],
166 }; 10];
167 let mut num_lights = 0;
168
169 if let Some(q) = world.query::<(
170 &crate::renderer::components::PointLight,
171 &crate::physics::GlobalTransform,
172 )>() {
173 for (_id, (light, transform)) in q.iter() {
174 if num_lights >= 10 {
175 break;
176 }
177 let (_, _, pos) = transform.matrix.to_scale_rotation_translation();
178 lights_data[num_lights as usize] = crate::renderer::gpu_types::LightData {
179 position: [pos.x, pos.y, pos.z, light.intensity],
180 color: [light.color.x, light.color.y, light.color.z, light.radius],
181 direction: [0.0, -1.0, 0.0, 0.0],
182 params: [0.0, 0.0, 0.0, 0.0], };
184 num_lights += 1;
185 }
186 }
187
188 if let Some(q) = world.query::<(
189 &crate::renderer::components::SpotLight,
190 &crate::physics::GlobalTransform,
191 )>() {
192 for (_id, (light, transform)) in q.iter() {
193 if num_lights >= 10 {
194 break;
195 }
196 let (_, rot, pos) = transform.matrix.to_scale_rotation_translation();
197 let dir = rot
198 .mul_vec3(gizmo_math::Vec3::new(0.0, 0.0, -1.0))
199 .normalize();
200 lights_data[num_lights as usize] = crate::renderer::gpu_types::LightData {
201 position: [pos.x, pos.y, pos.z, light.intensity],
202 color: [light.color.x, light.color.y, light.color.z, light.radius],
203 direction: [dir.x, dir.y, dir.z, light.inner_angle],
204 params: [light.outer_angle, 1.0, 0.0, 0.0], };
206 num_lights += 1;
207 }
208 }
209
210 let scene_uniform_data = crate::renderer::gpu_types::SceneUniforms {
211 view_proj: view_proj.to_cols_array_2d(),
212 camera_pos: [cam_pos.x, cam_pos.y, cam_pos.z, 1.0],
213 sun_direction: [sun_dir.x, sun_dir.y, sun_dir.z, 1.0],
214 sun_color: [sun_col.x, sun_col.y, sun_col.z, sun_col.w],
215 lights: lights_data,
216 light_view_proj: light_view_projs,
217 cascade_splits,
218 camera_forward: [cam_forward.x, cam_forward.y, cam_forward.z, 0.0],
219 cascade_params: [0.1, 1.0 / crate::renderer::SHADOW_MAP_RES as f32, 0.0, 0.0],
220 num_lights,
221 _pre_align_pad: [0; 3],
223 _align_pad: [0; 3],
224 _post_align_pad: 0,
225 _pad_scene: [0; 3],
226 shading_mode: 0,
227 };
228 renderer.queue.write_buffer(
229 &renderer.scene.global_uniform_buffer,
230 0,
231 bytemuck::cast_slice(&[scene_uniform_data]),
232 );
233 for i in 0..crate::renderer::CASCADE_COUNT {
234 renderer.queue.write_buffer(
235 &renderer.scene.shadow_cascade_uniform_buffers[i],
236 0,
237 bytemuck::bytes_of(&crate::renderer::gpu_types::ShadowVsUniform {
238 light_view_proj: light_view_projs[i],
239 }),
240 );
241 }
242
243 if let Some(ref mut taa) = renderer.taa {
245 let jp = crate::renderer::taa::TaaState::get_jitter(taa.frame_index);
246 let jx = jp[0] * 2.0 / renderer.size.width as f32;
247 let jy = jp[1] * 2.0 / renderer.size.height as f32;
248 let alpha = if taa.frame_index == 0 { 1.0f32 } else { 0.1f32 };
249 taa.update_params(&renderer.queue, [jx, jy], alpha);
250 taa.store_prev_vp(unjittered_view_proj.to_cols_array_2d());
251 }
252
253 let renderers = world.borrow::<MeshRenderer>();
256
257 let frustum = crate::math::Frustum::from_matrix(&unjittered_view_proj);
259
260 let draw_items = RENDER_CACHE.with(|rc| {
261 let mut cache = rc.borrow_mut();
262
263 for batch in cache.batches.values_mut() {
265 batch.instances.clear();
266 }
267 cache.instances.clear();
268 cache.draw_items.clear();
269
270 let pooled_storage = world.borrow::<gizmo_core::pool::Pooled>();
271
272 macro_rules! process_mesh {
273 ($e:expr, $mesh:expr, $trans:expr, $mat:expr, $skeleton:expr) => {
274 if renderers.get($e).is_none() {
275 continue;
276 }
277
278 if pooled_storage.get($e).is_some() {
280 continue;
281 }
282
283 let center_mat = Mat4::from_translation($mesh.center_offset);
284 let model = $trans.matrix * center_mat;
285
286 let local_cx = ($mesh.bounds.min.x + $mesh.bounds.max.x) * 0.5;
288 let local_cy = ($mesh.bounds.min.y + $mesh.bounds.max.y) * 0.5;
289 let local_cz = ($mesh.bounds.min.z + $mesh.bounds.max.z) * 0.5;
290 let world_c = model.transform_point3(Vec3::new(local_cx, local_cy, local_cz));
291 let hx = ($mesh.bounds.max.x - $mesh.bounds.min.x) * 0.5;
292 let hy = ($mesh.bounds.max.y - $mesh.bounds.min.y) * 0.5;
293 let hz = ($mesh.bounds.max.z - $mesh.bounds.min.z) * 0.5;
294 let local_r = (hx * hx + hy * hy + hz * hz).sqrt();
295 let sx = model.x_axis.truncate().length();
296 let sy = model.y_axis.truncate().length();
297 let sz = model.z_axis.truncate().length();
298 let world_r = local_r * sx.max(sy).max(sz);
299
300 if !frustum.intersects_sphere(world_c, world_r) {
301 continue;
302 }
303
304 let dist_to_cam = (world_c - cam_pos).length();
306 let use_lod1 = if !$mesh.lod_vbufs.is_empty() {
307 dist_to_cam > world_r * 15.0 } else {
309 false
310 };
311
312 let active_vbuf = if use_lod1 {
313 $mesh.lod_vbufs[0].clone()
314 } else {
315 $mesh.vbuf.clone()
316 };
317 let active_vertex_count = if use_lod1 {
318 $mesh.lod_vertex_counts[0]
319 } else {
320 $mesh.vertex_count
321 };
322
323 let instance_data = crate::renderer::gpu_types::InstanceRaw {
324 model: model.to_cols_array_2d(),
325 albedo_color: [$mat.albedo.x, $mat.albedo.y, $mat.albedo.z, $mat.albedo.w],
326 roughness: $mat.roughness,
327 metallic: $mat.metallic,
328 unlit: match $mat.material_type {
329 crate::renderer::components::MaterialType::Skybox => 2.0,
330 crate::renderer::components::MaterialType::Unlit => 1.0,
331 _ => 0.0,
332 },
333 _padding: 0.0,
334 };
335 let skel_bg = $skeleton.map(|s: &crate::renderer::components::Skeleton| s.bind_group.clone());
336
337 let key = BatchKey {
338 vbuf_id: std::sync::Arc::as_ptr(&active_vbuf) as usize,
339 mat_id: std::sync::Arc::as_ptr(&$mat.bind_group) as usize,
340 skeleton_id: skel_bg.as_ref().map(|bg| std::sync::Arc::as_ptr(bg) as usize),
341 };
342
343 let batch = cache.batches.entry(key).or_insert_with(|| BatchData {
344 vbuf: active_vbuf.clone(),
345 bind_group: $mat.bind_group.clone(),
346 vertex_count: active_vertex_count,
347 unlit: $mat.material_type == crate::renderer::components::MaterialType::Unlit
348 || $mat.material_type == crate::renderer::components::MaterialType::Skybox,
349 is_skybox: $mat.material_type == crate::renderer::components::MaterialType::Skybox,
350 skeleton_bind_group: skel_bg,
351 instances: Vec::new(),
352 });
353 batch.instances.push(instance_data);
354 };
355 }
356
357 let skeletons = world.borrow::<crate::renderer::components::Skeleton>();
358
359 if let Some(mut q) = world.query::<(&Mesh, &crate::physics::GlobalTransform, &Material)>() {
360 for (e, (mesh, trans, mat)) in q.iter_mut() {
361 process_mesh!(e, mesh, trans, mat, skeletons.get(e));
362 }
363 }
364
365 let meshes = world.try_get_resource::<gizmo_core::asset::Assets<Mesh>>().ok();
366 let materials = world.try_get_resource::<gizmo_core::asset::Assets<Material>>().ok();
367
368 if let (Some(meshes), Some(materials)) = (meshes, materials) {
369 if let Some(mut q) = world.query::<(&gizmo_core::asset::Handle<Mesh>, &crate::physics::GlobalTransform, &gizmo_core::asset::Handle<Material>)>() {
370 for (e, (h_mesh, trans, h_mat)) in q.iter_mut() {
371 if let (Some(mesh), Some(mat)) = (meshes.get(h_mesh), materials.get(h_mat)) {
372 process_mesh!(e, mesh, trans, mat, skeletons.get(e));
373 }
374 }
375 }
376 }
377
378 let mut local_instances: Vec<crate::renderer::gpu_types::InstanceRaw> = std::mem::take(&mut cache.instances);
379 let mut local_draw_items: Vec<DrawItem> = std::mem::take(&mut cache.draw_items);
380
381 for (_, batch) in cache.batches.iter() {
382 if batch.instances.is_empty() { continue; }
383 let first_instance = local_instances.len() as u32;
384 let instance_count = batch.instances.len() as u32;
385 local_instances.extend(&batch.instances);
386
387 local_draw_items.push(DrawItem {
388 vbuf: batch.vbuf.clone(),
389 vertex_count: batch.vertex_count,
390 bind_group: batch.bind_group.clone(),
391 unlit: batch.unlit,
392 is_skybox: batch.is_skybox,
393 skeleton_bind_group: batch.skeleton_bind_group.clone(),
394 first_instance,
395 instance_count,
396 });
397 }
398
399 cache.instances = local_instances;
400 cache.draw_items = local_draw_items;
401
402 let max_instances = renderer.scene.instance_capacity;
404 let instances_slice = if cache.instances.len() > max_instances {
405 &cache.instances[..max_instances]
406 } else {
407 &cache.instances
408 };
409
410 if !instances_slice.is_empty() {
411 renderer.queue.write_buffer(
412 &renderer.scene.instance_buffer,
413 0,
414 bytemuck::cast_slice(instances_slice),
415 );
416 }
417
418 cache.draw_items.clone()
420 });
421 if let Some(physics) = &renderer.gpu_physics {
424 physics.request_readback(encoder);
426
427 physics.compute_pass(encoder);
428 physics.debug_compute_pass(encoder);
429 physics.cull_pass(encoder, &renderer.scene.global_bind_group);
430 }
431
432 let fluid_pos = Vec3::new(0.0, 5.0, 0.0);
434 let dist_to_fluid = (cam_pos - fluid_pos).length();
435 let fluid_lod = if dist_to_fluid < 40.0 {
436 1.0
437 } else if dist_to_fluid < 80.0 {
438 0.5
439 } else if dist_to_fluid < 150.0 {
440 0.1
441 } else {
442 0.0
443 };
444
445 let dist_to_origin = cam_pos.length();
446 let particle_lod = if dist_to_origin < 50.0 {
447 1.0
448 } else if dist_to_origin < 100.0 {
449 0.5
450 } else if dist_to_origin < 200.0 {
451 0.1
452 } else {
453 0.0
454 };
455
456 if let Some(fluid) = &renderer.gpu_fluid {
458 let active_fluid = (fluid.num_particles as f32 * fluid_lod) as u32;
459 fluid.compute_pass(encoder, &renderer.queue, true, active_fluid);
460 }
461
462 if let Some(particles) = &renderer.gpu_particles {
464 let active_parts = (particles.max_particles as f32 * particle_lod) as u32;
465 let dt = world
466 .get_resource::<gizmo_core::time::Time>()
467 .map(|t| t.time_scale() * 0.016)
468 .unwrap_or(0.016);
469 particles.update_params(&renderer.queue, dt); particles.compute_pass(encoder, active_parts);
471 }
472
473 if let Some(ref mut def) = renderer.deferred {
477 def.resize(&renderer.device, renderer.size.width, renderer.size.height);
478 }
479 {
480 let w = renderer.size.width;
481 let h = renderer.size.height;
482 if let (Some(ssao), Some(def)) = (&mut renderer.ssao, &renderer.deferred) {
483 if ssao.width != w || ssao.height != h {
484 ssao.resize(&renderer.device, def, w, h);
485 }
486 }
487 if let (Some(ssr), Some(def)) = (&mut renderer.ssr, &renderer.deferred) {
488 if ssr.width != w || ssr.height != h {
489 ssr.resize(&renderer.device, def, &renderer.post.hdr_texture_view, w, h);
490 }
491 }
492 if let (Some(volumetric), Some(def)) = (&mut renderer.volumetric, &renderer.deferred) {
493 if volumetric.width != w || volumetric.height != h {
494 volumetric.resize(&renderer.device, def, w, h);
495 }
496 }
497 }
498 {
499 let w = renderer.size.width;
500 let h = renderer.size.height;
501 if let (Some(taa), Some(def)) = (&mut renderer.taa, &renderer.deferred) {
502 if taa.width != w || taa.height != h {
503 taa.resize(
504 &renderer.device,
505 &renderer.post.hdr_texture_view,
506 &def.world_position_view,
507 w,
508 h,
509 );
510 }
511 }
512 }
513
514 for i in 0..crate::renderer::CASCADE_COUNT {
516 let mut shadow_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
517 label: Some("Shadow Pass"),
518 color_attachments: &[],
519 depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
520 view: &renderer.scene.shadow_cascade_layer_views[i],
521 depth_ops: Some(wgpu::Operations {
522 load: wgpu::LoadOp::Clear(1.0),
523 store: wgpu::StoreOp::Store,
524 }),
525 stencil_ops: None,
526 }),
527 timestamp_writes: None,
528 occlusion_query_set: None,
529 });
530 shadow_pass.set_pipeline(&renderer.scene.shadow_pipeline);
531 shadow_pass.set_bind_group(0, &renderer.scene.shadow_pass_bind_groups[i], &[]);
532 shadow_pass.set_bind_group(2, &renderer.scene.instance_bind_group, &[]);
533 for item in &draw_items {
534 if item.unlit {
535 continue;
536 }
537 let skel_bg = item
538 .skeleton_bind_group
539 .as_ref()
540 .unwrap_or(&renderer.scene.dummy_skeleton_bind_group);
541 shadow_pass.set_bind_group(1, skel_bg, &[]);
542 shadow_pass.set_vertex_buffer(0, item.vbuf.slice(..));
543 shadow_pass.draw(
544 0..item.vertex_count,
545 item.first_instance..(item.first_instance + item.instance_count),
546 );
547 }
548 }
549
550 if let Some(ref def) = renderer.deferred {
552 let mut z_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
553 label: Some("Z-Prepass"),
554 color_attachments: &[], depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
556 view: &renderer.depth_texture_view,
557 depth_ops: Some(wgpu::Operations {
558 load: wgpu::LoadOp::Clear(1.0),
559 store: wgpu::StoreOp::Store,
560 }),
561 stencil_ops: None,
562 }),
563 timestamp_writes: None,
564 occlusion_query_set: None,
565 });
566 z_pass.set_pipeline(&def.z_prepass_pipeline);
567 z_pass.set_bind_group(0, &renderer.scene.global_bind_group, &[]);
568 z_pass.set_bind_group(2, &renderer.scene.shadow_bind_group, &[]);
569 z_pass.set_bind_group(4, &renderer.scene.instance_bind_group, &[]);
570 for item in &draw_items {
571 if item.unlit || item.is_skybox {
572 continue;
573 }
574 let skel_bg = item
575 .skeleton_bind_group
576 .as_ref()
577 .unwrap_or(&renderer.scene.dummy_skeleton_bind_group);
578 z_pass.set_bind_group(3, skel_bg, &[]);
579 z_pass.set_bind_group(1, &item.bind_group, &[]);
580 z_pass.set_vertex_buffer(0, item.vbuf.slice(..));
581 z_pass.draw(
582 0..item.vertex_count,
583 item.first_instance..(item.first_instance + item.instance_count),
584 );
585 }
586 }
587
588 if let Some(ref def) = renderer.deferred {
590 let mut gbuf_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
591 label: Some("G-Buffer Pass"),
592 color_attachments: &[
593 Some(wgpu::RenderPassColorAttachment {
594 view: &def.albedo_metallic_view,
595 resolve_target: None,
596 ops: wgpu::Operations {
597 load: wgpu::LoadOp::Clear(wgpu::Color::BLACK),
598 store: wgpu::StoreOp::Store,
599 },
600 }),
601 Some(wgpu::RenderPassColorAttachment {
602 view: &def.normal_roughness_view,
603 resolve_target: None,
604 ops: wgpu::Operations {
605 load: wgpu::LoadOp::Clear(wgpu::Color::BLACK),
606 store: wgpu::StoreOp::Store,
607 },
608 }),
609 Some(wgpu::RenderPassColorAttachment {
610 view: &def.world_position_view,
611 resolve_target: None,
612 ops: wgpu::Operations {
613 load: wgpu::LoadOp::Clear(wgpu::Color::BLACK),
614 store: wgpu::StoreOp::Store,
615 },
616 }),
617 ],
618 depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
619 view: &renderer.depth_texture_view,
620 depth_ops: Some(wgpu::Operations {
621 load: wgpu::LoadOp::Load, store: wgpu::StoreOp::Store,
623 }),
624 stencil_ops: None,
625 }),
626 timestamp_writes: None,
627 occlusion_query_set: None,
628 });
629 gbuf_pass.set_pipeline(&def.gbuffer_pipeline);
630 gbuf_pass.set_bind_group(0, &renderer.scene.global_bind_group, &[]);
631 gbuf_pass.set_bind_group(2, &renderer.scene.shadow_bind_group, &[]);
632 gbuf_pass.set_bind_group(4, &renderer.scene.instance_bind_group, &[]);
633 for item in &draw_items {
634 if item.unlit {
635 continue;
636 }
637 let skel_bg = item
638 .skeleton_bind_group
639 .as_ref()
640 .unwrap_or(&renderer.scene.dummy_skeleton_bind_group);
641 gbuf_pass.set_bind_group(3, skel_bg, &[]);
642 gbuf_pass.set_bind_group(1, &item.bind_group, &[]);
643 gbuf_pass.set_vertex_buffer(0, item.vbuf.slice(..));
644 gbuf_pass.draw(
645 0..item.vertex_count,
646 item.first_instance..(item.first_instance + item.instance_count),
647 );
648 }
649 }
650
651 let mut decal_draws = Vec::new();
653 if let Some(ref decal_state) = renderer.decal {
654 let decals = world.borrow::<crate::renderer::components::Decal>();
655 let transforms = world.borrow::<crate::physics::Transform>();
656 let mut uniform_data = Vec::new();
657
658 for (id, decal) in decals.iter() {
659 if let Some(trans) = transforms.get(id) {
660 let model = trans.local_matrix;
661 let inv_model = model.inverse();
662
663 uniform_data.push(crate::renderer::decal::DecalUniforms {
664 inv_model: inv_model.to_cols_array(),
665 model: model.to_cols_array(),
666 albedo_color: [decal.color.x, decal.color.y, decal.color.z, decal.color.w],
667 _pad: [0.0; 28],
668 });
669
670 decal_draws.push(decal.bind_group.clone());
671 if uniform_data.len() >= 1024 {
672 break;
673 } }
675 }
676
677 if !uniform_data.is_empty() {
678 renderer.queue.write_buffer(
679 &decal_state.uniform_buffer,
680 0,
681 bytemuck::cast_slice(&uniform_data),
682 );
683 }
684 }
685
686 if !decal_draws.is_empty() {
687 if let (Some(ref decal_state), Some(ref def)) = (&renderer.decal, &renderer.deferred) {
688 let mut decal_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
689 label: Some("Decal Pass"),
690 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
691 view: &def.albedo_metallic_view,
692 resolve_target: None,
693 ops: wgpu::Operations {
694 load: wgpu::LoadOp::Load,
695 store: wgpu::StoreOp::Store,
696 },
697 })],
698 depth_stencil_attachment: None, timestamp_writes: None,
700 occlusion_query_set: None,
701 });
702
703 decal_pass.set_pipeline(&decal_state.pipeline);
704 decal_pass.set_bind_group(0, &renderer.scene.global_bind_group, &[]);
705 decal_pass.set_bind_group(1, &decal_state.world_pos_bg, &[]);
706 decal_pass.set_vertex_buffer(0, decal_state.vertex_buffer.slice(..));
707
708 for (i, bind_group) in decal_draws.iter().enumerate() {
709 let offset = (i * 256) as u32;
710 decal_pass.set_bind_group(2, bind_group, &[]);
711 decal_pass.set_bind_group(3, &decal_state.decal_uniform_bg, &[offset]);
712 decal_pass.draw(0..36, 0..1);
713 }
714 }
715 }
716
717 if let Some(ref def) = renderer.deferred {
719 let mut light_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
720 label: Some("Deferred Lighting Pass"),
721 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
722 view: &renderer.post.hdr_texture_view,
723 resolve_target: None,
724 ops: wgpu::Operations {
725 load: wgpu::LoadOp::Clear(wgpu::Color::BLACK),
726 store: wgpu::StoreOp::Store,
727 },
728 })],
729 depth_stencil_attachment: None,
730 timestamp_writes: None,
731 occlusion_query_set: None,
732 });
733 light_pass.set_pipeline(&def.lighting_pipeline);
734 light_pass.set_bind_group(0, &renderer.scene.global_bind_group, &[]);
735 light_pass.set_bind_group(1, &renderer.scene.shadow_bind_group, &[]);
736 light_pass.set_bind_group(2, &def.gbuffer_bind_group, &[]);
737 light_pass.draw(0..3, 0..1);
738 }
739
740 if let Some(ref ssao) = renderer.ssao {
742 let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
743 label: Some("SSAO Pass"),
744 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
745 view: &ssao.ao_view,
746 resolve_target: None,
747 ops: wgpu::Operations {
748 load: wgpu::LoadOp::Clear(wgpu::Color::WHITE),
749 store: wgpu::StoreOp::Store,
750 },
751 })],
752 depth_stencil_attachment: None,
753 timestamp_writes: None,
754 occlusion_query_set: None,
755 });
756 pass.set_pipeline(&ssao.ssao_pipeline);
757 pass.set_bind_group(0, &renderer.scene.global_bind_group, &[]);
758 pass.set_bind_group(1, &ssao.ssao_gbuf_bind_group, &[]);
759 pass.draw(0..3, 0..1);
760 }
761
762 if let Some(ref ssao) = renderer.ssao {
764 let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
765 label: Some("SSAO Blur Pass"),
766 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
767 view: &ssao.ao_blurred_view,
768 resolve_target: None,
769 ops: wgpu::Operations {
770 load: wgpu::LoadOp::Clear(wgpu::Color::WHITE),
771 store: wgpu::StoreOp::Store,
772 },
773 })],
774 depth_stencil_attachment: None,
775 timestamp_writes: None,
776 occlusion_query_set: None,
777 });
778 pass.set_pipeline(&ssao.blur_pipeline);
779 pass.set_bind_group(0, &ssao.blur_bind_group, &[]);
780 pass.draw(0..3, 0..1);
781 }
782
783 if let Some(ref ssao) = renderer.ssao {
785 let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
786 label: Some("SSAO Apply Pass"),
787 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
788 view: &renderer.post.hdr_texture_view,
789 resolve_target: None,
790 ops: wgpu::Operations {
791 load: wgpu::LoadOp::Load,
792 store: wgpu::StoreOp::Store,
793 },
794 })],
795 depth_stencil_attachment: None,
796 timestamp_writes: None,
797 occlusion_query_set: None,
798 });
799 pass.set_pipeline(&ssao.apply_pipeline);
800 pass.set_bind_group(0, &ssao.apply_bind_group, &[]);
801 pass.draw(0..3, 0..1);
802 }
803
804 {
806 let hdr_load = if renderer.deferred.is_some() {
807 wgpu::LoadOp::Load
808 } else {
809 wgpu::LoadOp::Clear(wgpu::Color {
810 r: 0.1,
811 g: 0.1,
812 b: 0.15,
813 a: 1.0,
814 })
815 };
816 let depth_load = if renderer.deferred.is_some() {
817 wgpu::LoadOp::Load
818 } else {
819 wgpu::LoadOp::Clear(1.0)
820 };
821 let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
822 label: Some("Default Engine Render Pass"),
823 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
824 view: &renderer.post.hdr_texture_view,
825 resolve_target: None,
826 ops: wgpu::Operations {
827 load: hdr_load,
828 store: wgpu::StoreOp::Store,
829 },
830 })],
831 depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
832 view: &renderer.depth_texture_view,
833 depth_ops: Some(wgpu::Operations {
834 load: depth_load,
835 store: wgpu::StoreOp::Store,
836 }),
837 stencil_ops: None,
838 }),
839 timestamp_writes: None,
840 occlusion_query_set: None,
841 });
842 render_pass.set_bind_group(0, &renderer.scene.global_bind_group, &[]);
843 render_pass.set_bind_group(2, &renderer.scene.shadow_bind_group, &[]);
844 render_pass.set_bind_group(4, &renderer.scene.instance_bind_group, &[]);
845
846 for item in &draw_items {
847 let pipeline = if item.is_skybox {
848 &renderer.scene.sky_pipeline
849 } else if item.unlit {
850 &renderer.scene.unlit_pipeline
851 } else if renderer.deferred.is_none() {
852 &renderer.scene.render_pipeline
853 } else {
854 continue; };
856 render_pass.set_pipeline(pipeline);
857 let skel_bg = item
858 .skeleton_bind_group
859 .as_ref()
860 .unwrap_or(&renderer.scene.dummy_skeleton_bind_group);
861 render_pass.set_bind_group(1, &item.bind_group, &[]);
862 render_pass.set_bind_group(3, skel_bg, &[]);
863 render_pass.set_vertex_buffer(0, item.vbuf.slice(..));
864 render_pass.draw(
865 0..item.vertex_count,
866 item.first_instance..(item.first_instance + item.instance_count),
867 );
868 }
869
870 if let Some(physics) = &renderer.gpu_physics {
872 physics.render_pass(&mut render_pass, &renderer.scene.global_bind_group);
873 physics.debug_render_pass(&mut render_pass, &renderer.scene.global_bind_group);
874 }
875
876 if let Some(fluid) = &renderer.gpu_fluid {
878 fluid.render_pass(&mut render_pass, &renderer.scene.global_bind_group);
879 }
880
881 if let Some(particles) = &renderer.gpu_particles {
883 let active_parts = (particles.max_particles as f32 * particle_lod) as u32;
884 particles.render_pass(
885 &mut render_pass,
886 &renderer.scene.global_bind_group,
887 active_parts,
888 );
889 }
890
891 if let Some(gizmos) = world.get_resource::<crate::renderer::Gizmos>() {
892 if let Some(debug_renderer) = &mut renderer.debug_renderer {
893 debug_renderer.update(&renderer.queue, &gizmos);
894 debug_renderer.render(
895 &mut render_pass,
896 &renderer.scene.global_bind_group,
897 gizmos.depth_test,
898 );
899 }
900 }
901 }
902
903 if let Some(fluid) = &renderer.gpu_fluid {
904 let active_fluid = (fluid.num_particles as f32 * fluid_lod) as u32;
905 fluid.render_ssfr(
906 encoder,
907 &renderer.post.hdr_texture,
908 &renderer.post.hdr_texture_view,
909 &renderer.depth_texture_view,
910 &renderer.scene.global_bind_group,
911 active_fluid,
912 );
913 }
914
915 if let Some(mut gizmos) = world.get_resource_mut::<crate::renderer::Gizmos>() {
917 gizmos.clear();
918 }
919
920 if let Some(ref ssr) = renderer.ssr {
922 {
924 let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
925 label: Some("SSR Pass"),
926 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
927 view: &ssr.ssr_view,
928 resolve_target: None,
929 ops: wgpu::Operations {
930 load: wgpu::LoadOp::Clear(wgpu::Color::TRANSPARENT),
931 store: wgpu::StoreOp::Store,
932 },
933 })],
934 depth_stencil_attachment: None,
935 timestamp_writes: None,
936 occlusion_query_set: None,
937 });
938 pass.set_pipeline(&ssr.ssr_pipeline);
939 pass.set_bind_group(0, &renderer.scene.global_bind_group, &[]);
940 pass.set_bind_group(1, &ssr.ssr_bind_group, &[]);
941 pass.draw(0..3, 0..1);
942 }
943
944 {
946 let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
947 label: Some("SSR Apply Pass"),
948 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
949 view: &renderer.post.hdr_texture_view,
950 resolve_target: None,
951 ops: wgpu::Operations {
952 load: wgpu::LoadOp::Load,
953 store: wgpu::StoreOp::Store,
954 },
955 })],
956 depth_stencil_attachment: None,
957 timestamp_writes: None,
958 occlusion_query_set: None,
959 });
960 pass.set_pipeline(&ssr.apply_pipeline);
961 pass.set_bind_group(0, &ssr.apply_bind_group, &[]);
962 pass.draw(0..3, 0..1);
963 }
964 }
965
966 if let Some(ref ssgi) = renderer.ssgi {
968 {
970 let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
971 label: Some("SSGI Pass"),
972 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
973 view: &ssgi.ssgi_view,
974 resolve_target: None,
975 ops: wgpu::Operations {
976 load: wgpu::LoadOp::Clear(wgpu::Color::TRANSPARENT),
977 store: wgpu::StoreOp::Store,
978 },
979 })],
980 depth_stencil_attachment: None,
981 timestamp_writes: None,
982 occlusion_query_set: None,
983 });
984 pass.set_pipeline(&ssgi.ssgi_pipeline);
985 pass.set_bind_group(0, &renderer.scene.global_bind_group, &[]);
986 pass.set_bind_group(1, &ssgi.ssgi_bind_group, &[]);
987 pass.draw(0..3, 0..1);
988 }
989
990 {
992 let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
993 label: Some("SSGI Blur Pass"),
994 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
995 view: &ssgi.ssgi_blurred_view,
996 resolve_target: None,
997 ops: wgpu::Operations {
998 load: wgpu::LoadOp::Clear(wgpu::Color::TRANSPARENT),
999 store: wgpu::StoreOp::Store,
1000 },
1001 })],
1002 depth_stencil_attachment: None,
1003 timestamp_writes: None,
1004 occlusion_query_set: None,
1005 });
1006 pass.set_pipeline(&ssgi.blur_pipeline);
1007 pass.set_bind_group(0, &ssgi.blur_bind_group, &[]);
1008 pass.draw(0..3, 0..1);
1009 }
1010
1011 {
1013 let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
1014 label: Some("SSGI Apply Pass"),
1015 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
1016 view: &renderer.post.hdr_texture_view,
1017 resolve_target: None,
1018 ops: wgpu::Operations {
1019 load: wgpu::LoadOp::Load,
1020 store: wgpu::StoreOp::Store,
1021 },
1022 })],
1023 depth_stencil_attachment: None,
1024 timestamp_writes: None,
1025 occlusion_query_set: None,
1026 });
1027 pass.set_pipeline(&ssgi.apply_pipeline);
1028 pass.set_bind_group(0, &ssgi.apply_bind_group, &[]);
1029 pass.draw(0..3, 0..1);
1030 }
1031 }
1032
1033 if let Some(ref vol) = renderer.volumetric {
1035 {
1037 let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
1038 label: Some("Volumetric Pass"),
1039 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
1040 view: &vol.volumetric_view,
1041 resolve_target: None,
1042 ops: wgpu::Operations {
1043 load: wgpu::LoadOp::Clear(wgpu::Color::TRANSPARENT),
1044 store: wgpu::StoreOp::Store,
1045 },
1046 })],
1047 depth_stencil_attachment: None,
1048 timestamp_writes: None,
1049 occlusion_query_set: None,
1050 });
1051 pass.set_pipeline(&vol.volumetric_pipeline);
1052 pass.set_bind_group(0, &renderer.scene.global_bind_group, &[]);
1053 pass.set_bind_group(1, &renderer.scene.shadow_bind_group, &[]);
1054 pass.set_bind_group(2, &vol.volumetric_bind_group, &[]);
1055 pass.draw(0..3, 0..1);
1056 }
1057
1058 {
1060 let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
1061 label: Some("Volumetric Apply Pass"),
1062 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
1063 view: &renderer.post.hdr_texture_view,
1064 resolve_target: None,
1065 ops: wgpu::Operations {
1066 load: wgpu::LoadOp::Load,
1067 store: wgpu::StoreOp::Store,
1068 },
1069 })],
1070 depth_stencil_attachment: None,
1071 timestamp_writes: None,
1072 occlusion_query_set: None,
1073 });
1074 pass.set_pipeline(&vol.apply_pipeline);
1075 pass.set_bind_group(0, &vol.apply_bind_group, &[]);
1076 pass.draw(0..3, 0..1);
1077 }
1078 }
1079
1080 if let Some(ref taa) = renderer.taa {
1082 let (resolve_bg, output_view) = taa.current_resolve_inputs_output();
1083 let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
1084 label: Some("TAA Resolve Pass"),
1085 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
1086 view: output_view,
1087 resolve_target: None,
1088 ops: wgpu::Operations {
1089 load: wgpu::LoadOp::Clear(wgpu::Color::BLACK),
1090 store: wgpu::StoreOp::Store,
1091 },
1092 })],
1093 depth_stencil_attachment: None,
1094 timestamp_writes: None,
1095 occlusion_query_set: None,
1096 });
1097 pass.set_pipeline(&taa.resolve_pipeline);
1098 pass.set_bind_group(0, resolve_bg, &[]);
1099 pass.draw(0..3, 0..1);
1100 }
1101
1102 if let Some(ref taa) = renderer.taa {
1104 let blit_bg = taa.current_blit_bg();
1105 let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
1106 label: Some("TAA Blit Pass"),
1107 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
1108 view: &renderer.post.hdr_texture_view,
1109 resolve_target: None,
1110 ops: wgpu::Operations {
1111 load: wgpu::LoadOp::Clear(wgpu::Color::BLACK),
1112 store: wgpu::StoreOp::Store,
1113 },
1114 })],
1115 depth_stencil_attachment: None,
1116 timestamp_writes: None,
1117 occlusion_query_set: None,
1118 });
1119 pass.set_pipeline(&taa.blit_pipeline);
1120 pass.set_bind_group(0, &taa.empty_bg, &[]);
1121 pass.set_bind_group(1, blit_bg, &[]);
1122 pass.draw(0..3, 0..1);
1123 }
1124
1125 if let Some(ref mut taa) = renderer.taa {
1127 taa.advance_frame();
1128 }
1129
1130 renderer.run_post_processing(encoder, view);
1131}
1132
1133pub trait RenderContextExt {
1141 fn default_render(&mut self, world: &mut crate::core::World);
1151}
1152
1153impl<'a> RenderContextExt for crate::renderer::RenderContext<'a> {
1154 fn default_render(&mut self, world: &mut crate::core::World) {
1155 let (encoder, view, renderer) = self.parts_mut();
1156 default_render_pass(world, encoder, view, renderer);
1157 }
1158}