cvkg_render_gpu/passes/
volumetric.rs1use crate::kvasir::node::{ExecutionContext, KvasirNode};
2use crate::kvasir::nodes::{PassId, RES_SCENE};
3
4pub struct VolumetricNode {
11 pub inputs: Vec<crate::kvasir::resource::ResourceId>,
12 pub outputs: Vec<crate::kvasir::resource::ResourceId>,
13}
14
15impl VolumetricNode {
16 pub fn new() -> Self {
17 Self {
18 inputs: vec![RES_SCENE],
19 outputs: vec![RES_SCENE],
20 }
21 }
22}
23
24impl Default for VolumetricNode {
25 fn default() -> Self {
26 Self::new()
27 }
28}
29
30impl KvasirNode for VolumetricNode {
31 fn label(&self) -> &'static str {
32 "Volumetric"
33 }
34
35 fn inputs(&self) -> &[crate::kvasir::resource::ResourceId] {
36 &self.inputs
37 }
38
39 fn outputs(&self) -> &[crate::kvasir::resource::ResourceId] {
40 &self.outputs
41 }
42
43 fn pass_id(&self) -> PassId {
44 PassId::Volumetric
45 }
46
47 fn execute(&self, ctx: &mut ExecutionContext) {
48 let scene_view = match ctx.registry.get_texture_view(RES_SCENE) {
50 Some(v) => v,
51 None => {
52 tracing::error!("[GPU] Volumetric: missing scene texture view");
53 return;
54 }
55 };
56
57 let current_time = ctx.renderer.current_time();
59 let resolution = [
60 ctx.renderer.current_width() as f32,
61 ctx.renderer.current_height() as f32,
62 ];
63 let light_pos = [0.5_f32, 0.3, 2.0];
65 let light_color = [0.8_f32, 0.85, 1.0]; let instances = ctx.renderer.hologram_instances();
69 let holo = instances.first(); let holo_rect_x = holo.map_or(0.0, |h| h.rect.x);
71 let holo_rect_y = holo.map_or(0.0, |h| h.rect.y);
72 let holo_rect_w = holo.map_or(0.0, |h| h.rect.width);
73 let holo_rect_h = holo.map_or(0.0, |h| h.rect.height);
74 let holo_id_hash = holo.map_or(0.0f32, |h| h.id_hash as f32);
75 let holo_time = holo.map_or(0.0f32, |h| h.time);
76 let holo_count = instances.len() as f32;
77
78 let msaa_count = ctx.renderer.quality_level.msaa_sample_count() as f32;
80
81 let uniform_data: [f32; 24] = [
82 current_time, resolution[0], resolution[1], msaa_count, light_pos[0], light_pos[1], light_pos[2], 0.0, light_color[0], light_color[1], light_color[2], 1.0, 0.15, 0.0, 0.0, 0.0, holo_rect_x, holo_rect_y, holo_rect_w, holo_rect_h, holo_id_hash, holo_time, holo_count, 0.0, ];
108 ctx.renderer.queue.write_buffer(
109 &ctx.renderer.volumetric_uniform_buffer,
110 0,
111 bytemuck::cast_slice(&uniform_data),
112 );
113
114 let is_msaa = ctx.renderer.quality_level.msaa_sample_count() > 1;
116 let (depth_view_single, depth_view_msaa) = if is_msaa {
117 (&ctx.renderer.dummy_depth_view, ctx.depth_view)
118 } else {
119 (ctx.depth_view, &ctx.renderer.dummy_depth_view_msaa)
120 };
121
122 let bind_group = ctx.get_or_create_bind_group(
124 (crate::kvasir::resource::ResourceId(99999), 0, false),
125 &ctx.renderer.volumetric_bind_group_layout,
126 &[
127 wgpu::BindGroupEntry {
128 binding: 0,
129 resource: wgpu::BindingResource::Buffer(
130 ctx.renderer
131 .volumetric_uniform_buffer
132 .as_entire_buffer_binding(),
133 ),
134 },
135 wgpu::BindGroupEntry {
136 binding: 1,
137 resource: wgpu::BindingResource::TextureView(depth_view_single),
138 },
139 wgpu::BindGroupEntry {
140 binding: 2,
141 resource: wgpu::BindingResource::TextureView(depth_view_msaa),
142 },
143 wgpu::BindGroupEntry {
144 binding: 3,
145 resource: wgpu::BindingResource::Sampler(
146 &ctx.renderer.volumetric_depth_sampler,
147 ),
148 },
149 ],
150 Some("Volumetric Bind Group"),
151 );
152
153 let mut p = ctx.encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
154 label: Some("Surtr Volumetric Raymarching"),
155 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
156 view: &scene_view,
157 resolve_target: None,
158 ops: wgpu::Operations {
159 load: wgpu::LoadOp::Load,
160 store: wgpu::StoreOp::Store,
161 },
162 depth_slice: None,
163 })],
164 depth_stencil_attachment: None,
165 ..Default::default()
166 });
167
168 p.set_pipeline(&ctx.renderer.volumetric_pipeline);
169 p.set_bind_group(0, &bind_group, &[]);
170 p.draw(0..3, 0..1); }
172}