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