wgpu_3dgs_editor/modifier.rs
1use crate::{
2 BasicColorModifiersBuffer, RotScaleBuffer, SelectionBuffer, TransformFlagsBuffer,
3 core::{
4 self, BufferWrapper, ComputeBundle, ComputeBundleBuilder, GaussianPod,
5 GaussianTransformBuffer, GaussiansBuffer, ModelTransformBuffer,
6 },
7 shader,
8};
9
10/// A trait to apply modifier to Gaussians.
11///
12/// ## Overview
13///
14/// This trait simply defines a method to apply modifications to a set of Gaussians stored in a
15/// [`GaussiansBuffer`]. It makes it convenient for users to apply a sequence of modifications.
16///
17/// The trait is also blanket implemented for closures with the same signature, allowing users to
18/// easily create modifier closures instead of having to define a modifier struct.
19///
20/// [`Editor`](crate::Editor) also provides an `apply` method which takes a slice of
21/// [`Modifier`]s to apply them in sequence to the stored Gaussians.
22///
23/// ## Usage
24///
25/// There are many ways to use this but the recommended way is to implement this trait for a closure
26/// which dispatch a [`ComputeBundle`].
27///
28/// ```rust no_run
29/// # pollster::block_on(async {
30/// # use wgpu_3dgs_editor::{
31/// # Editor, MODIFIER_GAUSSIANS_BIND_GROUP_LAYOUT_DESCRIPTOR, Modifier,
32/// # core::{
33/// # self, BufferWrapper, GaussianPod as _, GaussianTransformBuffer,
34/// # GaussiansBuffer, ModelTransformBuffer, glam::*,
35/// # },
36/// # shader,
37/// # };
38/// #
39/// # type GaussianPod = core::GaussianPodWithShSingleCov3dSingleConfigs;
40/// #
41/// # let instance = wgpu::Instance::new(
42/// # wgpu::InstanceDescriptor::new_without_display_handle_from_env()
43/// # );
44/// #
45/// # let adapter = instance
46/// # .request_adapter(&wgpu::RequestAdapterOptions::default())
47/// # .await
48/// # .expect("adapter");
49/// #
50/// # let (device, _queue) = adapter
51/// # .request_device(&wgpu::DeviceDescriptor {
52/// # label: Some("Device"),
53/// # required_limits: adapter.limits(),
54/// # ..Default::default()
55/// # })
56/// # .await
57/// # .expect("device");
58/// #
59/// # const MY_CUSTOM_BIND_GROUP_LAYOUT_DESCRIPTOR: wgpu::BindGroupLayoutDescriptor =
60/// # wgpu::BindGroupLayoutDescriptor {
61/// # label: Some("My Custom Bind Group Layout"),
62/// # entries: &[wgpu::BindGroupLayoutEntry {
63/// # binding: 0,
64/// # visibility: wgpu::ShaderStages::COMPUTE,
65/// # ty: wgpu::BindingType::Buffer {
66/// # ty: wgpu::BufferBindingType::Uniform,
67/// # has_dynamic_offset: false,
68/// # min_binding_size: None,
69/// # },
70/// # count: None,
71/// # }],
72/// # };
73/// #
74/// # let my_buffer = device.create_buffer(&wgpu::BufferDescriptor {
75/// # label: Some("My Buffer"),
76/// # size: 4,
77/// # usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
78/// # mapped_at_creation: false,
79/// # });
80/// #
81/// // Create an editor that holds the buffers for the Gaussians and will apply the modifier
82/// let editor = Editor::new(
83/// &device,
84/// &vec![core::Gaussian {
85/// rot: Quat::IDENTITY,
86/// pos: Vec3::ZERO,
87/// color: U8Vec4::ZERO,
88/// sh: [Vec3::ZERO; 15],
89/// scale: Vec3::ONE,
90/// }],
91/// );
92///
93/// // Create the modifier compute bundle
94/// let my_modifier_bundle = core::ComputeBundleBuilder::new()
95/// .label("My Modifier")
96/// .bind_group_layouts([
97/// // For accessing Gaussians and transforms
98/// &MODIFIER_GAUSSIANS_BIND_GROUP_LAYOUT_DESCRIPTOR,
99/// // Your custom bind group layout here
100/// &MY_CUSTOM_BIND_GROUP_LAYOUT_DESCRIPTOR,
101/// ])
102/// .resolver({
103/// let mut resolver =
104/// wesl::StandardResolver::new("path/to/my/folder/containing/wesl");
105/// // Required for using core buffer structs.
106/// resolver.add_package(&core::shader::PACKAGE);
107/// // Optionally add this for some utility functions.
108/// resolver.add_package(&shader::PACKAGE);
109/// resolver
110/// })
111/// .main_shader("package::my_wesl_filename".parse().unwrap())
112/// .entry_point("main")
113/// .wesl_compile_options(wesl::CompileOptions {
114/// // Required for enabling the correct features for core struct.
115/// features: GaussianPod::wesl_features(),
116/// ..Default::default()
117/// })
118/// .build(
119/// &device,
120/// [
121/// vec![
122/// editor.gaussians_buffer.buffer().as_entire_binding(),
123/// editor.model_transform_buffer.buffer().as_entire_binding(),
124/// editor.gaussian_transform_buffer.buffer().as_entire_binding(),
125/// ],
126/// vec![my_buffer.buffer().as_entire_binding()],
127/// ],
128/// )
129/// .map_err(|e| log::error!("{e}"))
130/// .expect("my modifier bundle");
131///
132/// // Create the modifier closure
133/// // This function signature implements Modifier by default
134/// let my_modifier =
135/// |_device: &wgpu::Device,
136/// encoder: &mut wgpu::CommandEncoder,
137/// gaussians: &GaussiansBuffer<GaussianPod>,
138/// _model_transform: &ModelTransformBuffer,
139/// _gaussian_transform: &GaussianTransformBuffer| {
140/// my_modifier_bundle.dispatch(encoder, gaussians.len() as u32);
141/// };
142///
143/// # let mut encoder =
144/// # device.create_command_encoder(&wgpu::CommandEncoderDescriptor::default());
145///
146/// // Apply the modifier using the editor
147/// editor.apply(
148/// &device,
149/// &mut encoder,
150/// [&my_modifier as &dyn Modifier<GaussianPod>],
151/// );
152/// # });
153/// ```
154///
155/// ## Shader Format
156///
157/// You may copy and paste the following shader bindings for
158/// [`MODIFIER_GAUSSIANS_BIND_GROUP_LAYOUT_DESCRIPTOR`] into your custom selection operation
159/// shader to ensure that the bindings are correct, then add your own bindings after that.
160///
161/// ```wgsl
162/// import wgpu_3dgs_core::{
163/// gaussian::Gaussian,
164/// gaussian_transform::GaussianTransform,
165/// model_transform::ModelTransform,
166/// };
167///
168/// @group(0) @binding(0)
169/// var<storage, read_write> gaussians: array<Gaussian>;
170///
171/// @group(0) @binding(1)
172/// var<uniform> model_transform: ModelTransform;
173///
174/// @group(0) @binding(2)
175/// var<uniform> gaussian_transform: GaussianTransform;
176///
177/// // Your custom bindings here...
178/// //
179/// // You may also apply modifier to selected gaussians only by adding:
180/// // @group(1) @binding(N)
181/// // var<storage, read> selection: array<u32>;
182///
183/// override workgroup_size: u32;
184///
185/// @compute @workgroup_size(workgroup_size)
186/// fn main(@builtin(global_invocation_id) id: vec3<u32>) {
187/// let index = id.x;
188///
189/// if index >= arrayLength(&gaussians) {
190/// return;
191/// }
192///
193/// @if(/* using selection buffer */) {
194/// let word_index = index / 32u;
195/// let bit_index = index % 32u;
196/// let bit_mask = 1u << bit_index;
197/// if (selection[word_index] & bit_mask) == 0 {
198/// return;
199/// }
200/// }
201///
202/// var gaussian = gaussians[index];
203///
204/// // Your custom modifier operation code here...
205///
206/// gaussians[index] = gaussian;
207/// }
208/// ```
209pub trait Modifier<G: GaussianPod> {
210 /// Apply the modifier to the Gaussians.
211 fn apply(
212 &self,
213 device: &wgpu::Device,
214 encoder: &mut wgpu::CommandEncoder,
215 gaussians: &GaussiansBuffer<G>,
216 model_transform: &ModelTransformBuffer,
217 gaussian_transform: &GaussianTransformBuffer,
218 );
219}
220
221impl<
222 G: GaussianPod,
223 F: Fn(
224 &wgpu::Device,
225 &mut wgpu::CommandEncoder,
226 &GaussiansBuffer<G>,
227 &ModelTransformBuffer,
228 &GaussianTransformBuffer,
229 ),
230> Modifier<G> for F
231{
232 fn apply(
233 &self,
234 device: &wgpu::Device,
235 encoder: &mut wgpu::CommandEncoder,
236 gaussians: &GaussiansBuffer<G>,
237 model_transform: &ModelTransformBuffer,
238 gaussian_transform: &GaussianTransformBuffer,
239 ) {
240 self(
241 device,
242 encoder,
243 gaussians,
244 model_transform,
245 gaussian_transform,
246 );
247 }
248}
249
250/// The bind group layout descriptor for the Gaussians buffer, with the
251/// model transform and Gaussian transform.
252///
253/// This bind group layout takes the following buffers:
254/// - [`GaussiansBuffer`]
255/// - [`ModelTransformBuffer`]
256/// - [`GaussianTransformBuffer`]
257///
258/// This bind group is usually at group 0 for [`Modifier`]s.
259pub const MODIFIER_GAUSSIANS_BIND_GROUP_LAYOUT_DESCRIPTOR: wgpu::BindGroupLayoutDescriptor =
260 wgpu::BindGroupLayoutDescriptor {
261 label: Some("Modifier Gaussians Bind Group Layout"),
262 entries: &[
263 // Gaussians storage buffer
264 wgpu::BindGroupLayoutEntry {
265 binding: 0,
266 visibility: wgpu::ShaderStages::COMPUTE,
267 ty: wgpu::BindingType::Buffer {
268 ty: wgpu::BufferBindingType::Storage { read_only: false },
269 has_dynamic_offset: false,
270 min_binding_size: None,
271 },
272 count: None,
273 },
274 // Model transform uniform buffer
275 wgpu::BindGroupLayoutEntry {
276 binding: 1,
277 visibility: wgpu::ShaderStages::COMPUTE,
278 ty: wgpu::BindingType::Buffer {
279 ty: wgpu::BufferBindingType::Uniform,
280 has_dynamic_offset: false,
281 min_binding_size: None,
282 },
283 count: None,
284 },
285 // Gaussian transform uniform buffer
286 wgpu::BindGroupLayoutEntry {
287 binding: 2,
288 visibility: wgpu::ShaderStages::COMPUTE,
289 ty: wgpu::BindingType::Buffer {
290 ty: wgpu::BufferBindingType::Uniform,
291 has_dynamic_offset: false,
292 min_binding_size: None,
293 },
294 count: None,
295 },
296 ],
297 };
298
299/// A marker struct to indicate that a modifier takes a selection buffer.
300#[derive(Debug)]
301pub struct WithSelection;
302
303/// A marker struct to indicate that a modifier does not take a selection buffer.
304#[derive(Debug)]
305pub struct NoSelection;
306
307/// A specialized [`ComputeBundle`] for some built-in basic modifier.
308///
309/// This bundle includes the modifiers for [`BasicColorModifiersBuffer`],
310/// [`RotScaleBuffer`], and [`TransformFlagsBuffer`] (which provides flags for applying
311/// [`core::ModelTransformBuffer`] and [`core::GaussianTransformBuffer`]).
312#[derive(Debug)]
313pub struct BasicModifierBundle<G: GaussianPod, S = NoSelection, B = wgpu::BindGroup> {
314 bundle: ComputeBundle<B>,
315 gaussian_pod_marker: std::marker::PhantomData<G>,
316 selection_marker: std::marker::PhantomData<S>,
317}
318
319impl<G: GaussianPod, S, B> BasicModifierBundle<G, S, B> {
320 /// Gets the inner [`ComputeBundle`].
321 pub fn bundle(&self) -> &ComputeBundle<B> {
322 &self.bundle
323 }
324}
325
326impl<G: GaussianPod> BasicModifierBundle<G> {
327 /// The bind group layout descriptor for the [`BasicModifierBundle`].
328 ///
329 /// This bind group layout takes the following buffers:
330 /// - [`TransformFlagsBuffer`]
331 /// - [`BasicColorModifiersBuffer`]
332 /// - [`RotScaleBuffer`]
333 ///
334 /// This is at group 1, because group 0 is the [`MODIFIER_GAUSSIANS_BIND_GROUP_LAYOUT_DESCRIPTOR`].
335 pub const BIND_GROUP_LAYOUT_DESCRIPTOR: wgpu::BindGroupLayoutDescriptor<'static> =
336 wgpu::BindGroupLayoutDescriptor {
337 label: Some("Basic Modifier Bind Group Layout"),
338 entries: BasicModifierBundle::<G, WithSelection>::BIND_GROUP_LAYOUT_DESCRIPTOR
339 .entries
340 .split_at(3)
341 .0,
342 };
343
344 /// Creates a new [`BasicModifierBundle`] bundle.
345 pub fn new(
346 device: &wgpu::Device,
347 gaussians_buffer: &GaussiansBuffer<G>,
348 model_transform_buffer: &ModelTransformBuffer,
349 gaussian_transform_buffer: &GaussianTransformBuffer,
350 transform_flags_buffer: &TransformFlagsBuffer,
351 basic_color_modifiers_buffer: &BasicColorModifiersBuffer,
352 rot_scale_buffer: &RotScaleBuffer,
353 ) -> Self {
354 Self::create_bundle_builder(false)
355 .build(
356 device,
357 [
358 [
359 gaussians_buffer.buffer().as_entire_binding(),
360 model_transform_buffer.buffer().as_entire_binding(),
361 gaussian_transform_buffer.buffer().as_entire_binding(),
362 ],
363 [
364 transform_flags_buffer.buffer().as_entire_binding(),
365 basic_color_modifiers_buffer.buffer().as_entire_binding(),
366 rot_scale_buffer.buffer().as_entire_binding(),
367 ],
368 ],
369 )
370 .map(|bundle| Self {
371 bundle,
372 gaussian_pod_marker: std::marker::PhantomData,
373 selection_marker: std::marker::PhantomData,
374 })
375 .map_err(|e| log::error!("{e}"))
376 .expect("basic modifier bundle")
377 }
378
379 /// Creates a new [`ComputeBundleBuilder`] for the basic modifier.
380 fn create_bundle_builder<'a>(
381 has_selection: bool,
382 ) -> ComputeBundleBuilder<'a, wesl::PkgResolver> {
383 ComputeBundleBuilder::new()
384 .label("Basic Modifier")
385 .bind_group_layouts([
386 &MODIFIER_GAUSSIANS_BIND_GROUP_LAYOUT_DESCRIPTOR,
387 match has_selection {
388 true => &BasicModifierBundle::<G, WithSelection>::BIND_GROUP_LAYOUT_DESCRIPTOR,
389 false => &BasicModifierBundle::<G>::BIND_GROUP_LAYOUT_DESCRIPTOR,
390 },
391 ])
392 .resolver({
393 let mut resolver = wesl::PkgResolver::new();
394 resolver.add_package(&core::shader::PACKAGE);
395 resolver.add_package(&shader::PACKAGE);
396 resolver
397 })
398 .main_shader(
399 "wgpu_3dgs_editor::modifier::basic"
400 .parse()
401 .expect("modifier::basic module path"),
402 )
403 .entry_point("main")
404 .wesl_compile_options(wesl::CompileOptions {
405 features: wesl::Features {
406 flags: G::features()
407 .into_iter()
408 .chain(std::iter::once(("selection_buffer", has_selection)))
409 .map(|(k, v)| (k.to_string(), v.into()))
410 .collect(),
411 ..Default::default()
412 },
413 ..Default::default()
414 })
415 }
416}
417
418impl<G: GaussianPod> BasicModifierBundle<G, WithSelection> {
419 /// The bind group layout descriptor for the [`BasicModifierBundle`] with a [`SelectionBuffer`].
420 ///
421 /// Thie bind group layout takes the following buffers:
422 /// - [`TransformFlagsBuffer`]
423 /// - [`BasicColorModifiersBuffer`]
424 /// - [`RotScaleBuffer`]
425 /// - [`SelectionBuffer`]
426 ///
427 /// This is at group 1, because group 0 is the [`MODIFIER_GAUSSIANS_BIND_GROUP_LAYOUT_DESCRIPTOR`].
428 pub const BIND_GROUP_LAYOUT_DESCRIPTOR: wgpu::BindGroupLayoutDescriptor<'static> =
429 wgpu::BindGroupLayoutDescriptor {
430 label: Some("Basic Modifier Bind Group Layout"),
431 entries: &[
432 // Transform flags uniform buffer
433 wgpu::BindGroupLayoutEntry {
434 binding: 0,
435 visibility: wgpu::ShaderStages::COMPUTE,
436 ty: wgpu::BindingType::Buffer {
437 ty: wgpu::BufferBindingType::Uniform,
438 has_dynamic_offset: false,
439 min_binding_size: None,
440 },
441 count: None,
442 },
443 // Basic color modifiers uniform buffer
444 wgpu::BindGroupLayoutEntry {
445 binding: 1,
446 visibility: wgpu::ShaderStages::COMPUTE,
447 ty: wgpu::BindingType::Buffer {
448 ty: wgpu::BufferBindingType::Uniform,
449 has_dynamic_offset: false,
450 min_binding_size: None,
451 },
452 count: None,
453 },
454 // Scale rotation uniform buffer
455 wgpu::BindGroupLayoutEntry {
456 binding: 2,
457 visibility: wgpu::ShaderStages::COMPUTE,
458 ty: wgpu::BindingType::Buffer {
459 ty: wgpu::BufferBindingType::Uniform,
460 has_dynamic_offset: false,
461 min_binding_size: None,
462 },
463 count: None,
464 },
465 // Selection buffer
466 wgpu::BindGroupLayoutEntry {
467 binding: 3,
468 visibility: wgpu::ShaderStages::COMPUTE,
469 ty: wgpu::BindingType::Buffer {
470 ty: wgpu::BufferBindingType::Storage { read_only: true },
471 has_dynamic_offset: false,
472 min_binding_size: None,
473 },
474 count: None,
475 },
476 ],
477 };
478
479 /// Creates a new [`BasicModifierBundle`] bundle with [`SelectionBuffer`].
480 #[allow(clippy::too_many_arguments)]
481 pub fn new_with_selection(
482 device: &wgpu::Device,
483 gaussians_buffer: &GaussiansBuffer<G>,
484 model_transform_buffer: &ModelTransformBuffer,
485 gaussian_transform_buffer: &GaussianTransformBuffer,
486 transform_flags_buffer: &TransformFlagsBuffer,
487 basic_color_modifiers_buffer: &BasicColorModifiersBuffer,
488 rot_scale_buffer: &RotScaleBuffer,
489 selection_buffer: &SelectionBuffer,
490 ) -> Self {
491 BasicModifierBundle::<G>::create_bundle_builder(true)
492 .build(
493 device,
494 [
495 vec![
496 gaussians_buffer.buffer().as_entire_binding(),
497 model_transform_buffer.buffer().as_entire_binding(),
498 gaussian_transform_buffer.buffer().as_entire_binding(),
499 ],
500 vec![
501 transform_flags_buffer.buffer().as_entire_binding(),
502 basic_color_modifiers_buffer.buffer().as_entire_binding(),
503 rot_scale_buffer.buffer().as_entire_binding(),
504 selection_buffer.buffer().as_entire_binding(),
505 ],
506 ],
507 )
508 .map(|bundle| Self {
509 bundle,
510 gaussian_pod_marker: std::marker::PhantomData,
511 selection_marker: std::marker::PhantomData,
512 })
513 .map_err(|e| log::error!("{e}"))
514 .expect("basic modifier bundle")
515 }
516}
517
518impl<G: GaussianPod, S> BasicModifierBundle<G, S> {
519 /// Apply the basic modifier to the Gaussians.
520 pub fn apply_with_count(&self, encoder: &mut wgpu::CommandEncoder, gaussian_count: u32) {
521 self.bundle().dispatch(encoder, gaussian_count);
522 }
523}
524
525impl<G: GaussianPod, S> Modifier<G> for BasicModifierBundle<G, S> {
526 fn apply(
527 &self,
528 _device: &wgpu::Device,
529 encoder: &mut wgpu::CommandEncoder,
530 gaussians: &GaussiansBuffer<G>,
531 _model_transform: &ModelTransformBuffer,
532 _gaussian_transform: &GaussianTransformBuffer,
533 ) {
534 self.apply_with_count(encoder, gaussians.len() as u32);
535 }
536}
537
538impl<G: GaussianPod> BasicModifierBundle<G, NoSelection, ()> {
539 /// Creates a new [`BasicModifierBundle`] bundle without a bind group.
540 pub fn new_without_bind_group(device: &wgpu::Device) -> Self {
541 BasicModifierBundle::<G>::create_bundle_builder(false)
542 .build_without_bind_groups(device)
543 .map(|bundle| Self {
544 bundle,
545 gaussian_pod_marker: std::marker::PhantomData,
546 selection_marker: std::marker::PhantomData,
547 })
548 .expect("basic modifier bundle")
549 }
550}
551
552impl<G: GaussianPod> BasicModifierBundle<G, WithSelection, ()> {
553 /// Creates a new [`BasicModifierBundle`] bundle without a bind group with selection buffer.
554 pub fn new_without_bind_group_with_selection(device: &wgpu::Device) -> Self {
555 BasicModifierBundle::<G>::create_bundle_builder(true)
556 .build_without_bind_groups(device)
557 .map(|bundle| Self {
558 bundle,
559 gaussian_pod_marker: std::marker::PhantomData,
560 selection_marker: std::marker::PhantomData,
561 })
562 .expect("basic modifier bundle")
563 }
564}
565
566impl<G: GaussianPod, S> BasicModifierBundle<G, S, ()> {
567 /// Apply the basic modifier to the Gaussians.
568 ///
569 /// - `gaussians_bind_group` is the bind group created from [`MODIFIER_GAUSSIANS_BIND_GROUP_LAYOUT_DESCRIPTOR`].
570 /// - `bind_group` is the bind group created from [`BasicModifierBundle::BIND_GROUP_LAYOUT_DESCRIPTOR`].
571 pub fn apply_with_count(
572 &self,
573 encoder: &mut wgpu::CommandEncoder,
574 gaussians_bind_group: &wgpu::BindGroup,
575 bind_group: &wgpu::BindGroup,
576 gaussian_count: u32,
577 ) {
578 self.bundle()
579 .dispatch(encoder, gaussian_count, [gaussians_bind_group, bind_group]);
580 }
581}
582
583/// A struct to handle basic modifier.
584///
585/// This modifier holds a [`BasicModifierBundle`] along with necessary buffers, and applies the
586/// basic modifier.
587#[derive(Debug)]
588pub struct BasicModifier<G: GaussianPod, S = NoSelection> {
589 pub transform_flags_buffer: TransformFlagsBuffer,
590 pub basic_color_modifiers_buffer: BasicColorModifiersBuffer,
591 pub rot_scale_buffer: RotScaleBuffer,
592 pub modifier: BasicModifierBundle<G, S>,
593}
594
595impl<G: GaussianPod> BasicModifier<G> {
596 /// Create a new basic modifier.
597 pub fn new(
598 device: &wgpu::Device,
599 gaussians_buffer: &GaussiansBuffer<G>,
600 model_transform_buffer: &ModelTransformBuffer,
601 gaussian_transform_buffer: &GaussianTransformBuffer,
602 ) -> Self {
603 log::debug!("Creating transform flags buffer");
604 let transform_flags_buffer = TransformFlagsBuffer::new(device);
605
606 log::debug!("Creating basic color modifiers buffer");
607 let basic_color_modifiers_buffer = BasicColorModifiersBuffer::new(device);
608
609 log::debug!("Creating rotation scale buffer");
610 let rot_scale_buffer = RotScaleBuffer::new(device);
611
612 log::debug!("Creating basic modifier bundle");
613 let modifier = BasicModifierBundle::new(
614 device,
615 gaussians_buffer,
616 model_transform_buffer,
617 gaussian_transform_buffer,
618 &transform_flags_buffer,
619 &basic_color_modifiers_buffer,
620 &rot_scale_buffer,
621 );
622
623 log::debug!("Basic modifier created");
624
625 Self {
626 transform_flags_buffer,
627 basic_color_modifiers_buffer,
628 rot_scale_buffer,
629
630 modifier,
631 }
632 }
633}
634
635impl<G: GaussianPod> BasicModifier<G, WithSelection> {
636 /// Create a new basic modifier with selection.
637 pub fn new_with_selection(
638 device: &wgpu::Device,
639 gaussians_buffer: &GaussiansBuffer<G>,
640 model_transform_buffer: &ModelTransformBuffer,
641 gaussian_transform_buffer: &GaussianTransformBuffer,
642 selection_buffer: &SelectionBuffer,
643 ) -> Self {
644 log::debug!("Creating transform flags buffer");
645 let transform_flags_buffer = TransformFlagsBuffer::new(device);
646
647 log::debug!("Creating basic color modifiers buffer");
648 let basic_color_modifiers_buffer = BasicColorModifiersBuffer::new(device);
649
650 log::debug!("Creating rotation scale buffer");
651 let rot_scale_buffer = RotScaleBuffer::new(device);
652
653 log::debug!("Creating basic modifier bundle");
654 let modifier = BasicModifierBundle::new_with_selection(
655 device,
656 gaussians_buffer,
657 model_transform_buffer,
658 gaussian_transform_buffer,
659 &transform_flags_buffer,
660 &basic_color_modifiers_buffer,
661 &rot_scale_buffer,
662 selection_buffer,
663 );
664
665 log::debug!("Basic modifier created");
666
667 Self {
668 transform_flags_buffer,
669 basic_color_modifiers_buffer,
670 rot_scale_buffer,
671
672 modifier,
673 }
674 }
675}
676
677impl<G: GaussianPod, S> Modifier<G> for BasicModifier<G, S> {
678 fn apply(
679 &self,
680 device: &wgpu::Device,
681 encoder: &mut wgpu::CommandEncoder,
682 gaussians: &GaussiansBuffer<G>,
683 model_transform: &ModelTransformBuffer,
684 gaussian_transform: &GaussianTransformBuffer,
685 ) {
686 self.modifier.apply(
687 device,
688 encoder,
689 gaussians,
690 model_transform,
691 gaussian_transform,
692 );
693 }
694}