1mod debug;
2
3use crate::{CameraParams, DummyResources, EnvironmentMap};
4use debug::{DebugEntry, DebugVariance};
5
6pub(crate) use debug::DebugRender;
7pub use debug::{DebugBlit, DebugLine, DebugPoint};
8
9use std::{collections::HashMap, mem, num::NonZeroU32, path::Path, ptr};
10
11const MAX_RESOURCES: u32 = 8192;
12const RADIANCE_FORMAT: blade_graphics::TextureFormat = blade_graphics::TextureFormat::Rgba16Float;
13
14fn mat4_transform(t: &blade_graphics::Transform) -> glam::Mat4 {
15 glam::Mat4 {
16 x_axis: t.x.into(),
17 y_axis: t.y.into(),
18 z_axis: t.z.into(),
19 w_axis: glam::Vec4::W,
20 }
21 .transpose()
22}
23fn mat3_transform(t_orig: &blade_graphics::Transform) -> glam::Mat3 {
24 let t = mint::ColumnMatrix3x4::from(*t_orig);
25 glam::Mat3 {
26 x_axis: t.x.into(),
27 y_axis: t.y.into(),
28 z_axis: t.z.into(),
29 }
30}
31
32#[derive(Clone, Copy, Debug)]
33pub struct RenderConfig {
34 pub surface_size: blade_graphics::Extent,
35 pub surface_info: blade_graphics::SurfaceInfo,
36 pub max_debug_lines: u32,
37}
38
39struct Samplers {
40 nearest: blade_graphics::Sampler,
41 linear: blade_graphics::Sampler,
42}
43
44#[derive(
45 Clone, Copy, Debug, Default, PartialEq, PartialOrd, blade_macros::AsPrimitive, strum::EnumIter,
46)]
47#[repr(u32)]
48pub enum DebugMode {
49 #[default]
50 Final = 0,
51 Depth = 1,
52 DiffuseAlbedoTexture = 2,
53 DiffuseAlbedoFactor = 3,
54 NormalTexture = 4,
55 NormalScale = 5,
56 GeometryNormal = 6,
57 ShadingNormal = 7,
58 Motion = 8,
59 HitConsistency = 9,
60 SampleReuse = 10,
61 Variance = 15,
62}
63
64bitflags::bitflags! {
65 #[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq, PartialOrd)]
66 pub struct DebugDrawFlags: u32 {
67 const SPACE = 1;
68 const GEOMETRY = 2;
69 const RESTIR = 4;
70 }
71}
72
73bitflags::bitflags! {
74 #[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq, PartialOrd)]
75 pub struct DebugTextureFlags: u32 {
76 const ALBEDO = 1;
77 const NORMAL = 2;
78 }
79}
80
81#[derive(Clone, Copy, Debug, Default)]
82pub struct DebugConfig {
83 pub view_mode: DebugMode,
84 pub draw_flags: DebugDrawFlags,
85 pub texture_flags: DebugTextureFlags,
86 pub mouse_pos: Option<[i32; 2]>,
87}
88
89#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
90pub struct RayConfig {
91 pub num_environment_samples: u32,
92 pub environment_importance_sampling: bool,
93 pub tap_count: u32,
94 pub tap_radius: u32,
95 pub tap_confidence_near: u32,
96 pub tap_confidence_far: u32,
97 pub t_start: f32,
98 pub pairwise_mis: bool,
101 pub defensive_mis: f32,
104}
105
106#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)]
107pub struct DenoiserConfig {
108 pub num_passes: u32,
109 pub temporal_weight: f32,
110}
111
112#[derive(Clone, Copy, Debug)]
113pub struct PostProcConfig {
114 pub average_luminocity: f32,
116 pub exposure_key_value: f32,
117 pub white_level: f32,
118}
119impl Default for PostProcConfig {
120 fn default() -> Self {
121 Self {
122 average_luminocity: 1.0,
123 exposure_key_value: 1.0,
124 white_level: 1.0,
125 }
126 }
127}
128
129pub struct SelectionInfo {
130 pub std_deviation: mint::Vector3<f32>,
131 pub std_deviation_history: u32,
132 pub custom_index: u32,
133 pub depth: f32,
134 pub position: mint::Vector3<f32>,
135 pub normal: mint::Vector3<f32>,
136 pub tex_coords: mint::Vector2<f32>,
137 pub base_color_texture: Option<blade_asset::Handle<crate::Texture>>,
138 pub normal_texture: Option<blade_asset::Handle<crate::Texture>>,
139}
140impl Default for SelectionInfo {
141 fn default() -> Self {
142 Self {
143 std_deviation: [0.0; 3].into(),
144 std_deviation_history: 0,
145 custom_index: 0,
146 depth: 0.0,
147 position: [0.0; 3].into(),
148 normal: [0.0; 3].into(),
149 tex_coords: [0.0; 2].into(),
150 base_color_texture: None,
151 normal_texture: None,
152 }
153 }
154}
155
156struct RenderTarget<const N: usize> {
157 texture: blade_graphics::Texture,
158 views: [blade_graphics::TextureView; N],
159}
160impl<const N: usize> RenderTarget<N> {
161 fn new(
162 name: &str,
163 format: blade_graphics::TextureFormat,
164 size: blade_graphics::Extent,
165 encoder: &mut blade_graphics::CommandEncoder,
166 gpu: &blade_graphics::Context,
167 ) -> Self {
168 let texture = gpu.create_texture(blade_graphics::TextureDesc {
169 name,
170 format,
171 size,
172 dimension: blade_graphics::TextureDimension::D2,
173 array_layer_count: N as u32,
174 mip_level_count: 1,
175 usage: blade_graphics::TextureUsage::RESOURCE | blade_graphics::TextureUsage::STORAGE,
176 sample_count: 1,
177 external: None,
178 });
179 encoder.init_texture(texture);
180
181 let mut views = [blade_graphics::TextureView::default(); N];
182 for (i, view) in views.iter_mut().enumerate() {
183 *view = gpu.create_texture_view(
184 texture,
185 blade_graphics::TextureViewDesc {
186 name: &format!("{name}{i}"),
187 format,
188 dimension: blade_graphics::ViewDimension::D2,
189 subresources: &blade_graphics::TextureSubresources {
190 base_array_layer: i as u32,
191 array_layer_count: NonZeroU32::new(1),
192 ..Default::default()
193 },
194 },
195 );
196 }
197
198 Self { texture, views }
199 }
200
201 fn destroy(&self, gpu: &blade_graphics::Context) {
202 gpu.destroy_texture(self.texture);
203 for view in self.views.iter() {
204 gpu.destroy_texture_view(*view);
205 }
206 }
207}
208
209struct RestirTargets {
210 reservoir_buf: [blade_graphics::Buffer; 2],
211 debug: RenderTarget<1>,
212 depth: RenderTarget<2>,
213 basis: RenderTarget<2>,
214 flat_normal: RenderTarget<2>,
215 albedo: RenderTarget<1>,
216 motion: RenderTarget<1>,
217 light_diffuse: RenderTarget<3>,
218 camera_params: [CameraParams; 2],
219}
220
221impl RestirTargets {
222 fn new(
223 size: blade_graphics::Extent,
224 reservoir_size: u32,
225 encoder: &mut blade_graphics::CommandEncoder,
226 gpu: &blade_graphics::Context,
227 ) -> Self {
228 let total_reservoirs = size.width as usize * size.height as usize;
229 let mut reservoir_buf = [blade_graphics::Buffer::default(); 2];
230 for (i, rb) in reservoir_buf.iter_mut().enumerate() {
231 *rb = gpu.create_buffer(blade_graphics::BufferDesc {
232 name: &format!("reservoirs{i}"),
233 size: reservoir_size as u64 * total_reservoirs as u64,
234 memory: blade_graphics::Memory::Device,
235 });
236 }
237
238 Self {
239 reservoir_buf,
240 debug: RenderTarget::new(
241 "debug",
242 blade_graphics::TextureFormat::Rgba8Unorm,
243 size,
244 encoder,
245 gpu,
246 ),
247 depth: RenderTarget::new(
248 "depth",
249 blade_graphics::TextureFormat::R32Float,
250 size,
251 encoder,
252 gpu,
253 ),
254 basis: RenderTarget::new(
255 "basis",
256 blade_graphics::TextureFormat::Rgba8Snorm,
257 size,
258 encoder,
259 gpu,
260 ),
261 flat_normal: RenderTarget::new(
262 "flat-normal",
263 blade_graphics::TextureFormat::Rgba8Snorm,
264 size,
265 encoder,
266 gpu,
267 ),
268 albedo: RenderTarget::new(
269 "albedo",
270 blade_graphics::TextureFormat::Rgba8Unorm,
271 size,
272 encoder,
273 gpu,
274 ),
275 motion: RenderTarget::new(
276 "motion",
277 blade_graphics::TextureFormat::Rg8Snorm,
278 size,
279 encoder,
280 gpu,
281 ),
282 light_diffuse: RenderTarget::new("light-diffuse", RADIANCE_FORMAT, size, encoder, gpu),
283 camera_params: [CameraParams::default(); 2],
284 }
285 }
286
287 fn destroy(&self, gpu: &blade_graphics::Context) {
288 for rb in self.reservoir_buf.iter() {
289 gpu.destroy_buffer(*rb);
290 }
291 self.debug.destroy(gpu);
292 self.depth.destroy(gpu);
293 self.basis.destroy(gpu);
294 self.flat_normal.destroy(gpu);
295 self.albedo.destroy(gpu);
296 self.motion.destroy(gpu);
297 self.light_diffuse.destroy(gpu);
298 }
299}
300
301struct Blur {
302 temporal_accum_pipeline: blade_graphics::ComputePipeline,
303 a_trous_pipeline: blade_graphics::ComputePipeline,
304}
305
306pub struct RayTracer {
316 shaders: Shaders,
317 targets: RestirTargets,
318 post_proc_input_index: usize,
319 fill_pipeline: blade_graphics::ComputePipeline,
320 main_pipeline: blade_graphics::ComputePipeline,
321 post_proc_pipeline: blade_graphics::RenderPipeline,
322 blur: Blur,
323 acceleration_structure: blade_graphics::AccelerationStructure,
324 prev_acceleration_structure: blade_graphics::AccelerationStructure,
325 env_map: EnvironmentMap,
326 dummy: DummyResources,
327 hit_buffer: blade_graphics::Buffer,
328 vertex_buffers: blade_graphics::BufferArray<MAX_RESOURCES>,
329 index_buffers: blade_graphics::BufferArray<MAX_RESOURCES>,
330 textures: blade_graphics::TextureArray<MAX_RESOURCES>,
331 samplers: Samplers,
332 reservoir_size: u32,
333 debug: DebugRender,
334 surface_size: blade_graphics::Extent,
335 surface_info: blade_graphics::SurfaceInfo,
336 frame_index: usize,
337 frame_scene_built: usize,
338 is_frozen: bool,
339 texture_resource_lookup:
342 HashMap<blade_graphics::ResourceIndex, blade_asset::Handle<crate::Texture>>,
343}
344
345#[repr(C)]
346#[derive(Clone, Copy, bytemuck::Zeroable, bytemuck::Pod)]
347pub(crate) struct DebugParams {
348 view_mode: u32,
349 draw_flags: u32,
350 texture_flags: u32,
351 unused: u32,
352 mouse_pos: [i32; 2],
353}
354
355#[repr(C)]
356#[derive(Clone, Copy, bytemuck::Zeroable, bytemuck::Pod)]
357struct MainParams {
358 frame_index: u32,
359 num_environment_samples: u32,
360 environment_importance_sampling: u32,
361 tap_count: u32,
362 tap_radius: f32,
363 tap_confidence_near: f32,
364 tap_confidence_far: f32,
365 t_start: f32,
366 use_pairwise_mis: u32,
367 defensive_mis: f32,
368 use_motion_vectors: u32,
369}
370
371#[derive(blade_macros::ShaderData)]
372struct FillData<'a> {
373 camera: CameraParams,
374 prev_camera: CameraParams,
375 debug: DebugParams,
376 acc_struct: blade_graphics::AccelerationStructure,
377 hit_entries: blade_graphics::BufferPiece,
378 index_buffers: &'a blade_graphics::BufferArray<MAX_RESOURCES>,
379 vertex_buffers: &'a blade_graphics::BufferArray<MAX_RESOURCES>,
380 textures: &'a blade_graphics::TextureArray<MAX_RESOURCES>,
381 sampler_linear: blade_graphics::Sampler,
382 debug_buf: blade_graphics::BufferPiece,
383 out_depth: blade_graphics::TextureView,
384 out_basis: blade_graphics::TextureView,
385 out_flat_normal: blade_graphics::TextureView,
386 out_albedo: blade_graphics::TextureView,
387 out_motion: blade_graphics::TextureView,
388 out_debug: blade_graphics::TextureView,
389}
390
391#[derive(blade_macros::ShaderData)]
392struct MainData {
393 camera: CameraParams,
394 prev_camera: CameraParams,
395 debug: DebugParams,
396 parameters: MainParams,
397 acc_struct: blade_graphics::AccelerationStructure,
398 prev_acc_struct: blade_graphics::AccelerationStructure,
399 sampler_linear: blade_graphics::Sampler,
400 sampler_nearest: blade_graphics::Sampler,
401 env_map: blade_graphics::TextureView,
402 env_weights: blade_graphics::TextureView,
403 t_depth: blade_graphics::TextureView,
404 t_prev_depth: blade_graphics::TextureView,
405 t_basis: blade_graphics::TextureView,
406 t_prev_basis: blade_graphics::TextureView,
407 t_flat_normal: blade_graphics::TextureView,
408 t_prev_flat_normal: blade_graphics::TextureView,
409 t_motion: blade_graphics::TextureView,
410 debug_buf: blade_graphics::BufferPiece,
411 reservoirs: blade_graphics::BufferPiece,
412 prev_reservoirs: blade_graphics::BufferPiece,
413 out_diffuse: blade_graphics::TextureView,
414 out_debug: blade_graphics::TextureView,
415}
416
417#[repr(C)]
418#[derive(Clone, Copy, bytemuck::Zeroable, bytemuck::Pod)]
419struct BlurParams {
420 extent: [u32; 2],
421 temporal_weight: f32,
422 iteration: i32,
423 use_motion_vectors: u32,
424 pad: u32,
425}
426
427#[derive(blade_macros::ShaderData)]
428struct TemporalAccumData {
429 camera: CameraParams,
430 prev_camera: CameraParams,
431 params: BlurParams,
432 input: blade_graphics::TextureView,
433 t_depth: blade_graphics::TextureView,
434 t_prev_depth: blade_graphics::TextureView,
435 t_flat_normal: blade_graphics::TextureView,
436 t_prev_flat_normal: blade_graphics::TextureView,
437 t_motion: blade_graphics::TextureView,
438 output: blade_graphics::TextureView,
439}
440
441#[derive(blade_macros::ShaderData)]
442struct ATrousData {
443 params: BlurParams,
444 input: blade_graphics::TextureView,
445 t_depth: blade_graphics::TextureView,
446 t_flat_normal: blade_graphics::TextureView,
447 output: blade_graphics::TextureView,
448}
449
450#[repr(C)]
451#[derive(Clone, Copy, Default, bytemuck::Zeroable, bytemuck::Pod)]
452struct ToneMapParams {
453 enabled: u32,
454 average_lum: f32,
455 key_value: f32,
456 white_level: f32,
457}
458
459#[derive(blade_macros::ShaderData)]
460struct PostProcData {
461 t_albedo: blade_graphics::TextureView,
462 light_diffuse: blade_graphics::TextureView,
463 t_debug: blade_graphics::TextureView,
464 tone_map_params: ToneMapParams,
465 debug_params: DebugParams,
466}
467
468#[repr(C)]
469#[derive(Debug)]
470struct HitEntry {
471 index_buf: u32,
472 vertex_buf: u32,
473 winding: f32,
474 geometry_to_world_rotation: [i8; 4],
475 geometry_to_object: mint::ColumnMatrix4<f32>,
478 prev_object_to_world: mint::ColumnMatrix4<f32>,
479 base_color_texture: u32,
480 base_color_factor: [u8; 4],
481 normal_texture: u32,
482 normal_scale: f32,
483}
484
485#[derive(Clone, PartialEq)]
486pub struct Shaders {
487 pub(crate) env_prepare: blade_asset::Handle<crate::Shader>,
488 pub(crate) fill_gbuf: blade_asset::Handle<crate::Shader>,
489 pub(crate) ray_trace: blade_asset::Handle<crate::Shader>,
490 pub(crate) a_trous: blade_asset::Handle<crate::Shader>,
491 pub(crate) post_proc: blade_asset::Handle<crate::Shader>,
492 pub(crate) raster: blade_asset::Handle<crate::Shader>,
493 pub(crate) debug_draw: blade_asset::Handle<crate::Shader>,
494 pub(crate) debug_blit: blade_asset::Handle<crate::Shader>,
495}
496
497impl Shaders {
498 pub fn load(
499 path: &Path,
500 asset_hub: &crate::AssetHub,
501 ray_tracing: bool,
502 ) -> (Self, choir::RunningTask) {
503 let mut ctx = asset_hub.open_context(path, "shader finish");
504 let noop = if ray_tracing {
505 None
506 } else {
507 Some(ctx.load_shader("noop.wgsl"))
508 };
509 let shaders = Self {
510 env_prepare: noop.unwrap_or_else(|| ctx.load_shader("env-prepare.wgsl")),
511 fill_gbuf: noop.unwrap_or_else(|| ctx.load_shader("fill-gbuf.wgsl")),
512 ray_trace: noop.unwrap_or_else(|| ctx.load_shader("ray-trace.wgsl")),
513 a_trous: noop.unwrap_or_else(|| ctx.load_shader("a-trous.wgsl")),
514 post_proc: noop.unwrap_or_else(|| ctx.load_shader("post-proc.wgsl")),
515 raster: ctx.load_shader("raster.wgsl"),
516 debug_draw: ctx.load_shader("debug-draw.wgsl"),
517 debug_blit: ctx.load_shader("debug-blit.wgsl"),
518 };
519 (shaders, ctx.close())
520 }
521}
522
523struct ShaderPipelines {
524 fill: blade_graphics::ComputePipeline,
525 main: blade_graphics::ComputePipeline,
526 temporal_accum: blade_graphics::ComputePipeline,
527 a_trous: blade_graphics::ComputePipeline,
528 post_proc: blade_graphics::RenderPipeline,
529 env_prepare: blade_graphics::ComputePipeline,
530 reservoir_size: u32,
531}
532
533impl ShaderPipelines {
534 fn create_gbuf_fill(
535 shader: &blade_graphics::Shader,
536 gpu: &blade_graphics::Context,
537 ) -> blade_graphics::ComputePipeline {
538 shader.check_struct_size::<crate::Vertex>();
539 shader.check_struct_size::<HitEntry>();
540 let layout = <FillData as blade_graphics::ShaderData>::layout();
541 gpu.create_compute_pipeline(blade_graphics::ComputePipelineDesc {
542 name: "fill-gbuf",
543 data_layouts: &[&layout],
544 compute: shader.at("main"),
545 })
546 }
547 fn create_ray_trace(
548 shader: &blade_graphics::Shader,
549 gpu: &blade_graphics::Context,
550 ) -> blade_graphics::ComputePipeline {
551 shader.check_struct_size::<CameraParams>();
552 shader.check_struct_size::<DebugParams>();
553 shader.check_struct_size::<MainParams>();
554 shader.check_struct_size::<DebugVariance>();
555 shader.check_struct_size::<DebugEntry>();
556 let layout = <MainData as blade_graphics::ShaderData>::layout();
557 gpu.create_compute_pipeline(blade_graphics::ComputePipelineDesc {
558 name: "ray-trace",
559 data_layouts: &[&layout],
560 compute: shader.at("main"),
561 })
562 }
563
564 fn create_temporal_accum(
565 shader: &blade_graphics::Shader,
566 gpu: &blade_graphics::Context,
567 ) -> blade_graphics::ComputePipeline {
568 let layout = <TemporalAccumData as blade_graphics::ShaderData>::layout();
569 gpu.create_compute_pipeline(blade_graphics::ComputePipelineDesc {
570 name: "temporal-accum",
571 data_layouts: &[&layout],
572 compute: shader.at("temporal_accum"),
573 })
574 }
575
576 fn create_a_trous(
577 shader: &blade_graphics::Shader,
578 gpu: &blade_graphics::Context,
579 ) -> blade_graphics::ComputePipeline {
580 let layout = <ATrousData as blade_graphics::ShaderData>::layout();
581 gpu.create_compute_pipeline(blade_graphics::ComputePipelineDesc {
582 name: "a-trous",
583 data_layouts: &[&layout],
584 compute: shader.at("atrous3x3"),
585 })
586 }
587
588 fn create_post_proc(
589 shader: &blade_graphics::Shader,
590 info: blade_graphics::SurfaceInfo,
591 gpu: &blade_graphics::Context,
592 ) -> blade_graphics::RenderPipeline {
593 let layout = <PostProcData as blade_graphics::ShaderData>::layout();
594 gpu.create_render_pipeline(blade_graphics::RenderPipelineDesc {
595 name: "main",
596 data_layouts: &[&layout],
597 primitive: blade_graphics::PrimitiveState {
598 topology: blade_graphics::PrimitiveTopology::TriangleStrip,
599 ..Default::default()
600 },
601 vertex: shader.at("postfx_vs"),
602 vertex_fetches: &[],
603 fragment: Some(shader.at("postfx_fs")),
604 color_targets: &[info.format.into()],
605 depth_stencil: None,
606 multisample_state: blade_graphics::MultisampleState::default(),
607 })
608 }
609
610 fn init(
611 shaders: &Shaders,
612 config: &RenderConfig,
613 gpu: &blade_graphics::Context,
614 shader_man: &blade_asset::AssetManager<crate::shader::Baker>,
615 ) -> Result<Self, &'static str> {
616 let sh_main = shader_man[shaders.ray_trace].raw.as_ref().unwrap();
617 let sh_a_trous = shader_man[shaders.a_trous].raw.as_ref().unwrap();
618 Ok(Self {
619 fill: Self::create_gbuf_fill(shader_man[shaders.fill_gbuf].raw.as_ref().unwrap(), gpu),
620 main: Self::create_ray_trace(sh_main, gpu),
621 temporal_accum: Self::create_temporal_accum(sh_a_trous, gpu),
622 a_trous: Self::create_a_trous(sh_a_trous, gpu),
623 post_proc: Self::create_post_proc(
624 shader_man[shaders.post_proc].raw.as_ref().unwrap(),
625 config.surface_info,
626 gpu,
627 ),
628 env_prepare: EnvironmentMap::init_pipeline(
629 shader_man[shaders.env_prepare].raw.as_ref().unwrap(),
630 gpu,
631 )?,
632 reservoir_size: sh_main.get_struct_size("StoredReservoir"),
633 })
634 }
635}
636
637#[derive(Clone, Copy, Default)]
638pub struct FrameConfig {
639 pub frozen: bool,
640 pub debug_draw: bool,
641 pub reset_variance: bool,
642 pub reset_reservoirs: bool,
643}
644
645#[derive(Default)]
647pub struct FrameResources {
648 pub buffers: Vec<blade_graphics::Buffer>,
649 pub acceleration_structures: Vec<blade_graphics::AccelerationStructure>,
650}
651
652impl RayTracer {
653 #[profiling::function]
658 pub fn new(
659 encoder: &mut blade_graphics::CommandEncoder,
660 gpu: &blade_graphics::Context,
661 shaders: Shaders,
662 shader_man: &blade_asset::AssetManager<crate::shader::Baker>,
663 config: &RenderConfig,
664 ) -> Self {
665 let capabilities = gpu.capabilities();
666 assert!(
667 capabilities
668 .ray_query
669 .contains(blade_graphics::ShaderVisibility::COMPUTE)
670 );
671
672 let sp = ShaderPipelines::init(&shaders, config, gpu, shader_man).unwrap();
673 let debug = {
674 let sh_draw = shader_man[shaders.debug_draw].raw.as_ref().unwrap();
675 let sh_blit = shader_man[shaders.debug_blit].raw.as_ref().unwrap();
676 DebugRender::init(
677 encoder,
678 gpu,
679 sh_draw,
680 sh_blit,
681 config.max_debug_lines,
682 config.surface_info,
683 )
684 };
685
686 let targets = RestirTargets::new(config.surface_size, sp.reservoir_size, encoder, gpu);
687 let dummy = DummyResources::new(encoder, gpu);
688
689 let samplers = Samplers {
690 nearest: gpu.create_sampler(blade_graphics::SamplerDesc {
691 name: "nearest",
692 address_modes: [blade_graphics::AddressMode::ClampToEdge; 3],
693 mag_filter: blade_graphics::FilterMode::Nearest,
694 min_filter: blade_graphics::FilterMode::Nearest,
695 mipmap_filter: blade_graphics::FilterMode::Nearest,
696 ..Default::default()
697 }),
698 linear: gpu.create_sampler(blade_graphics::SamplerDesc {
699 name: "linear",
700 address_modes: [blade_graphics::AddressMode::Repeat; 3],
701 mag_filter: blade_graphics::FilterMode::Linear,
702 min_filter: blade_graphics::FilterMode::Linear,
703 mipmap_filter: blade_graphics::FilterMode::Linear,
704 ..Default::default()
705 }),
706 };
707
708 Self {
709 shaders,
710 targets,
711 post_proc_input_index: 0,
712 fill_pipeline: sp.fill,
713 main_pipeline: sp.main,
714 post_proc_pipeline: sp.post_proc,
715 blur: Blur {
716 temporal_accum_pipeline: sp.temporal_accum,
717 a_trous_pipeline: sp.a_trous,
718 },
719 acceleration_structure: blade_graphics::AccelerationStructure::default(),
720 prev_acceleration_structure: blade_graphics::AccelerationStructure::default(),
721 env_map: EnvironmentMap::with_pipeline(&dummy, sp.env_prepare),
722 dummy,
723 hit_buffer: blade_graphics::Buffer::default(),
724 vertex_buffers: blade_graphics::BufferArray::new(),
725 index_buffers: blade_graphics::BufferArray::new(),
726 textures: blade_graphics::TextureArray::new(),
727 samplers,
728 reservoir_size: sp.reservoir_size,
729 debug,
730 surface_size: config.surface_size,
731 surface_info: config.surface_info,
732 frame_index: 0,
733 frame_scene_built: 0,
734 is_frozen: false,
735 texture_resource_lookup: HashMap::default(),
736 }
737 }
738
739 pub fn destroy(&mut self, gpu: &blade_graphics::Context) {
741 self.targets.destroy(gpu);
743 if self.hit_buffer != blade_graphics::Buffer::default() {
744 gpu.destroy_buffer(self.hit_buffer);
745 }
746 gpu.destroy_acceleration_structure(self.acceleration_structure);
747 if self.prev_acceleration_structure != blade_graphics::AccelerationStructure::default() {
748 gpu.destroy_acceleration_structure(self.prev_acceleration_structure);
749 }
750 self.env_map.destroy(gpu);
752 self.dummy.destroy(gpu);
753 self.debug.destroy(gpu);
754 gpu.destroy_sampler(self.samplers.nearest);
756 gpu.destroy_sampler(self.samplers.linear);
757 gpu.destroy_compute_pipeline(&mut self.blur.temporal_accum_pipeline);
759 gpu.destroy_compute_pipeline(&mut self.blur.a_trous_pipeline);
760 gpu.destroy_compute_pipeline(&mut self.fill_pipeline);
761 gpu.destroy_compute_pipeline(&mut self.main_pipeline);
762 gpu.destroy_render_pipeline(&mut self.post_proc_pipeline);
763 }
764
765 #[profiling::function]
766 pub fn hot_reload(
767 &mut self,
768 asset_hub: &crate::AssetHub,
769 gpu: &blade_graphics::Context,
770 sync_point: &blade_graphics::SyncPoint,
771 ) -> bool {
772 let mut tasks = Vec::new();
773 let old = self.shaders.clone();
774
775 tasks.extend(asset_hub.shaders.hot_reload(&mut self.shaders.fill_gbuf));
776 tasks.extend(asset_hub.shaders.hot_reload(&mut self.shaders.ray_trace));
777 tasks.extend(asset_hub.shaders.hot_reload(&mut self.shaders.a_trous));
778 tasks.extend(asset_hub.shaders.hot_reload(&mut self.shaders.post_proc));
779 tasks.extend(asset_hub.shaders.hot_reload(&mut self.shaders.debug_draw));
780 tasks.extend(asset_hub.shaders.hot_reload(&mut self.shaders.debug_blit));
781
782 if tasks.is_empty() {
783 return false;
784 }
785
786 log::info!("Hot reloading shaders");
787 let _ = gpu.wait_for(sync_point, !0);
788 for task in tasks {
789 let _ = task.join();
790 }
791
792 if self.shaders.fill_gbuf != old.fill_gbuf
793 && let Ok(ref shader) = asset_hub.shaders[self.shaders.fill_gbuf].raw
794 {
795 self.fill_pipeline = ShaderPipelines::create_gbuf_fill(shader, gpu);
796 }
797 if self.shaders.ray_trace != old.ray_trace
798 && let Ok(ref shader) = asset_hub.shaders[self.shaders.ray_trace].raw
799 {
800 assert_eq!(
801 shader.get_struct_size("StoredReservoir"),
802 self.reservoir_size
803 );
804 self.main_pipeline = ShaderPipelines::create_ray_trace(shader, gpu);
805 }
806 if self.shaders.a_trous != old.a_trous
807 && let Ok(ref shader) = asset_hub.shaders[self.shaders.a_trous].raw
808 {
809 self.blur.temporal_accum_pipeline = ShaderPipelines::create_temporal_accum(shader, gpu);
810 self.blur.a_trous_pipeline = ShaderPipelines::create_a_trous(shader, gpu);
811 }
812 if self.shaders.post_proc != old.post_proc
813 && let Ok(ref shader) = asset_hub.shaders[self.shaders.post_proc].raw
814 {
815 self.post_proc_pipeline =
816 ShaderPipelines::create_post_proc(shader, self.surface_info, gpu);
817 }
818 if self.shaders.debug_draw != old.debug_draw
819 && let Ok(ref shader) = asset_hub.shaders[self.shaders.debug_draw].raw
820 {
821 self.debug.recreate_draw_pipeline(shader, gpu);
822 }
823 if self.shaders.debug_blit != old.debug_blit
824 && let Ok(ref shader) = asset_hub.shaders[self.shaders.debug_blit].raw
825 {
826 self.debug.recreate_blit_pipeline(shader, gpu);
827 }
828
829 true
830 }
831
832 pub fn get_surface_size(&self) -> blade_graphics::Extent {
833 self.surface_size
834 }
835
836 pub fn view_dummy_white(&self) -> blade_graphics::TextureView {
837 self.dummy.white_view
838 }
839 pub fn view_environment_main(&self) -> blade_graphics::TextureView {
840 self.env_map.main_view
841 }
842 pub fn view_environment_weight(&self) -> blade_graphics::TextureView {
843 self.env_map.weight_view
844 }
845
846 #[profiling::function]
847 pub fn resize_screen(
848 &mut self,
849 size: blade_graphics::Extent,
850 encoder: &mut blade_graphics::CommandEncoder,
851 gpu: &blade_graphics::Context,
852 ) {
853 self.surface_size = size;
854 self.targets.destroy(gpu);
855 self.targets = RestirTargets::new(size, self.reservoir_size, encoder, gpu);
856 }
857
858 #[profiling::function]
859 pub fn build_scene(
860 &mut self,
861 command_encoder: &mut blade_graphics::CommandEncoder,
862 objects: &[crate::Object],
863 env_map: Option<blade_asset::Handle<crate::Texture>>,
864 asset_hub: &crate::AssetHub,
865 gpu: &blade_graphics::Context,
866 temp: &mut FrameResources,
867 ) {
868 let (env_view, env_extent) = match env_map {
869 Some(handle) => {
870 let asset = &asset_hub.textures[handle];
871 (asset.view, asset.extent)
872 }
873 None => (self.dummy.white_view, blade_graphics::Extent::default()),
874 };
875 self.env_map
876 .assign(env_view, env_extent, command_encoder, gpu);
877
878 if self.prev_acceleration_structure != blade_graphics::AccelerationStructure::default() {
879 temp.acceleration_structures
880 .push(self.prev_acceleration_structure);
881 }
882 self.prev_acceleration_structure = self.acceleration_structure;
883
884 let geometry_count = objects
885 .iter()
886 .map(|object| {
887 let model = &asset_hub.models[object.model];
888 model.geometries.len()
889 })
890 .sum::<usize>();
891 let hit_size = (geometry_count.max(1) * mem::size_of::<HitEntry>()) as u64;
892 if self.hit_buffer != blade_graphics::Buffer::default() {
894 temp.buffers.push(self.hit_buffer);
895 }
896 self.hit_buffer = gpu.create_buffer(blade_graphics::BufferDesc {
897 name: "hit entries",
898 size: hit_size,
899 memory: blade_graphics::Memory::Device,
900 });
901 let hit_staging = gpu.create_buffer(blade_graphics::BufferDesc {
902 name: "hit staging",
903 size: hit_size,
904 memory: blade_graphics::Memory::Upload,
905 });
906 temp.buffers.push(hit_staging);
907 {
908 let mut transfers = command_encoder.transfer("build-scene");
909 transfers.copy_buffer_to_buffer(hit_staging.at(0), self.hit_buffer.at(0), hit_size);
910 }
911
912 self.vertex_buffers.clear();
913 self.index_buffers.clear();
914 self.textures.clear();
915 let dummy_white = self.textures.alloc(self.dummy.white_view);
916 let dummy_black = self.textures.alloc(self.dummy.black_view);
917
918 let mut geometry_index = 0;
919 let mut instances = Vec::with_capacity(objects.len());
920 let mut blases = Vec::with_capacity(objects.len());
921 let mut texture_indices = HashMap::new();
922
923 for object in objects {
924 let m3_object = mat3_transform(&object.transform);
925 let model = &asset_hub.models[object.model];
926 instances.push(blade_graphics::AccelerationStructureInstance {
927 acceleration_structure_index: blases.len() as u32,
928 transform: object.transform,
929 mask: 0xFF,
930 custom_index: geometry_index as u32,
931 });
932 blases.push(model.acceleration_structure);
933
934 for geometry in model.geometries.iter() {
935 let material = &model.materials[geometry.material_index];
936 let vertex_offset =
937 geometry.vertex_range.start as u64 * mem::size_of::<crate::Vertex>() as u64;
938 let geometry_to_world_rotation = {
939 let m3_geo = mat3_transform(&geometry.transform);
940 let m3_normal = (m3_object * m3_geo).inverse().transpose();
941 let quat = glam::Quat::from_mat3(&m3_normal);
942 let qv = glam::Vec4::from(quat) * 127.0;
943 [qv.x as i8, qv.y as i8, qv.z as i8, qv.w as i8]
944 };
945
946 let hit_entry = HitEntry {
947 index_buf: match geometry.index_type {
948 Some(_) => self
949 .index_buffers
950 .alloc(model.index_buffer.at(geometry.index_offset)),
951 None => !0,
952 },
953 vertex_buf: self
954 .vertex_buffers
955 .alloc(model.vertex_buffer.at(vertex_offset)),
956 winding: model.winding,
957 geometry_to_world_rotation,
958 geometry_to_object: mint::ColumnMatrix4::from(mint::RowMatrix4 {
959 x: geometry.transform.x,
960 y: geometry.transform.y,
961 z: geometry.transform.z,
962 w: [0.0, 0.0, 0.0, 1.0].into(),
963 }),
964 prev_object_to_world: mat4_transform(&object.prev_transform).into(),
965 base_color_texture: match material.base_color_texture {
966 Some(handle) => *texture_indices.entry(handle).or_insert_with(|| {
967 let texture = &asset_hub.textures[handle];
968 self.textures.alloc(texture.view)
969 }),
970 None => dummy_white,
971 },
972 base_color_factor: {
973 let c = material.base_color_factor;
974 [
975 (c[0] * 255.0) as u8,
976 (c[1] * 255.0) as u8,
977 (c[2] * 255.0) as u8,
978 (c[3] * 255.0) as u8,
979 ]
980 },
981 normal_texture: match material.normal_texture {
982 Some(handle) => *texture_indices.entry(handle).or_insert_with(|| {
983 let texture = &asset_hub.textures[handle];
984 self.textures.alloc(texture.view)
985 }),
986 None => dummy_black,
987 },
988 normal_scale: material.normal_scale,
989 };
990
991 log::debug!("Entry[{geometry_index}] = {hit_entry:?}");
992 unsafe {
993 ptr::write(
994 (hit_staging.data() as *mut HitEntry).add(geometry_index),
995 hit_entry,
996 );
997 }
998 geometry_index += 1;
999 }
1000 }
1001
1002 self.texture_resource_lookup.clear();
1003 for (handle, res_id) in texture_indices {
1004 self.texture_resource_lookup.insert(res_id, handle);
1005 }
1006
1007 assert_eq!(geometry_index, geometry_count);
1008 log::info!(
1009 "Preparing ray tracing with {} geometries in total",
1010 geometry_count
1011 );
1012
1013 let sizes = gpu.get_top_level_acceleration_structure_sizes(instances.len() as u32);
1015 self.acceleration_structure =
1016 gpu.create_acceleration_structure(blade_graphics::AccelerationStructureDesc {
1017 name: "TLAS",
1018 ty: blade_graphics::AccelerationStructureType::TopLevel,
1019 size: sizes.data,
1020 });
1021 let instance_buf = gpu.create_acceleration_structure_instance_buffer(&instances, &blases);
1022 let scratch_buf = gpu.create_buffer(blade_graphics::BufferDesc {
1023 name: "TLAS scratch",
1024 size: sizes.scratch,
1025 memory: blade_graphics::Memory::Device,
1026 });
1027
1028 let mut tlas_encoder = command_encoder.acceleration_structure("TLAS");
1029 tlas_encoder.build_top_level(
1030 self.acceleration_structure,
1031 &blases,
1032 instances.len() as u32,
1033 instance_buf.at(0),
1034 scratch_buf.at(0),
1035 );
1036
1037 temp.buffers.push(instance_buf);
1038 temp.buffers.push(scratch_buf);
1039 self.frame_scene_built = self.frame_index + 1;
1040 }
1041
1042 fn make_debug_params(&self, config: &DebugConfig) -> DebugParams {
1043 DebugParams {
1044 view_mode: config.view_mode as u32,
1045 draw_flags: config.draw_flags.bits(),
1046 texture_flags: config.texture_flags.bits(),
1047 unused: 0,
1048 mouse_pos: config.mouse_pos.unwrap_or([-1; 2]),
1049 }
1050 }
1051
1052 fn make_camera_params(&self, camera: &super::Camera) -> CameraParams {
1053 let fov_x = 2.0
1054 * ((camera.fov_y * 0.5).tan() * self.surface_size.width as f32
1055 / self.surface_size.height as f32)
1056 .atan();
1057 CameraParams {
1058 position: camera.pos.into(),
1059 depth: camera.depth,
1060 orientation: camera.rot.into(),
1061 fov: [fov_x, camera.fov_y],
1062 target_size: [self.surface_size.width, self.surface_size.height],
1063 }
1064 }
1065
1066 fn work_indices(&self) -> (usize, usize) {
1067 let cur = self.frame_index & 1;
1068 let prev = if cur < self.frame_index { cur ^ 1 } else { cur };
1069 (cur, prev)
1070 }
1071
1072 #[profiling::function]
1074 pub fn prepare(
1075 &mut self,
1076 command_encoder: &mut blade_graphics::CommandEncoder,
1077 camera: &crate::Camera,
1078 config: FrameConfig,
1079 ) {
1080 let mut transfer = command_encoder.transfer("prepare");
1081
1082 if config.debug_draw {
1083 self.debug.reset_lines(&mut transfer);
1084 self.debug.enable_draw(&mut transfer, true);
1085 } else {
1086 self.debug.enable_draw(&mut transfer, false);
1087 }
1088
1089 if config.reset_reservoirs || config.reset_variance {
1090 self.debug.reset_variance(&mut transfer);
1091 } else {
1092 self.debug.update_variance(&mut transfer);
1093 }
1094 self.debug.update_entry(&mut transfer);
1095
1096 if config.reset_reservoirs {
1097 if !config.debug_draw {
1098 self.debug.reset_lines(&mut transfer);
1099 }
1100 let total_reservoirs = self.surface_size.width as u64 * self.surface_size.height as u64;
1101 for reservoir_buf in self.targets.reservoir_buf.iter() {
1102 transfer.fill_buffer(
1103 reservoir_buf.at(0),
1104 total_reservoirs * self.reservoir_size as u64,
1105 0,
1106 );
1107 }
1108 }
1109
1110 if !config.frozen {
1111 self.frame_index += 1;
1112 }
1113 self.is_frozen = config.frozen;
1114 self.targets.camera_params[self.frame_index % 2] = self.make_camera_params(camera);
1115 self.post_proc_input_index = self.frame_index % 2;
1116 }
1117
1118 #[profiling::function]
1122 pub fn ray_trace(
1123 &self,
1124 command_encoder: &mut blade_graphics::CommandEncoder,
1125 debug_config: DebugConfig,
1126 ray_config: RayConfig,
1127 ) {
1128 let debug = self.make_debug_params(&debug_config);
1129 let (cur, prev) = self.work_indices();
1130 assert_eq!(cur, self.post_proc_input_index);
1131
1132 if let mut pass = command_encoder.compute("fill-gbuf") {
1133 let mut pc = pass.with(&self.fill_pipeline);
1134 let groups = self.fill_pipeline.get_dispatch_for(self.surface_size);
1135 pc.bind(
1136 0,
1137 &FillData {
1138 camera: self.targets.camera_params[cur],
1139 prev_camera: self.targets.camera_params[prev],
1140 debug,
1141 acc_struct: self.acceleration_structure,
1142 hit_entries: self.hit_buffer.into(),
1143 index_buffers: &self.index_buffers,
1144 vertex_buffers: &self.vertex_buffers,
1145 textures: &self.textures,
1146 sampler_linear: self.samplers.linear,
1147 debug_buf: self.debug.buffer_resource(),
1148 out_depth: self.targets.depth.views[cur],
1149 out_basis: self.targets.basis.views[cur],
1150 out_flat_normal: self.targets.flat_normal.views[cur],
1151 out_albedo: self.targets.albedo.views[0],
1152 out_motion: self.targets.motion.views[0],
1153 out_debug: self.targets.debug.views[0],
1154 },
1155 );
1156 pc.dispatch(groups);
1157 }
1158
1159 if let mut pass = command_encoder.compute("ray-trace") {
1160 let mut pc = pass.with(&self.main_pipeline);
1161 let groups = self.main_pipeline.get_dispatch_for(self.surface_size);
1162 pc.bind(
1163 0,
1164 &MainData {
1165 camera: self.targets.camera_params[cur],
1166 prev_camera: self.targets.camera_params[prev],
1167 debug,
1168 parameters: MainParams {
1169 frame_index: self.frame_index as u32,
1170 num_environment_samples: ray_config.num_environment_samples,
1171 environment_importance_sampling: ray_config.environment_importance_sampling
1172 as u32,
1173 tap_count: ray_config.tap_count,
1174 tap_radius: ray_config.tap_radius as f32,
1175 tap_confidence_near: ray_config.tap_confidence_near as f32,
1176 tap_confidence_far: ray_config.tap_confidence_far as f32,
1177 t_start: ray_config.t_start,
1178 use_pairwise_mis: ray_config.pairwise_mis as u32,
1179 defensive_mis: ray_config.defensive_mis,
1180 use_motion_vectors: (self.frame_scene_built >= self.frame_index) as u32,
1181 },
1182 acc_struct: self.acceleration_structure,
1183 prev_acc_struct: if self.frame_scene_built < self.frame_index
1184 || self.prev_acceleration_structure
1185 == blade_graphics::AccelerationStructure::default()
1186 {
1187 self.acceleration_structure
1188 } else {
1189 self.prev_acceleration_structure
1190 },
1191 sampler_linear: self.samplers.linear,
1192 sampler_nearest: self.samplers.nearest,
1193 env_map: self.env_map.main_view,
1194 env_weights: self.env_map.weight_view,
1195 t_depth: self.targets.depth.views[cur],
1196 t_prev_depth: self.targets.depth.views[prev],
1197 t_basis: self.targets.basis.views[cur],
1198 t_prev_basis: self.targets.basis.views[prev],
1199 t_flat_normal: self.targets.flat_normal.views[cur],
1200 t_prev_flat_normal: self.targets.flat_normal.views[prev],
1201 t_motion: self.targets.motion.views[0],
1202 debug_buf: self.debug.buffer_resource(),
1203 reservoirs: self.targets.reservoir_buf[cur].into(),
1204 prev_reservoirs: self.targets.reservoir_buf[prev].into(),
1205 out_diffuse: self.targets.light_diffuse.views[cur],
1206 out_debug: self.targets.debug.views[0],
1207 },
1208 );
1209 pc.dispatch(groups);
1210 }
1211 }
1212
1213 #[profiling::function]
1215 pub fn denoise(
1216 &mut self, command_encoder: &mut blade_graphics::CommandEncoder,
1218 denoiser_config: DenoiserConfig,
1219 ) {
1220 let mut params = BlurParams {
1221 extent: [self.surface_size.width, self.surface_size.height],
1222 temporal_weight: denoiser_config.temporal_weight,
1223 iteration: 0,
1224 use_motion_vectors: (self.frame_scene_built >= self.frame_index) as u32,
1225 pad: 0,
1226 };
1227 let (cur, prev) = self.work_indices();
1228
1229 if denoiser_config.temporal_weight < 1.0 {
1230 let mut pass = command_encoder.compute("temporal-accum");
1231 let mut pc = pass.with(&self.blur.temporal_accum_pipeline);
1232 let groups = self
1233 .blur
1234 .a_trous_pipeline
1235 .get_dispatch_for(self.surface_size);
1236 pc.bind(
1237 0,
1238 &TemporalAccumData {
1239 camera: self.targets.camera_params[cur],
1240 prev_camera: self.targets.camera_params[prev],
1241 params,
1242 input: self.targets.light_diffuse.views[prev],
1243 t_depth: self.targets.depth.views[cur],
1244 t_prev_depth: self.targets.depth.views[prev],
1245 t_flat_normal: self.targets.flat_normal.views[cur],
1246 t_prev_flat_normal: self.targets.flat_normal.views[prev],
1247 t_motion: self.targets.motion.views[0],
1248 output: self.targets.light_diffuse.views[cur],
1249 },
1250 );
1251 pc.dispatch(groups);
1252 }
1253
1254 assert_eq!(cur, self.post_proc_input_index);
1255 let mut ping_pong = [2, if self.is_frozen { cur } else { prev }];
1256 for _ in 0..denoiser_config.num_passes {
1257 let mut pass = command_encoder.compute("a-trous");
1258 let mut pc = pass.with(&self.blur.a_trous_pipeline);
1259 let groups = self
1260 .blur
1261 .a_trous_pipeline
1262 .get_dispatch_for(self.surface_size);
1263 pc.bind(
1264 0,
1265 &ATrousData {
1266 params,
1267 input: self.targets.light_diffuse.views[self.post_proc_input_index],
1268 t_depth: self.targets.depth.views[cur],
1269 t_flat_normal: self.targets.flat_normal.views[cur],
1270 output: self.targets.light_diffuse.views[ping_pong[0]],
1271 },
1272 );
1273 pc.dispatch(groups);
1274 self.post_proc_input_index = ping_pong[0];
1275 ping_pong.swap(0, 1);
1276 params.iteration += 1;
1277 }
1278 }
1279
1280 #[profiling::function]
1282 pub fn post_proc(
1283 &self,
1284 pass: &mut blade_graphics::RenderCommandEncoder,
1285 debug_config: DebugConfig,
1286 pp_config: PostProcConfig,
1287 debug_lines: &[DebugLine],
1288 debug_blits: &[DebugBlit],
1289 ) {
1290 let cur = self.frame_index % 2;
1291 if let mut pc = pass.with(&self.post_proc_pipeline) {
1292 let debug_params = self.make_debug_params(&debug_config);
1293 pc.bind(
1294 0,
1295 &PostProcData {
1296 t_albedo: self.targets.albedo.views[0],
1297 light_diffuse: self.targets.light_diffuse.views[self.post_proc_input_index],
1298 t_debug: self.targets.debug.views[0],
1299 tone_map_params: ToneMapParams {
1300 enabled: 1,
1301 average_lum: pp_config.average_luminocity,
1302 key_value: pp_config.exposure_key_value,
1303 white_level: pp_config.white_level,
1304 },
1305 debug_params,
1306 },
1307 );
1308 pc.draw(0, 3, 0, 1);
1309 }
1310
1311 self.debug.render_lines(
1312 debug_lines,
1313 self.targets.camera_params[cur],
1314 self.targets.depth.views[cur],
1315 pass,
1316 );
1317 self.debug
1318 .render_blits(debug_blits, self.samplers.linear, self.surface_size, pass);
1319 }
1320
1321 #[profiling::function]
1322 pub fn read_debug_selection_info(&self) -> SelectionInfo {
1323 let (db_v, db_e) = self.debug.read_shared_data();
1324 SelectionInfo {
1325 std_deviation: if db_v.count == 0 {
1326 [0.0; 3].into()
1327 } else {
1328 let sum_avg = glam::Vec3::from(db_v.color_sum) / (db_v.count as f32);
1329 let sum2_avg = glam::Vec3::from(db_v.color2_sum) / (db_v.count as f32);
1330 let variance = sum2_avg - sum_avg * sum_avg;
1331 mint::Vector3 {
1332 x: variance.x.sqrt(),
1333 y: variance.y.sqrt(),
1334 z: variance.z.sqrt(),
1335 }
1336 },
1337 std_deviation_history: db_v.count,
1338 custom_index: db_e.custom_index,
1339 depth: db_e.depth,
1340 position: db_e.position.into(),
1341 normal: db_e.normal.into(),
1342 tex_coords: db_e.tex_coords.into(),
1343 base_color_texture: self
1344 .texture_resource_lookup
1345 .get(&db_e.base_color_texture)
1346 .cloned(),
1347 normal_texture: self
1348 .texture_resource_lookup
1349 .get(&db_e.normal_texture)
1350 .cloned(),
1351 }
1352 }
1353}