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