viewport_lib/resources/volume/
implicit.rs1use crate::renderer::GpuImplicitItem;
7use crate::resources::DeviceResources;
8use wgpu::util::DeviceExt as _;
9
10#[repr(C)]
28#[derive(Clone, Copy, Debug, bytemuck::Pod, bytemuck::Zeroable)]
29pub struct ImplicitPrimitive {
30 pub kind: u32,
32 pub blend: f32,
35 #[doc(hidden)]
36 pub _pad: [f32; 2],
37 pub params: [f32; 8],
39 pub colour: [f32; 4],
42}
43
44#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
46pub enum ImplicitBlendMode {
47 #[default]
49 Union,
50 SmoothUnion,
52 Intersection,
54}
55
56#[derive(Clone, Copy, Debug)]
58pub struct GpuImplicitOptions {
59 pub max_steps: u32,
61 pub step_scale: f32,
64 pub hit_threshold: f32,
66 pub max_distance: f32,
68}
69
70impl Default for GpuImplicitOptions {
71 fn default() -> Self {
72 Self {
73 max_steps: 128,
74 step_scale: 0.85,
75 hit_threshold: 5e-4,
76 max_distance: 40.0,
77 }
78 }
79}
80
81impl ImplicitPrimitive {
82 pub fn zeroed() -> Self {
84 bytemuck::Zeroable::zeroed()
85 }
86}
87
88#[repr(C)]
96#[derive(Clone, Copy, bytemuck::Pod, bytemuck::Zeroable)]
97pub(crate) struct ImplicitUniformRaw {
98 pub num_primitives: u32,
99 pub blend_mode: u32,
100 pub max_steps: u32,
101 pub unlit: u32,
102 pub step_scale: f32,
103 pub hit_threshold: f32,
104 pub max_distance: f32,
105 pub opacity: f32,
106 pub primitives: [ImplicitPrimitive; 16],
107}
108
109pub(crate) struct ImplicitGpuItem {
111 pub _uniform_buf: wgpu::Buffer,
112 pub bind_group: wgpu::BindGroup,
113}
114
115impl DeviceResources {
120 pub(crate) fn ensure_implicit_pipeline(&mut self, device: &wgpu::Device) {
125 if self.implicit.pipeline.is_some() {
126 return;
127 }
128
129 let shader = crate::resources::builders::wgsl_module(
130 device,
131 "implicit_shader",
132 crate::resources::builders::wgsl_source!("implicit"),
133 );
134
135 let implicit_bgl = crate::resources::builders::uniform_bgl(
137 device,
138 "implicit_bgl",
139 wgpu::ShaderStages::FRAGMENT,
140 );
141
142 let layout = crate::resources::builders::standard_scene_layout(
144 device,
145 "implicit_pipeline_layout",
146 &self.camera_bind_group_layout,
147 &implicit_bgl,
148 );
149
150 self.implicit.bgl = Some(implicit_bgl);
151 self.implicit.pipeline = Some(crate::resources::builders::build_dual_pipeline(
153 device,
154 &crate::resources::builders::DualPipelineDesc {
155 label: "implicit_pipeline",
156 layout: &layout,
157 shader: &shader,
158 vertex_entry: "vs_main",
159 fragment_entry: "fs_main",
160 vertex_buffers: &[],
161 blend: Some(wgpu::BlendState::ALPHA_BLENDING),
162 topology: wgpu::PrimitiveTopology::TriangleList,
163 cull_mode: None,
164 depth_write: true,
165 depth_compare: wgpu::CompareFunction::LessEqual,
166 sample_count: 1,
167 ldr_format: self.target_format,
168 },
169 ));
170 }
171
172 pub(crate) fn ensure_implicit_outline_mask_pipeline(&mut self, device: &wgpu::Device) {
178 if self.implicit.outline_mask_pipeline.is_some() {
179 return;
180 }
181
182 let implicit_bgl = self.implicit.bgl.as_ref().expect(
183 "ensure_implicit_pipeline must be called before ensure_implicit_outline_mask_pipeline",
184 );
185
186 let shader = crate::resources::builders::wgsl_module(
187 device,
188 "implicit_outline_mask_shader",
189 crate::resources::builders::wgsl_source!("implicit_outline_mask"),
190 );
191
192 let layout = crate::resources::builders::standard_scene_layout(
193 device,
194 "implicit_outline_mask_pipeline_layout",
195 &self.camera_bind_group_layout,
196 implicit_bgl,
197 );
198
199 self.implicit.outline_mask_pipeline =
200 Some(crate::resources::builders::build_outline_mask_pipeline(
201 device,
202 "implicit_outline_mask_pipeline",
203 &layout,
204 &shader,
205 wgpu::TextureFormat::R8Unorm,
206 &[],
207 None,
208 true,
209 wgpu::CompareFunction::Less,
210 ));
211 }
212
213 pub(crate) fn upload_implicit_item(
217 &self,
218 device: &wgpu::Device,
219 item: &GpuImplicitItem,
220 ) -> ImplicitGpuItem {
221 let blend_mode_u32 = match item.blend_mode {
223 ImplicitBlendMode::Union => 0u32,
224 ImplicitBlendMode::SmoothUnion => 1,
225 ImplicitBlendMode::Intersection => 2,
226 };
227
228 let mut raw = ImplicitUniformRaw {
229 num_primitives: item.primitives.len().min(16) as u32,
230 blend_mode: blend_mode_u32,
231 max_steps: item.march_options.max_steps,
232 unlit: item.settings.unlit as u32,
233 step_scale: item.march_options.step_scale,
234 hit_threshold: item.march_options.hit_threshold,
235 max_distance: item.march_options.max_distance,
236 opacity: item.settings.opacity,
237 primitives: [ImplicitPrimitive::zeroed(); 16],
238 };
239
240 for (i, prim) in item.primitives.iter().take(16).enumerate() {
241 raw.primitives[i] = *prim;
242 }
243
244 let uniform_buf = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
245 label: Some("implicit_uniform_buf"),
246 contents: bytemuck::bytes_of(&raw),
247 usage: wgpu::BufferUsages::UNIFORM,
248 });
249
250 let bgl = self
251 .implicit
252 .bgl
253 .as_ref()
254 .expect("ensure_implicit_pipeline not called");
255
256 let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
257 label: Some("implicit_bind_group"),
258 layout: bgl,
259 entries: &[wgpu::BindGroupEntry {
260 binding: 0,
261 resource: uniform_buf.as_entire_binding(),
262 }],
263 });
264
265 ImplicitGpuItem {
266 _uniform_buf: uniform_buf,
267 bind_group,
268 }
269 }
270}