wgpu_3dgs_editor/selection_modifier.rs
1use crate::{
2 BasicModifier, Modifier, SelectionBuffer, SelectionBundle, SelectionExpr, WithSelection,
3 core::{
4 ComputeBundle, GaussianPod, GaussianTransformBuffer, GaussiansBuffer, ModelTransformBuffer,
5 },
6};
7
8/// A struct to handle custom selection and custom modifier together.
9///
10/// ## Overview
11///
12/// This modifier holdes a [`SelectionBundle`] and a [`Modifier`] along with necessary
13/// buffers, and applies the selection followed by the basic modifier in order.
14///
15/// The [`Modifier`] can use the [`SelectionModifier::selection_buffer`] to determine which
16/// Gaussians to modify.
17///
18/// ## Usage
19///
20/// You can supply your own selection bundles and modifier when creating a
21/// [`SelectionModifier`].
22///
23/// The creation expects a modifier factory function instead of a modifier,
24/// so that the modifier can be created with a reference to the selection buffer.
25///
26/// ```rust
27/// // Create your selection bundles
28/// let selection_bundles = vec![
29/// SelectionBundle::<GaussianPod>::create_sphere_bundle(&device), // The built-in sphere selection bundle as example
30/// ];
31///
32/// struct MyCustomModifier(ComputeBundle);
33///
34/// impl MyCustomModifier {
35/// pub fn new(device: &wgpu::Device, /* Your buffers */, selection: &SelectionBuffer) -> Self {
36/// // Build your compute bundle here,
37/// // and include the selection buffer to only modify selected Gaussians
38/// let compute_bundle = ComputeBundleBuilder::new().build(&device, /* Your buffers */);
39/// Self(compute_bundle)
40/// }
41/// }
42///
43/// impl Modifier<GaussianPod> for MyCustomModifier {
44/// fn apply(
45/// &self,
46/// device: &wgpu::Device,
47/// encoder: &mut wgpu::CommandEncoder,
48/// gaussians: &GaussiansBuffer<GaussianPod>,
49/// model_transform: &ModelTransformBuffer,
50/// gaussian_transform: &GaussianTransformBuffer,
51/// ) {
52/// self.0.dispatch(encoder, gaussians.len() as u32);
53/// }
54/// }
55///
56/// let selection_modifier = SelectionModifier::new(
57/// &device,
58/// &gaussians_buffer,
59/// selection_bundles,
60/// |selection_buffer| { // The factory closure
61/// BasicModifier::new_with_selection(
62/// device,
63/// // Your buffers,
64/// selection_buffer,
65/// )
66/// },
67/// );
68/// ```
69///
70/// Alternatively, you can use a modifier closure instead of a struct (but be reminded this could
71/// harm readability of your code).
72///
73/// ```rust
74/// let selection_modifier = SelectionModifier::<GaussianPod>::new(
75/// &device,
76/// &gaussians_buffer,
77/// selection_bundles,
78/// |selection_buffer| { // The factory closure
79/// // Build your compute bundle here,
80/// // and include the selection buffer to only modify selected Gaussians
81/// let modifier_bundle = ComputeBundleBuilder::new().build(&device, /* Your buffers */);
82///
83/// // This function signature has blanket impl of the modifier trait
84/// move |_device: &wgpu::Device,
85/// encoder: &mut wgpu::CommandEncoder,
86/// gaussians: &gs::core::GaussiansBuffer<GaussianPod>,
87/// _model_transform: &gs::core::ModelTransformBuffer,
88/// _gaussian_transform: &gs::core::GaussianTransformBuffer| {
89/// modifier_bundle.dispatch(encoder, gaussians.len() as u32);
90/// }
91/// },
92/// );
93/// ``````
94#[derive(Debug)]
95pub struct SelectionModifier<G: GaussianPod, M: Modifier<G>> {
96 pub selection_expr: SelectionExpr,
97 pub selection_buffer: SelectionBuffer,
98 pub selection: SelectionBundle<G>,
99 pub modifier: M,
100}
101
102impl<G: GaussianPod, M: Modifier<G>> SelectionModifier<G, M> {
103 /// Create a new selection modifier.
104 ///
105 /// `bundles` are used for [`SelectionExpr::Unary`], [`SelectionExpr::Binary`], or
106 /// [`SelectionExpr::Selection`], they must have the same bind group 0 as the
107 /// [`SelectionBundle::GAUSSIANS_BIND_GROUP_LAYOUT_DESCRIPTOR`], see documentation of
108 /// [`SelectionBundle`] for more details.
109 pub fn new(
110 device: &wgpu::Device,
111 gaussians_buffer: &GaussiansBuffer<G>,
112 selection_bundles: Vec<ComputeBundle<()>>,
113 modifier: impl FnOnce(&SelectionBuffer) -> M,
114 ) -> Self {
115 log::debug!("Creating selection buffer");
116 let selection_buffer = SelectionBuffer::new(device, gaussians_buffer.len() as u32);
117
118 log::debug!("Creating selection bundle");
119 let selection = SelectionBundle::<G>::new(device, selection_bundles);
120
121 log::debug!("Creating modifier");
122 let modifier = modifier(&selection_buffer);
123
124 log::debug!("Creating selection modifier");
125
126 Self {
127 selection_expr: SelectionExpr::default(),
128 selection_buffer,
129 selection,
130 modifier,
131 }
132 }
133
134 /// Apply the selection and the modifier with the given expression and buffer.
135 ///
136 /// [`SelectionModifier::apply`] is the equivalent of applying this function with
137 /// [`SelectionModifier::selection_expr`] and [`SelectionModifier::selection_buffer`].
138 pub fn apply_with(
139 &self,
140 device: &wgpu::Device,
141 encoder: &mut wgpu::CommandEncoder,
142 gaussians: &GaussiansBuffer<G>,
143 model_transform: &ModelTransformBuffer,
144 gaussian_transform: &GaussianTransformBuffer,
145 selection_expr: &SelectionExpr,
146 selection_buffer: &SelectionBuffer,
147 ) {
148 self.selection.evaluate(
149 device,
150 encoder,
151 selection_expr,
152 selection_buffer,
153 model_transform,
154 gaussian_transform,
155 gaussians,
156 );
157
158 self.modifier.apply(
159 device,
160 encoder,
161 gaussians,
162 model_transform,
163 gaussian_transform,
164 );
165 }
166}
167
168impl<G: GaussianPod, M: Modifier<G>> Modifier<G> for SelectionModifier<G, M> {
169 fn apply(
170 &self,
171 device: &wgpu::Device,
172 encoder: &mut wgpu::CommandEncoder,
173 gaussians: &GaussiansBuffer<G>,
174 model_transform: &ModelTransformBuffer,
175 gaussian_transform: &GaussianTransformBuffer,
176 ) {
177 self.apply_with(
178 device,
179 encoder,
180 gaussians,
181 model_transform,
182 gaussian_transform,
183 &self.selection_expr,
184 &self.selection_buffer,
185 );
186 }
187}
188
189/// A type alias of [`SelectionModifier`] with [`BasicModifier`].
190pub type BasicSelectionModifier<G> = SelectionModifier<G, BasicModifier<G, WithSelection>>;
191
192impl<G: GaussianPod> BasicSelectionModifier<G> {
193 /// Create a new selection modifier with [`BasicModifier`].
194 ///
195 /// `bundles` are used for [`SelectionExpr::Unary`], [`SelectionExpr::Binary`], or
196 /// [`SelectionExpr::Selection`], they must have the same bind group 0 as the
197 /// [`SelectionBundle::GAUSSIANS_BIND_GROUP_LAYOUT_DESCRIPTOR`], see documentation of
198 /// [`SelectionBundle`] for more details.
199 pub fn new_with_basic_modifier(
200 device: &wgpu::Device,
201 gaussians_buffer: &GaussiansBuffer<G>,
202 model_transform: &ModelTransformBuffer,
203 gaussian_transform: &GaussianTransformBuffer,
204 selection_bundles: Vec<ComputeBundle<()>>,
205 ) -> Self {
206 Self::new(
207 device,
208 gaussians_buffer,
209 selection_bundles,
210 |selection_buffer| {
211 BasicModifier::new_with_selection(
212 device,
213 gaussians_buffer,
214 model_transform,
215 gaussian_transform,
216 selection_buffer,
217 )
218 },
219 )
220 }
221}