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 WireframeConfig {
13 pub global: bool,
14}
15
16#[derive(Default)]
17pub struct RenderCache {
18 pub(crate) batches: std::collections::HashMap<BatchKey, BatchData>,
19 pub instances: Vec<crate::renderer::gpu_types::InstanceRaw>,
20 pub draw_items: Vec<DrawItem>,
21}
22
23thread_local! {
24 static RENDER_CACHE: std::cell::RefCell<RenderCache> = std::cell::RefCell::new(RenderCache::default());
25}
26
27pub fn clear_render_cache() {
28 RENDER_CACHE.with(|rc| {
29 let mut cache = rc.borrow_mut();
30 cache.batches.clear();
31 cache.instances.clear();
32 cache.draw_items.clear();
33 });
34}
35
36#[derive(Clone)]
37pub struct DrawItem {
38 vbuf: std::sync::Arc<wgpu::Buffer>,
39 vertex_count: u32,
40 bind_group: std::sync::Arc<wgpu::BindGroup>,
41 unlit: bool,
42 is_skybox: bool,
43 skeleton_bind_group: Option<std::sync::Arc<wgpu::BindGroup>>,
44 is_transparent: bool,
45 first_instance: u32,
46 instance_count: u32,
47}
48
49#[derive(Clone, PartialEq, Eq, Hash)]
50pub(crate) struct BatchKey {
51 vbuf_id: usize,
52 mat_id: usize,
53 skeleton_id: Option<usize>,
54}
55
56pub(crate) struct BatchData {
57 vbuf: std::sync::Arc<wgpu::Buffer>,
58 bind_group: std::sync::Arc<wgpu::BindGroup>,
59 vertex_count: u32,
60 unlit: bool,
61 is_skybox: bool,
62 skeleton_bind_group: Option<std::sync::Arc<wgpu::BindGroup>>,
63 is_transparent: bool,
64 instances: Vec<crate::renderer::gpu_types::InstanceRaw>,
65}
66
67#[tracing::instrument(skip_all, name = "render_system")]
71pub fn default_render_pass(
72 world: &mut World,
73 encoder: &mut wgpu::CommandEncoder,
74 view: &wgpu::TextureView,
75 renderer: &mut Renderer,
76) {
77 renderer.update_post_process(
79 &renderer.queue,
80 crate::renderer::gpu_types::PostProcessUniforms {
81 bloom_intensity: renderer.bloom_intensity,
82 bloom_threshold: renderer.bloom_threshold,
83 exposure: renderer.exposure,
84 chromatic_aberration: renderer.chromatic_aberration,
85 vignette_intensity: 0.25,
86 film_grain_intensity: renderer.film_grain_intensity,
87 dof_focus_dist: renderer.dof_focus_dist,
88 dof_focus_range: renderer.dof_focus_range,
89 dof_blur_size: if renderer.dof_enabled { renderer.dof_blur_size } else { 0.0 },
90 _padding: [0.0; 3],
91 },
92 );
93
94 let aspect = if renderer.size.height > 0 {
95 renderer.size.width as f32 / renderer.size.height as f32
96 } else {
97 1.0
98 };
99 let mut proj = Mat4::perspective_rh(std::f32::consts::FRAC_PI_4, aspect, 0.1, 2000.0);
100 let mut view_mat = Mat4::from_translation(Vec3::ZERO);
101 let mut cam_pos = Vec3::ZERO;
102 let mut cam_forward = Vec3::new(0.0, 0.0, -1.0);
103
104 gpu_physics_submit_system(world, renderer);
109 gpu_physics_readback_system(world, renderer);
110
111 let mut cam_exposure = 1.0;
112
113 let cameras = world.borrow::<Camera>();
115 let transforms = world.borrow::<gizmo_physics_core::components::GlobalTransform>();
116 {
117 if let Some((active_cam, _)) = cameras.iter().next() {
120 if let (Some(cam), Some(trans)) = (cameras.get(active_cam), transforms.get(active_cam))
121 {
122 let (_, _, pos) = trans.matrix.to_scale_rotation_translation();
123 proj = cam.get_projection(aspect);
124 view_mat = cam.get_view(pos);
125 cam_pos = pos;
126 cam_forward = cam.get_front();
127 cam_exposure = cam.exposure;
128 }
129 }
130 }
131
132 let unjittered_proj = proj;
134
135 if let Some(ref taa) = renderer.taa {
137 if taa.enabled {
138 let jp = crate::renderer::taa::TaaState::get_jitter(taa.frame_index);
139 let jx = jp[0] * 2.0 / renderer.size.width as f32;
141 let jy = jp[1] * 2.0 / renderer.size.height as f32;
142 proj.z_axis.x -= jx;
145 proj.z_axis.y -= jy;
146 }
147 }
148
149 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);
153 let mut sun_col = gizmo_math::Vec4::new(0.0, 0.0, 0.0, 0.0); if let Some(q) = world.query::<(
155 &crate::renderer::components::DirectionalLight,
156 &gizmo_physics_core::components::GlobalTransform,
157 )>() {
158 for (_id, (light, transform)) in q.iter() {
159 if light.role == crate::renderer::components::LightRole::Sun {
160 let (_, rot, _) = transform.matrix.to_scale_rotation_translation();
161 sun_dir = rot
162 .mul_vec3(gizmo_math::Vec3::new(0.0, 0.0, -1.0))
163 .normalize();
164 sun_col = gizmo_math::Vec4::new(
165 light.color.x,
166 light.color.y,
167 light.color.z,
168 light.intensity,
169 );
170 break;
171 }
172 }
173 }
174
175 let cascade_splits = [20.0f32, 80.0, 250.0, 2000.0];
176 let cascade_vp = crate::renderer::directional_cascade_view_projs(
177 cam_pos,
178 cam_forward,
179 aspect,
180 std::f32::consts::FRAC_PI_4,
181 0.1,
182 &cascade_splits,
183 sun_dir,
184 crate::renderer::SHADOW_MAP_RES,
185 );
186 let light_view_projs: [[[f32; 4]; 4]; 4] = cascade_vp.map(|m| m.to_cols_array_2d());
187
188 let mut lights_data = [crate::renderer::gpu_types::LightData {
190 position: [0.0; 4],
191 color: [0.0; 4],
192 direction: [0.0, -1.0, 0.0, 0.0],
193 params: [0.0; 4],
194 }; 10];
195 let mut num_lights = 0;
196
197 if let Some(q) = world.query::<(
198 &crate::renderer::components::PointLight,
199 &gizmo_physics_core::components::GlobalTransform,
200 )>() {
201 for (_id, (light, transform)) in q.iter() {
202 if num_lights >= 10 {
203 break;
204 }
205 let (_, _, pos) = transform.matrix.to_scale_rotation_translation();
206 lights_data[num_lights as usize] = crate::renderer::gpu_types::LightData {
207 position: [pos.x, pos.y, pos.z, light.intensity],
208 color: [light.color.x, light.color.y, light.color.z, light.radius],
209 direction: [0.0, -1.0, 0.0, 0.0],
210 params: [0.0, 0.0, 0.0, 0.0], };
212 num_lights += 1;
213 }
214 }
215
216 if let Some(q) = world.query::<(
217 &crate::renderer::components::SpotLight,
218 &gizmo_physics_core::components::GlobalTransform,
219 )>() {
220 for (_id, (light, transform)) in q.iter() {
221 if num_lights >= 10 {
222 break;
223 }
224 let (_, rot, pos) = transform.matrix.to_scale_rotation_translation();
225 let dir = rot
226 .mul_vec3(gizmo_math::Vec3::new(0.0, 0.0, -1.0))
227 .normalize();
228 lights_data[num_lights as usize] = crate::renderer::gpu_types::LightData {
229 position: [pos.x, pos.y, pos.z, light.intensity],
230 color: [light.color.x, light.color.y, light.color.z, light.radius],
231 direction: [dir.x, dir.y, dir.z, light.inner_angle],
232 params: [light.outer_angle, 1.0, 0.0, 0.0], };
234 num_lights += 1;
235 }
236 }
237
238 #[allow(unused_assignments)]
239 let mut point_light_view_projs = [gizmo_math::Mat4::IDENTITY; 6];
240 if renderer.point_shadows_enabled {
241 if let Some(q) = world.query::<(
242 &crate::renderer::components::PointLight,
243 &gizmo_physics_core::components::GlobalTransform,
244 )>() {
245 if let Some((_id, (_light, transform))) = q.iter().next() {
246 let (_, _, pos) = transform.matrix.to_scale_rotation_translation();
247 let proj = gizmo_math::Mat4::perspective_rh(std::f32::consts::FRAC_PI_2, 1.0, 0.1, 100.0);
248 point_light_view_projs = [
249 proj * gizmo_math::Mat4::look_to_rh(pos, gizmo_math::Vec3::X, -gizmo_math::Vec3::Y),
250 proj * gizmo_math::Mat4::look_to_rh(pos, gizmo_math::Vec3::NEG_X, -gizmo_math::Vec3::Y),
251 proj * gizmo_math::Mat4::look_to_rh(pos, gizmo_math::Vec3::Y, gizmo_math::Vec3::Z),
252 proj * gizmo_math::Mat4::look_to_rh(pos, gizmo_math::Vec3::NEG_Y, gizmo_math::Vec3::NEG_Z),
253 proj * gizmo_math::Mat4::look_to_rh(pos, gizmo_math::Vec3::Z, -gizmo_math::Vec3::Y),
254 proj * gizmo_math::Mat4::look_to_rh(pos, gizmo_math::Vec3::NEG_Z, -gizmo_math::Vec3::Y),
255 ];
256
257 for i in 0..6 {
258 renderer.queue.write_buffer(
259 &renderer.scene.point_shadow_uniform_buffers[i],
260 0,
261 bytemuck::bytes_of(&crate::renderer::gpu_types::ShadowVsUniform {
262 light_view_proj: point_light_view_projs[i].to_cols_array_2d(),
263 }),
264 );
265 }
266 }
267 }
268 }
269
270
271 let scene_uniform_data = crate::renderer::gpu_types::SceneUniforms {
272 view_proj: view_proj.to_cols_array_2d(),
273 camera_pos: [cam_pos.x, cam_pos.y, cam_pos.z, 1.0],
274 sun_direction: [sun_dir.x, sun_dir.y, sun_dir.z, 1.0],
275 sun_color: [sun_col.x, sun_col.y, sun_col.z, sun_col.w],
276 lights: lights_data,
277 light_view_proj: light_view_projs,
278 cascade_splits,
279 camera_forward: [cam_forward.x, cam_forward.y, cam_forward.z, 0.0],
280 cascade_params: [0.1, 1.0 / crate::renderer::SHADOW_MAP_RES as f32, 0.0, 0.0],
281 num_lights,
282 exposure: cam_exposure,
283 _pre_align_pad: [0; 2],
284 _align_pad: [0; 3],
285 environment_blend_t: renderer.environment_blend_t,
286 environment_preset: renderer.environment_preset,
287 point_shadows_enabled: renderer.point_shadows_enabled as u32,
288 environment_preset_2: renderer.environment_preset_2,
289 shading_mode: renderer.shading_mode,
290 };
291 renderer.queue.write_buffer(
292 &renderer.scene.global_uniform_buffer,
293 0,
294 bytemuck::cast_slice(&[scene_uniform_data]),
295 );
296 for i in 0..crate::renderer::CASCADE_COUNT {
297 renderer.queue.write_buffer(
298 &renderer.scene.shadow_cascade_uniform_buffers[i],
299 0,
300 bytemuck::bytes_of(&crate::renderer::gpu_types::ShadowVsUniform {
301 light_view_proj: light_view_projs[i],
302 }),
303 );
304 }
305
306 if let Some(ref mut taa) = renderer.taa {
308 if taa.enabled {
309 let jp = crate::renderer::taa::TaaState::get_jitter(taa.frame_index);
310 let jx = jp[0] * 2.0 / renderer.size.width as f32;
311 let jy = jp[1] * 2.0 / renderer.size.height as f32;
312 let alpha = if taa.frame_index == 0 { 1.0f32 } else { 0.1f32 };
313 taa.update_params(&renderer.queue, [jx, jy], alpha);
314 taa.store_prev_vp(unjittered_view_proj.to_cols_array_2d());
315 }
316 }
317
318 let renderers = world.borrow::<MeshRenderer>();
321
322 let frustum = crate::math::Frustum::from_matrix(&unjittered_view_proj);
324
325 let draw_items = RENDER_CACHE.with(|rc| {
326 let mut cache = rc.borrow_mut();
327
328 for batch in cache.batches.values_mut() {
330 batch.instances.clear();
331 }
332 cache.instances.clear();
333 cache.draw_items.clear();
334
335 let pooled_storage = world.borrow::<gizmo_core::pool::Pooled>();
336
337 macro_rules! process_mesh {
338 ($e:expr, $mesh:expr, $trans:expr, $mat:expr, $skeleton:expr) => {
339 if renderers.get($e).is_none() {
340 continue;
341 }
342
343 if pooled_storage.get($e).is_some() {
345 continue;
346 }
347
348 let center_mat = Mat4::from_translation($mesh.center_offset);
349 let model = $trans.matrix * center_mat;
350
351 let local_cx = ($mesh.bounds.min.x + $mesh.bounds.max.x) * 0.5;
353 let local_cy = ($mesh.bounds.min.y + $mesh.bounds.max.y) * 0.5;
354 let local_cz = ($mesh.bounds.min.z + $mesh.bounds.max.z) * 0.5;
355 let world_c = model.transform_point3(Vec3::new(local_cx, local_cy, local_cz));
356 let hx = ($mesh.bounds.max.x - $mesh.bounds.min.x) * 0.5;
357 let hy = ($mesh.bounds.max.y - $mesh.bounds.min.y) * 0.5;
358 let hz = ($mesh.bounds.max.z - $mesh.bounds.min.z) * 0.5;
359 let local_r = (hx * hx + hy * hy + hz * hz).sqrt();
360 let sx = model.x_axis.truncate().length();
361 let sy = model.y_axis.truncate().length();
362 let sz = model.z_axis.truncate().length();
363 let world_r = local_r * sx.max(sy).max(sz);
364
365 if !frustum.intersects_sphere(world_c, world_r) {
366 continue;
367 }
368
369 let dist_to_cam = (world_c - cam_pos).length();
371 let use_lod1 = if !$mesh.lod_vbufs.is_empty() {
372 dist_to_cam > world_r * 15.0 } else {
374 false
375 };
376
377 let active_vbuf = if use_lod1 {
378 $mesh.lod_vbufs[0].clone()
379 } else {
380 $mesh.vbuf.clone()
381 };
382 let active_vertex_count = if use_lod1 {
383 $mesh.lod_vertex_counts[0]
384 } else {
385 $mesh.vertex_count
386 };
387
388 let packed_params = (($mat.anisotropy * 1000.0).floor() + 1000.0 * ($mat.clear_coat * 1000.0).floor() + 1000000.0 * ($mat.subsurface * 100.0).floor()) as f32;
389
390 let instance_data = crate::renderer::gpu_types::InstanceRaw {
391 model: model.to_cols_array_2d(),
392 albedo_color: [$mat.albedo.x, $mat.albedo.y, $mat.albedo.z, $mat.albedo.w],
393 roughness: $mat.roughness,
394 metallic: $mat.metallic,
395 unlit: match $mat.material_type {
396 crate::renderer::components::MaterialType::Skybox => 2.0,
397 crate::renderer::components::MaterialType::Unlit => 1.0,
398 _ => 0.0,
399 },
400 _padding: packed_params,
401 };
402 let skel_bg = $skeleton.map(|s: &crate::renderer::components::Skeleton| s.bind_group.clone());
403
404 let key = BatchKey {
405 vbuf_id: std::sync::Arc::as_ptr(&active_vbuf) as usize,
406 mat_id: std::sync::Arc::as_ptr(&$mat.bind_group) as usize,
407 skeleton_id: skel_bg.as_ref().map(|bg| std::sync::Arc::as_ptr(bg) as usize),
408 };
409
410 let batch = cache.batches.entry(key).or_insert_with(|| BatchData {
411 vbuf: active_vbuf.clone(),
412 bind_group: $mat.bind_group.clone(),
413 vertex_count: active_vertex_count,
414 unlit: $mat.material_type == crate::renderer::components::MaterialType::Unlit
415 || $mat.material_type == crate::renderer::components::MaterialType::Skybox,
416 is_skybox: $mat.material_type == crate::renderer::components::MaterialType::Skybox,
417 skeleton_bind_group: skel_bg,
418 is_transparent: $mat.is_transparent || $mat.albedo.w < 0.99,
419 instances: Vec::new(),
420 });
421 batch.instances.push(instance_data);
422 };
423 }
424
425 let skeletons = world.borrow::<crate::renderer::components::Skeleton>();
426
427 if let Some(mut q) = world.query::<(&Mesh, &gizmo_physics_core::components::GlobalTransform, &Material)>() {
428 for (e, (mesh, trans, mat)) in q.iter_mut() {
429 process_mesh!(e, mesh, trans, mat, skeletons.get(e));
430 }
431 }
432
433 let meshes = world.try_get_resource::<gizmo_core::asset::Assets<Mesh>>().ok();
434 let materials = world.try_get_resource::<gizmo_core::asset::Assets<Material>>().ok();
435
436 if let (Some(meshes), Some(materials)) = (meshes, materials) {
437 if let Some(mut q) = world.query::<(&gizmo_core::asset::Handle<Mesh>, &gizmo_physics_core::components::GlobalTransform, &gizmo_core::asset::Handle<Material>)>() {
438 for (e, (h_mesh, trans, h_mat)) in q.iter_mut() {
439 if let (Some(mesh), Some(mat)) = (meshes.get(h_mesh), materials.get(h_mat)) {
440 process_mesh!(e, mesh, trans, mat, skeletons.get(e));
441 }
442 }
443 }
444 }
445
446 let mut local_instances: Vec<crate::renderer::gpu_types::InstanceRaw> = std::mem::take(&mut cache.instances);
447 let mut local_draw_items: Vec<DrawItem> = std::mem::take(&mut cache.draw_items);
448
449 for (_, batch) in cache.batches.iter() {
450 if batch.instances.is_empty() { continue; }
451 let first_instance = local_instances.len() as u32;
452 let instance_count = batch.instances.len() as u32;
453 local_instances.extend(&batch.instances);
454
455 local_draw_items.push(DrawItem {
456 vbuf: batch.vbuf.clone(),
457 vertex_count: batch.vertex_count,
458 bind_group: batch.bind_group.clone(),
459 unlit: batch.unlit,
460 is_skybox: batch.is_skybox,
461 skeleton_bind_group: batch.skeleton_bind_group.clone(),
462 is_transparent: batch.is_transparent,
463 first_instance,
464 instance_count,
465 });
466 }
467
468 cache.instances = local_instances;
469 cache.draw_items = local_draw_items;
470
471 let max_instances = renderer.scene.instance_capacity;
473 let instances_slice = if cache.instances.len() > max_instances {
474 &cache.instances[..max_instances]
475 } else {
476 &cache.instances
477 };
478
479 if !instances_slice.is_empty() {
480 renderer.queue.write_buffer(
481 &renderer.scene.instance_buffer,
482 0,
483 bytemuck::cast_slice(instances_slice),
484 );
485 }
486
487 cache.draw_items.clone()
489 });
490 if let Some(physics) = &renderer.gpu_physics {
493 physics.request_readback(encoder);
495
496 physics.compute_pass(encoder);
497 physics.debug_compute_pass(encoder);
498 physics.cull_pass(encoder, &renderer.scene.global_bind_group);
499 }
500
501 let fluid_pos = Vec3::new(0.0, 5.0, 0.0);
503 let dist_to_fluid = (cam_pos - fluid_pos).length();
504 let fluid_lod = if dist_to_fluid < 40.0 {
505 1.0
506 } else if dist_to_fluid < 80.0 {
507 0.5
508 } else if dist_to_fluid < 150.0 {
509 0.1
510 } else {
511 0.0
512 };
513
514 let dist_to_origin = cam_pos.length();
515 let particle_lod = if dist_to_origin < 50.0 {
516 1.0
517 } else if dist_to_origin < 100.0 {
518 0.5
519 } else if dist_to_origin < 200.0 {
520 0.1
521 } else {
522 0.0
523 };
524
525 if let Some(fluid) = &renderer.gpu_fluid {
527 let active_fluid = (fluid.num_particles as f32 * fluid_lod) as u32;
528 fluid.compute_pass(encoder, &renderer.queue, true, active_fluid);
529 }
530
531 if let Some(particles) = &renderer.gpu_particles {
533 let active_parts = (particles.max_particles as f32 * particle_lod) as u32;
534 let dt = world
535 .get_resource::<gizmo_core::time::Time>()
536 .map(|t| t.dt())
537 .unwrap_or(0.016);
538 particles.update_params(&renderer.queue, dt); particles.compute_pass(encoder, active_parts);
540 }
541
542 if let Some(ref mut def) = renderer.deferred {
546 def.resize(&renderer.device, renderer.size.width, renderer.size.height);
547 }
548 {
549 let w = renderer.size.width;
550 let h = renderer.size.height;
551 if let (Some(ssao), Some(def)) = (&mut renderer.ssao, &renderer.deferred) {
552 if ssao.width != w || ssao.height != h {
553 ssao.resize(&renderer.device, def, w, h);
554 }
555 }
556 if let (Some(ssr), Some(def)) = (&mut renderer.ssr, &renderer.deferred) {
557 if ssr.width != w || ssr.height != h {
558 ssr.resize(&renderer.device, def, &renderer.post.hdr_texture_view, w, h);
559 }
560 }
561 if let (Some(volumetric), Some(def)) = (&mut renderer.volumetric, &renderer.deferred) {
562 if volumetric.width != w || volumetric.height != h {
563 volumetric.resize(&renderer.device, def, w, h);
564 }
565 }
566 }
567 {
568 let w = renderer.size.width;
569 let h = renderer.size.height;
570 if let (Some(taa), Some(def)) = (&mut renderer.taa, &renderer.deferred) {
571 if taa.width != w || taa.height != h {
572 taa.resize(
573 &renderer.device,
574 &renderer.post.hdr_texture_view,
575 &def.world_position_view,
576 w,
577 h,
578 );
579 }
580 }
581 }
582
583 for i in 0..crate::renderer::CASCADE_COUNT {
585 let mut shadow_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
586 label: Some("Shadow Pass"),
587 color_attachments: &[],
588 depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
589 view: &renderer.scene.shadow_cascade_layer_views[i],
590 depth_ops: Some(wgpu::Operations {
591 load: wgpu::LoadOp::Clear(1.0),
592 store: wgpu::StoreOp::Store,
593 }),
594 stencil_ops: None,
595 }),
596 timestamp_writes: None,
597 occlusion_query_set: None,
598 });
599 shadow_pass.set_pipeline(&renderer.scene.shadow_pipeline);
600 shadow_pass.set_bind_group(0, &renderer.scene.shadow_pass_bind_groups[i], &[]);
601 shadow_pass.set_bind_group(2, &renderer.scene.instance_bind_group, &[]);
602 for item in &draw_items {
603 if item.unlit || item.is_transparent {
604 continue;
605 }
606 let skel_bg = item
607 .skeleton_bind_group
608 .as_ref()
609 .unwrap_or(&renderer.scene.dummy_skeleton_bind_group);
610 shadow_pass.set_bind_group(1, skel_bg, &[]);
611 shadow_pass.set_vertex_buffer(0, item.vbuf.slice(..));
612 shadow_pass.draw(
613 0..item.vertex_count,
614 item.first_instance..(item.first_instance + item.instance_count),
615 );
616 }
617 }
618
619 for i in 0..6 {
621 let mut shadow_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
622 label: Some("Point Shadow Pass"),
623 color_attachments: &[],
624 depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
625 view: &renderer.scene.point_shadow_face_views[i],
626 depth_ops: Some(wgpu::Operations {
627 load: wgpu::LoadOp::Clear(1.0),
628 store: wgpu::StoreOp::Store,
629 }),
630 stencil_ops: None,
631 }),
632 timestamp_writes: None,
633 occlusion_query_set: None,
634 });
635 shadow_pass.set_pipeline(&renderer.scene.shadow_pipeline);
637 shadow_pass.set_bind_group(0, &renderer.scene.point_shadow_pass_bind_groups[i], &[]);
638 shadow_pass.set_bind_group(2, &renderer.scene.instance_bind_group, &[]);
639 for item in &draw_items {
640 if item.unlit || item.is_transparent { continue; }
641 let skel_bg = item
642 .skeleton_bind_group
643 .as_ref()
644 .unwrap_or(&renderer.scene.dummy_skeleton_bind_group);
645 shadow_pass.set_bind_group(1, skel_bg, &[]);
646 shadow_pass.set_vertex_buffer(0, item.vbuf.slice(..));
647 shadow_pass.draw(
648 0..item.vertex_count,
649 item.first_instance..(item.first_instance + item.instance_count),
650 );
651 }
652 }
653
654
655 if let Some(ref def) = renderer.deferred {
657 let mut z_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
658 label: Some("Z-Prepass"),
659 color_attachments: &[], depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
661 view: &renderer.depth_texture_view,
662 depth_ops: Some(wgpu::Operations {
663 load: wgpu::LoadOp::Clear(1.0),
664 store: wgpu::StoreOp::Store,
665 }),
666 stencil_ops: None,
667 }),
668 timestamp_writes: None,
669 occlusion_query_set: None,
670 });
671 z_pass.set_pipeline(&def.z_prepass_pipeline);
672 z_pass.set_bind_group(0, &renderer.scene.global_bind_group, &[]);
673 z_pass.set_bind_group(2, &renderer.scene.shadow_bind_group, &[]);
674 z_pass.set_bind_group(4, &renderer.scene.instance_bind_group, &[]);
675 for item in &draw_items {
676 if item.unlit || item.is_skybox || item.is_transparent {
677 continue;
678 }
679 let skel_bg = item
680 .skeleton_bind_group
681 .as_ref()
682 .unwrap_or(&renderer.scene.dummy_skeleton_bind_group);
683 z_pass.set_bind_group(3, skel_bg, &[]);
684 z_pass.set_bind_group(1, &item.bind_group, &[]);
685 z_pass.set_vertex_buffer(0, item.vbuf.slice(..));
686 z_pass.draw(
687 0..item.vertex_count,
688 item.first_instance..(item.first_instance + item.instance_count),
689 );
690 }
691 }
692
693 if let Some(ref def) = renderer.deferred {
695 let mut gbuf_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
696 label: Some("G-Buffer Pass"),
697 color_attachments: &[
698 Some(wgpu::RenderPassColorAttachment {
699 view: &def.albedo_metallic_view,
700 resolve_target: None,
701 ops: wgpu::Operations {
702 load: wgpu::LoadOp::Clear(wgpu::Color::BLACK),
703 store: wgpu::StoreOp::Store,
704 },
705 }),
706 Some(wgpu::RenderPassColorAttachment {
707 view: &def.normal_roughness_view,
708 resolve_target: None,
709 ops: wgpu::Operations {
710 load: wgpu::LoadOp::Clear(wgpu::Color::BLACK),
711 store: wgpu::StoreOp::Store,
712 },
713 }),
714 Some(wgpu::RenderPassColorAttachment {
715 view: &def.world_position_view,
716 resolve_target: None,
717 ops: wgpu::Operations {
718 load: wgpu::LoadOp::Clear(wgpu::Color::BLACK),
719 store: wgpu::StoreOp::Store,
720 },
721 }),
722 Some(wgpu::RenderPassColorAttachment {
723 view: &def.world_tangent_view,
724 resolve_target: None,
725 ops: wgpu::Operations {
726 load: wgpu::LoadOp::Clear(wgpu::Color::BLACK),
727 store: wgpu::StoreOp::Store,
728 },
729 }),
730 ],
731 depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
732 view: &renderer.depth_texture_view,
733 depth_ops: Some(wgpu::Operations {
734 load: wgpu::LoadOp::Load, store: wgpu::StoreOp::Store,
736 }),
737 stencil_ops: None,
738 }),
739 timestamp_writes: None,
740 occlusion_query_set: None,
741 });
742 gbuf_pass.set_pipeline(&def.gbuffer_pipeline);
743 gbuf_pass.set_bind_group(0, &renderer.scene.global_bind_group, &[]);
744 gbuf_pass.set_bind_group(2, &renderer.scene.shadow_bind_group, &[]);
745 gbuf_pass.set_bind_group(4, &renderer.scene.instance_bind_group, &[]);
746 for item in &draw_items {
747 if item.unlit || item.is_transparent {
748 continue;
749 }
750 let skel_bg = item
751 .skeleton_bind_group
752 .as_ref()
753 .unwrap_or(&renderer.scene.dummy_skeleton_bind_group);
754 gbuf_pass.set_bind_group(3, skel_bg, &[]);
755 gbuf_pass.set_bind_group(1, &item.bind_group, &[]);
756 gbuf_pass.set_vertex_buffer(0, item.vbuf.slice(..));
757 gbuf_pass.draw(
758 0..item.vertex_count,
759 item.first_instance..(item.first_instance + item.instance_count),
760 );
761 }
762 }
763
764 let mut decal_draws = Vec::new();
766 if let Some(ref decal_state) = renderer.decal {
767 let decals = world.borrow::<crate::renderer::components::Decal>();
768 let transforms = world.borrow::<gizmo_physics_core::Transform>();
769 let mut uniform_data = Vec::new();
770
771 for (id, decal) in decals.iter() {
772 if let Some(trans) = transforms.get(id) {
773 let model = trans.local_matrix;
774 let inv_model = model.inverse();
775
776 uniform_data.push(crate::renderer::decal::DecalUniforms {
777 inv_model: inv_model.to_cols_array(),
778 model: model.to_cols_array(),
779 albedo_color: [decal.color.x, decal.color.y, decal.color.z, decal.color.w],
780 _pad: [0.0; 28],
781 });
782
783 decal_draws.push(decal.bind_group.clone());
784 if uniform_data.len() >= 1024 {
785 break;
786 } }
788 }
789
790 if !uniform_data.is_empty() {
791 renderer.queue.write_buffer(
792 &decal_state.uniform_buffer,
793 0,
794 bytemuck::cast_slice(&uniform_data),
795 );
796 }
797 }
798
799 if !decal_draws.is_empty() {
800 if let (Some(ref decal_state), Some(ref def)) = (&renderer.decal, &renderer.deferred) {
801 let mut decal_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
802 label: Some("Decal Pass"),
803 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
804 view: &def.albedo_metallic_view,
805 resolve_target: None,
806 ops: wgpu::Operations {
807 load: wgpu::LoadOp::Load,
808 store: wgpu::StoreOp::Store,
809 },
810 })],
811 depth_stencil_attachment: None, timestamp_writes: None,
813 occlusion_query_set: None,
814 });
815
816 decal_pass.set_pipeline(&decal_state.pipeline);
817 decal_pass.set_bind_group(0, &renderer.scene.global_bind_group, &[]);
818 decal_pass.set_bind_group(1, &decal_state.world_pos_bg, &[]);
819 decal_pass.set_vertex_buffer(0, decal_state.vertex_buffer.slice(..));
820
821 for (i, bind_group) in decal_draws.iter().enumerate() {
822 let offset = (i * 256) as u32;
823 decal_pass.set_bind_group(2, bind_group, &[]);
824 decal_pass.set_bind_group(3, &decal_state.decal_uniform_bg, &[offset]);
825 decal_pass.draw(0..36, 0..1);
826 }
827 }
828 }
829
830 if let Some(ref def) = renderer.deferred {
832 let mut light_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
833 label: Some("Deferred Lighting Pass"),
834 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
835 view: &renderer.post.hdr_texture_view,
836 resolve_target: None,
837 ops: wgpu::Operations {
838 load: wgpu::LoadOp::Clear(wgpu::Color { r: 0.4, g: 0.6, b: 0.9, a: 1.0 }),
839 store: wgpu::StoreOp::Store,
840 },
841 })],
842 depth_stencil_attachment: None,
843 timestamp_writes: None,
844 occlusion_query_set: None,
845 });
846 light_pass.set_pipeline(&def.lighting_pipeline);
847 light_pass.set_bind_group(0, &renderer.scene.global_bind_group, &[]);
848 light_pass.set_bind_group(1, &renderer.scene.shadow_bind_group, &[]);
849 light_pass.set_bind_group(2, &def.gbuffer_bind_group, &[]);
850 light_pass.draw(0..3, 0..1);
851 }
852
853 if let Some(ref ssao) = renderer.ssao {
855 let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
856 label: Some("SSAO Pass"),
857 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
858 view: &ssao.ao_view,
859 resolve_target: None,
860 ops: wgpu::Operations {
861 load: wgpu::LoadOp::Clear(wgpu::Color::WHITE),
862 store: wgpu::StoreOp::Store,
863 },
864 })],
865 depth_stencil_attachment: None,
866 timestamp_writes: None,
867 occlusion_query_set: None,
868 });
869 pass.set_pipeline(&ssao.ssao_pipeline);
870 pass.set_bind_group(0, &renderer.scene.global_bind_group, &[]);
871 pass.set_bind_group(1, &ssao.ssao_gbuf_bind_group, &[]);
872 pass.draw(0..3, 0..1);
873 }
874
875 if let Some(ref ssao) = renderer.ssao {
877 let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
878 label: Some("SSAO Blur Pass"),
879 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
880 view: &ssao.ao_blurred_view,
881 resolve_target: None,
882 ops: wgpu::Operations {
883 load: wgpu::LoadOp::Clear(wgpu::Color::WHITE),
884 store: wgpu::StoreOp::Store,
885 },
886 })],
887 depth_stencil_attachment: None,
888 timestamp_writes: None,
889 occlusion_query_set: None,
890 });
891 pass.set_pipeline(&ssao.blur_pipeline);
892 pass.set_bind_group(0, &ssao.blur_bind_group, &[]);
893 pass.draw(0..3, 0..1);
894 }
895
896 if let Some(ref ssao) = renderer.ssao {
898 let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
899 label: Some("SSAO Apply Pass"),
900 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
901 view: &renderer.post.hdr_texture_view,
902 resolve_target: None,
903 ops: wgpu::Operations {
904 load: wgpu::LoadOp::Load,
905 store: wgpu::StoreOp::Store,
906 },
907 })],
908 depth_stencil_attachment: None,
909 timestamp_writes: None,
910 occlusion_query_set: None,
911 });
912 pass.set_pipeline(&ssao.apply_pipeline);
913 pass.set_bind_group(0, &ssao.apply_bind_group, &[]);
914 pass.draw(0..3, 0..1);
915 }
916
917 {
919 let hdr_load = if renderer.deferred.is_some() {
920 wgpu::LoadOp::Load
921 } else {
922 wgpu::LoadOp::Clear(wgpu::Color {
923 r: 0.4,
924 g: 0.6,
925 b: 0.9,
926 a: 1.0,
927 })
928 };
929 let depth_load = if renderer.deferred.is_some() {
930 wgpu::LoadOp::Load
931 } else {
932 wgpu::LoadOp::Clear(1.0)
933 };
934 let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
935 label: Some("Default Engine Render Pass"),
936 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
937 view: &renderer.post.hdr_texture_view,
938 resolve_target: None,
939 ops: wgpu::Operations {
940 load: hdr_load,
941 store: wgpu::StoreOp::Store,
942 },
943 })],
944 depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
945 view: &renderer.depth_texture_view,
946 depth_ops: Some(wgpu::Operations {
947 load: depth_load,
948 store: wgpu::StoreOp::Store,
949 }),
950 stencil_ops: None,
951 }),
952 timestamp_writes: None,
953 occlusion_query_set: None,
954 });
955 render_pass.set_bind_group(0, &renderer.scene.global_bind_group, &[]);
956 render_pass.set_bind_group(2, &renderer.scene.shadow_bind_group, &[]);
957 render_pass.set_bind_group(4, &renderer.scene.instance_bind_group, &[]);
958
959 let show_wireframes = world.get_resource::<WireframeConfig>().map(|c| c.global).unwrap_or(false);
960
961 for item in &draw_items {
962 let mut draw_solid = false;
963 let draw_wire = show_wireframes && !item.is_skybox;
964
965 if item.is_skybox {
966 draw_solid = true;
967 } else if item.unlit {
968 draw_solid = true;
969 } else if renderer.deferred.is_none() {
970 draw_solid = true;
971 } else if item.is_transparent {
972 draw_solid = true;
973 }
974
975 let skel_bg = item
976 .skeleton_bind_group
977 .as_ref()
978 .unwrap_or(&renderer.scene.dummy_skeleton_bind_group);
979
980 if draw_solid {
981 let pipeline = if item.is_skybox {
982 &renderer.scene.sky_pipeline
983 } else if item.unlit {
984 &renderer.scene.unlit_pipeline
985 } else if item.is_transparent {
986 &renderer.scene.transparent_pipeline
987 } else {
988 &renderer.scene.render_pipeline
989 };
990 render_pass.set_pipeline(pipeline);
991 render_pass.set_bind_group(1, &item.bind_group, &[]);
992 render_pass.set_bind_group(3, skel_bg, &[]);
993 render_pass.set_vertex_buffer(0, item.vbuf.slice(..));
994 render_pass.draw(
995 0..item.vertex_count,
996 item.first_instance..(item.first_instance + item.instance_count),
997 );
998 }
999
1000 if draw_wire {
1001 render_pass.set_pipeline(&renderer.scene.wireframe_pipeline);
1002 render_pass.set_bind_group(1, &item.bind_group, &[]);
1003 render_pass.set_bind_group(3, skel_bg, &[]);
1004 render_pass.set_vertex_buffer(0, item.vbuf.slice(..));
1005 render_pass.draw(
1006 0..item.vertex_count,
1007 item.first_instance..(item.first_instance + item.instance_count),
1008 );
1009 }
1010 }
1011
1012 if let Some(physics) = &renderer.gpu_physics {
1014 physics.render_pass(&mut render_pass, &renderer.scene.global_bind_group);
1015 physics.debug_render_pass(&mut render_pass, &renderer.scene.global_bind_group);
1016 }
1017
1018 if let Some(fluid) = &renderer.gpu_fluid {
1020 fluid.render_pass(&mut render_pass, &renderer.scene.global_bind_group);
1021 }
1022
1023 if let Some(particles) = &renderer.gpu_particles {
1025 let active_parts = (particles.max_particles as f32 * particle_lod) as u32;
1026 particles.render_pass(
1027 &mut render_pass,
1028 &renderer.scene.global_bind_group,
1029 active_parts,
1030 );
1031 }
1032
1033
1034 }
1035
1036 if let Some(fluid) = &renderer.gpu_fluid {
1037 let active_fluid = (fluid.num_particles as f32 * fluid_lod) as u32;
1038 fluid.render_ssfr(
1039 encoder,
1040 &renderer.post.hdr_texture,
1041 &renderer.post.hdr_texture_view,
1042 &renderer.depth_texture_view,
1043 &renderer.scene.global_bind_group,
1044 active_fluid,
1045 );
1046 }
1047
1048
1049
1050 if let Some(ref ssr) = renderer.ssr {
1052 {
1054 let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
1055 label: Some("SSR Pass"),
1056 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
1057 view: &ssr.ssr_view,
1058 resolve_target: None,
1059 ops: wgpu::Operations {
1060 load: wgpu::LoadOp::Clear(wgpu::Color::TRANSPARENT),
1061 store: wgpu::StoreOp::Store,
1062 },
1063 })],
1064 depth_stencil_attachment: None,
1065 timestamp_writes: None,
1066 occlusion_query_set: None,
1067 });
1068 pass.set_pipeline(&ssr.ssr_pipeline);
1069 pass.set_bind_group(0, &renderer.scene.global_bind_group, &[]);
1070 pass.set_bind_group(1, &ssr.ssr_bind_group, &[]);
1071 pass.draw(0..3, 0..1);
1072 }
1073
1074 {
1076 let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
1077 label: Some("SSR Apply Pass"),
1078 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
1079 view: &renderer.post.hdr_texture_view,
1080 resolve_target: None,
1081 ops: wgpu::Operations {
1082 load: wgpu::LoadOp::Load,
1083 store: wgpu::StoreOp::Store,
1084 },
1085 })],
1086 depth_stencil_attachment: None,
1087 timestamp_writes: None,
1088 occlusion_query_set: None,
1089 });
1090 pass.set_pipeline(&ssr.apply_pipeline);
1091 pass.set_bind_group(0, &ssr.apply_bind_group, &[]);
1092 pass.draw(0..3, 0..1);
1093 }
1094 }
1095
1096 if let Some(ref ssgi) = renderer.ssgi {
1098 {
1100 let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
1101 label: Some("SSGI Pass"),
1102 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
1103 view: &ssgi.ssgi_view,
1104 resolve_target: None,
1105 ops: wgpu::Operations {
1106 load: wgpu::LoadOp::Clear(wgpu::Color::TRANSPARENT),
1107 store: wgpu::StoreOp::Store,
1108 },
1109 })],
1110 depth_stencil_attachment: None,
1111 timestamp_writes: None,
1112 occlusion_query_set: None,
1113 });
1114 pass.set_pipeline(&ssgi.ssgi_pipeline);
1115 pass.set_bind_group(0, &renderer.scene.global_bind_group, &[]);
1116 pass.set_bind_group(1, &ssgi.ssgi_bind_group, &[]);
1117 pass.draw(0..3, 0..1);
1118 }
1119
1120 {
1122 let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
1123 label: Some("SSGI Blur Pass"),
1124 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
1125 view: &ssgi.ssgi_blurred_view,
1126 resolve_target: None,
1127 ops: wgpu::Operations {
1128 load: wgpu::LoadOp::Clear(wgpu::Color::TRANSPARENT),
1129 store: wgpu::StoreOp::Store,
1130 },
1131 })],
1132 depth_stencil_attachment: None,
1133 timestamp_writes: None,
1134 occlusion_query_set: None,
1135 });
1136 pass.set_pipeline(&ssgi.blur_pipeline);
1137 pass.set_bind_group(0, &ssgi.blur_bind_group, &[]);
1138 pass.draw(0..3, 0..1);
1139 }
1140
1141 {
1143 let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
1144 label: Some("SSGI Apply Pass"),
1145 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
1146 view: &renderer.post.hdr_texture_view,
1147 resolve_target: None,
1148 ops: wgpu::Operations {
1149 load: wgpu::LoadOp::Load,
1150 store: wgpu::StoreOp::Store,
1151 },
1152 })],
1153 depth_stencil_attachment: None,
1154 timestamp_writes: None,
1155 occlusion_query_set: None,
1156 });
1157 pass.set_pipeline(&ssgi.apply_pipeline);
1158 pass.set_bind_group(0, &ssgi.apply_bind_group, &[]);
1159 pass.draw(0..3, 0..1);
1160 }
1161 }
1162
1163 if let Some(ref vol) = renderer.volumetric {
1165 {
1167 let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
1168 label: Some("Volumetric Pass"),
1169 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
1170 view: &vol.volumetric_view,
1171 resolve_target: None,
1172 ops: wgpu::Operations {
1173 load: wgpu::LoadOp::Clear(wgpu::Color::TRANSPARENT),
1174 store: wgpu::StoreOp::Store,
1175 },
1176 })],
1177 depth_stencil_attachment: None,
1178 timestamp_writes: None,
1179 occlusion_query_set: None,
1180 });
1181 pass.set_pipeline(&vol.volumetric_pipeline);
1182 pass.set_bind_group(0, &renderer.scene.global_bind_group, &[]);
1183 pass.set_bind_group(1, &renderer.scene.shadow_bind_group, &[]);
1184 pass.set_bind_group(2, &vol.volumetric_bind_group, &[]);
1185 pass.draw(0..3, 0..1);
1186 }
1187
1188 {
1190 let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
1191 label: Some("Volumetric Apply Pass"),
1192 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
1193 view: &renderer.post.hdr_texture_view,
1194 resolve_target: None,
1195 ops: wgpu::Operations {
1196 load: wgpu::LoadOp::Load,
1197 store: wgpu::StoreOp::Store,
1198 },
1199 })],
1200 depth_stencil_attachment: None,
1201 timestamp_writes: None,
1202 occlusion_query_set: None,
1203 });
1204 pass.set_pipeline(&vol.apply_pipeline);
1205 pass.set_bind_group(0, &vol.apply_bind_group, &[]);
1206 pass.draw(0..3, 0..1);
1207 }
1208 }
1209
1210 if let Some(ref taa) = renderer.taa {
1212 if taa.enabled {
1213 let (resolve_bg, output_view) = taa.current_resolve_inputs_output();
1214 let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
1215 label: Some("TAA Resolve Pass"),
1216 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
1217 view: output_view,
1218 resolve_target: None,
1219 ops: wgpu::Operations {
1220 load: wgpu::LoadOp::Clear(wgpu::Color::BLACK),
1221 store: wgpu::StoreOp::Store,
1222 },
1223 })],
1224 depth_stencil_attachment: None,
1225 timestamp_writes: None,
1226 occlusion_query_set: None,
1227 });
1228 pass.set_pipeline(&taa.resolve_pipeline);
1229 pass.set_bind_group(0, resolve_bg, &[]);
1230 pass.draw(0..3, 0..1);
1231 }
1232 }
1233
1234 if let Some(ref taa) = renderer.taa {
1236 if taa.enabled {
1237 let blit_bg = taa.current_blit_bg();
1238 let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
1239 label: Some("TAA Blit Pass"),
1240 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
1241 view: &renderer.post.hdr_texture_view,
1242 resolve_target: None,
1243 ops: wgpu::Operations {
1244 load: wgpu::LoadOp::Clear(wgpu::Color::BLACK),
1245 store: wgpu::StoreOp::Store,
1246 },
1247 })],
1248 depth_stencil_attachment: None,
1249 timestamp_writes: None,
1250 occlusion_query_set: None,
1251 });
1252 pass.set_pipeline(&taa.blit_pipeline);
1253 pass.set_bind_group(0, &taa.empty_bg, &[]);
1254 pass.set_bind_group(1, blit_bg, &[]);
1255 pass.draw(0..3, 0..1);
1256 }
1257 }
1258
1259 if let Some(gizmos) = world.get_resource::<crate::renderer::Gizmos>() {
1261 if let Some(debug_renderer) = &mut renderer.debug_renderer {
1262 debug_renderer.update(&renderer.queue, &gizmos);
1263 let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
1264 label: Some("Gizmo Render Pass (Post-TAA)"),
1265 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
1266 view: &renderer.post.hdr_texture_view,
1267 resolve_target: None,
1268 ops: wgpu::Operations {
1269 load: wgpu::LoadOp::Load, store: wgpu::StoreOp::Store,
1271 },
1272 })],
1273 depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
1274 view: &renderer.depth_texture_view,
1275 depth_ops: Some(wgpu::Operations {
1276 load: wgpu::LoadOp::Load,
1277 store: wgpu::StoreOp::Store,
1278 }),
1279 stencil_ops: None,
1280 }),
1281 timestamp_writes: None,
1282 occlusion_query_set: None,
1283 });
1284 debug_renderer.render(
1285 &mut pass,
1286 &renderer.scene.global_bind_group,
1287 gizmos.depth_test,
1288 );
1289 }
1290 }
1291
1292 let mut should_clear = true;
1294 let current_step = world.get_resource::<gizmo_core::time::PhysicsTime>()
1295 .map(|pt| pt.step_count());
1296
1297 if let Some(current_step) = current_step {
1298 struct GizmosLastStepCount(u64);
1299
1300 let has_resource = world.get_resource::<GizmosLastStepCount>().is_some();
1301 if has_resource {
1302 if let Some(mut last_step) = world.get_resource_mut::<GizmosLastStepCount>() {
1303 if last_step.0 == current_step {
1304 should_clear = false;
1305 } else {
1306 last_step.0 = current_step;
1307 }
1308 }
1309 } else {
1310 world.insert_resource(GizmosLastStepCount(current_step));
1311 }
1312 }
1313
1314 if should_clear {
1315 if let Some(mut gizmos) = world.get_resource_mut::<crate::renderer::Gizmos>() {
1316 gizmos.clear();
1317 }
1318 }
1319
1320 if let Some(ref mut taa) = renderer.taa {
1322 if taa.enabled {
1323 taa.advance_frame();
1324 }
1325 }
1326
1327 renderer.run_post_processing(encoder, view);
1328}
1329
1330pub trait RenderContextExt {
1338 fn default_render(&mut self, world: &mut crate::core::World);
1348}
1349
1350impl<'a> RenderContextExt for crate::renderer::RenderContext<'a> {
1351 fn default_render(&mut self, world: &mut crate::core::World) {
1352 let (encoder, view, renderer) = self.parts_mut();
1353 default_render_pass(world, encoder, view, renderer);
1354 }
1355}