SelectionExpr

Enum SelectionExpr 

Source
pub enum SelectionExpr {
    Identity,
    Union(Box<SelectionExpr>, Box<SelectionExpr>),
    Intersection(Box<SelectionExpr>, Box<SelectionExpr>),
    Difference(Box<SelectionExpr>, Box<SelectionExpr>),
    SymmetricDifference(Box<SelectionExpr>, Box<SelectionExpr>),
    Complement(Box<SelectionExpr>),
    Unary(usize, Box<SelectionExpr>, Vec<BindGroup>),
    Binary(Box<SelectionExpr>, usize, Box<SelectionExpr>, Vec<BindGroup>),
    Selection(usize, Vec<BindGroup>),
    Buffer(SelectionBuffer),
}
Expand description

A selection expression tree.

§Overview

This can be used to carry out operations on selection buffers, these operations are evaluated by SelectionBundle::evaluate in a recursive manner (depth-first).

§Custom Operations

SelectionExpr::Unary, SelectionExpr::Binary, and SelectionExpr::Selection are custom operations that can be defined with additional ComputeBundles, so they also carry a vector of bind groups that are used in the operation when dispatched/evaluated. These vectors should correspond to the selection bundle’s bind groups starting at index 1, because index 0 must be defined by SelectionBundle::GAUSSIANS_BIND_GROUP_LAYOUT_DESCRIPTOR.

Variants§

§

Identity

Apply an identity operation.

§

Union(Box<SelectionExpr>, Box<SelectionExpr>)

Union of the two selections.

§

Intersection(Box<SelectionExpr>, Box<SelectionExpr>)

Interaction of the two selections.

§

Difference(Box<SelectionExpr>, Box<SelectionExpr>)

Difference of the two selections.

§

SymmetricDifference(Box<SelectionExpr>, Box<SelectionExpr>)

Symmetric difference of the two selections.

§

Complement(Box<SelectionExpr>)

Complement of the selection.

§

Unary(usize, Box<SelectionExpr>, Vec<BindGroup>)

Apply a custom unary operation.

§

Binary(Box<SelectionExpr>, usize, Box<SelectionExpr>, Vec<BindGroup>)

Apply a custom binary operation.

§

Selection(usize, Vec<BindGroup>)

Create a selection.

§

Buffer(SelectionBuffer)

Directly use a selection buffer.

Implementations§

Source§

impl SelectionExpr

Source

pub const CUSTOM_OP_START: u32 = 5u32

The first u32 value for a custom operation.

Source

pub fn identity() -> Self

Source

pub fn union(self, other: Self) -> Self

Create a new SelectionExpr::Union.

Examples found in repository?
examples/filter_selection.rs (lines 186-189)
98async fn main() {
99    env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init();
100
101    let args = Args::parse();
102    let model_path = &args.model;
103    let pos = Vec3::from_slice(&args.pos);
104    let rot = Quat::from_slice(&args.rot);
105    let scale = Vec3::from_slice(&args.scale);
106    let shape = match args.shape {
107        Shape::Sphere => gs::SelectionBundle::<GaussianPod>::create_sphere_bundle,
108        Shape::Box => gs::SelectionBundle::<GaussianPod>::create_box_bundle,
109    };
110    let repeat = args.repeat;
111    let offset = Vec3::from_slice(&args.offset);
112
113    log::debug!("Creating wgpu instance");
114    let instance = wgpu::Instance::new(&wgpu::InstanceDescriptor::default());
115
116    log::debug!("Requesting adapter");
117    let adapter = instance
118        .request_adapter(&wgpu::RequestAdapterOptions::default())
119        .await
120        .expect("adapter");
121
122    log::debug!("Requesting device");
123    let (device, queue) = adapter
124        .request_device(&wgpu::DeviceDescriptor {
125            label: Some("Device"),
126            required_limits: adapter.limits(),
127            ..Default::default()
128        })
129        .await
130        .expect("device");
131
132    log::debug!("Creating gaussians");
133    let gaussians = [
134        gs::core::GaussiansSource::Ply,
135        gs::core::GaussiansSource::Spz,
136    ]
137    .into_iter()
138    .find_map(|source| gs::core::Gaussians::read_from_file(model_path, source).ok())
139    .expect("gaussians");
140
141    log::debug!("Creating gaussians buffer");
142    let gaussians_buffer = gs::core::GaussiansBuffer::<GaussianPod>::new(&device, &gaussians);
143
144    log::debug!("Creating model transform buffer");
145    let model_transform = gs::core::ModelTransformBuffer::new(&device);
146
147    log::debug!("Creating Gaussian transform buffer");
148    let gaussian_transform = gs::core::GaussianTransformBuffer::new(&device);
149
150    log::debug!("Creating shape selection compute bundle");
151    let shape_selection = shape(&device);
152
153    log::debug!("Creating selection bundle");
154    let selection_bundle = gs::SelectionBundle::<GaussianPod>::new(&device, vec![shape_selection]);
155
156    log::debug!("Creating shape selection buffers");
157    let shape_selection_buffers = (0..repeat)
158        .map(|i| {
159            let offset_pos = pos + offset * i as f32;
160            let buffer = gs::InvTransformBuffer::new(&device);
161            buffer.update_with_scale_rot_pos(&queue, scale, rot, offset_pos);
162            buffer
163        })
164        .collect::<Vec<_>>();
165
166    log::debug!("Creating shape selection bind groups");
167    let shape_selection_bind_groups = shape_selection_buffers
168        .iter()
169        .map(|buffer| {
170            selection_bundle.bundles[0]
171                .create_bind_group(
172                    &device,
173                    // index 0 is the Gaussians buffer, so we use 1,
174                    // see docs of create_sphere_bundle or create_box_bundle
175                    1,
176                    [buffer.buffer().as_entire_binding()],
177                )
178                .expect("bind group")
179        })
180        .collect::<Vec<_>>();
181
182    log::debug!("Creating selection expression");
183    let selection_expr = shape_selection_bind_groups.into_iter().fold(
184        gs::SelectionExpr::Identity,
185        |acc, bind_group| {
186            acc.union(gs::SelectionExpr::selection(
187                0, // the 0 here is the bundle index in the selection bundle
188                vec![bind_group],
189            ))
190        },
191    );
192
193    log::debug!("Creating destination buffer");
194    let dest = gs::SelectionBuffer::new(&device, gaussians_buffer.len() as u32);
195
196    log::info!("Starting selection process");
197    let time = std::time::Instant::now();
198
199    log::debug!("Selecting Gaussians");
200    let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
201        label: Some("Selection Encoder"),
202    });
203
204    selection_bundle.evaluate(
205        &device,
206        &mut encoder,
207        &selection_expr,
208        &dest,
209        &model_transform,
210        &gaussian_transform,
211        &gaussians_buffer,
212    );
213
214    queue.submit(Some(encoder.finish()));
215
216    device
217        .poll(wgpu::PollType::wait_indefinitely())
218        .expect("poll");
219
220    log::info!("Editing process completed in {:?}", time.elapsed());
221
222    log::debug!("Filtering Gaussians");
223    let selected_gaussians = dest
224        .download::<u32>(&device, &queue)
225        .await
226        .expect("selected download")
227        .iter()
228        .flat_map(|group| {
229            std::iter::repeat_n(group, 32)
230                .enumerate()
231                .map(|(i, g)| g & (1 << i) != 0)
232        })
233        .zip(gaussians.iter_gaussian())
234        .filter(|(selected, _)| *selected)
235        .map(|(_, g)| g)
236        .collect::<Vec<_>>();
237
238    let selected_gaussians = match &args.output[args.output.len().saturating_sub(4)..] {
239        ".ply" => gs::core::Gaussians::Ply(gs::core::PlyGaussians::from_iter(
240            selected_gaussians.into_iter(),
241        )),
242        ".spz" => {
243            gs::core::Gaussians::Spz(
244                gs::core::SpzGaussians::from_gaussians_with_options(
245                    selected_gaussians,
246                    &gs::core::SpzGaussiansFromGaussianSliceOptions {
247                        version: 2, // Version 2 is more widely supported as of now
248                        ..Default::default()
249                    },
250                )
251                .expect("SpzGaussians from gaussians"),
252            )
253        }
254        _ => panic!("Unsupported output file extension, expected .ply or .spz"),
255    };
256
257    log::debug!("Writing modified Gaussians to output file");
258    selected_gaussians
259        .write_to_file(&args.output)
260        .expect("write modified Gaussians to output file");
261
262    log::info!("Filtered Gaussians written to {}", args.output);
263}
More examples
Hide additional examples
examples/modify_selection.rs (lines 241-244)
137async fn main() {
138    env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init();
139
140    let args = Args::parse();
141    let model_path = &args.model;
142    let pos = Vec3::from_slice(&args.pos);
143    let rot = Quat::from_slice(&args.rot);
144    let scale = Vec3::from_slice(&args.scale);
145    let shape = match args.shape {
146        Shape::Sphere => gs::SelectionBundle::<GaussianPod>::create_sphere_bundle,
147        Shape::Box => gs::SelectionBundle::<GaussianPod>::create_box_bundle,
148    };
149    let repeat = args.repeat;
150    let offset = Vec3::from_slice(&args.offset);
151
152    log::debug!("Creating wgpu instance");
153    let instance = wgpu::Instance::new(&wgpu::InstanceDescriptor::default());
154
155    log::debug!("Requesting adapter");
156    let adapter = instance
157        .request_adapter(&wgpu::RequestAdapterOptions::default())
158        .await
159        .expect("adapter");
160
161    log::debug!("Requesting device");
162    let (device, queue) = adapter
163        .request_device(&wgpu::DeviceDescriptor {
164            label: Some("Device"),
165            required_limits: adapter.limits(),
166            ..Default::default()
167        })
168        .await
169        .expect("device");
170
171    log::debug!("Creating gaussians");
172    let gaussians = [
173        gs::core::GaussiansSource::Ply,
174        gs::core::GaussiansSource::Spz,
175    ]
176    .into_iter()
177    .find_map(|source| gs::core::Gaussians::read_from_file(model_path, source).ok())
178    .expect("gaussians");
179
180    log::debug!("Creating editor");
181    let editor = gs::Editor::<GaussianPod>::new(&device, &gaussians);
182
183    log::debug!("Creating shape selection compute bundle");
184    let shape_selection = shape(&device);
185
186    log::debug!("Creating basic selection modifier");
187    let mut basic_selection_modifier = gs::SelectionModifier::new_with_basic_modifier(
188        &device,
189        &editor.gaussians_buffer,
190        &editor.model_transform_buffer,
191        &editor.gaussian_transform_buffer,
192        vec![shape_selection],
193    );
194
195    log::debug!("Configuring modifiers");
196    basic_selection_modifier
197        .modifier
198        .basic_color_modifiers_buffer
199        .update(
200            &queue,
201            match args.override_rgb {
202                true => gs::BasicColorRgbOverrideOrHsvModifiersPod::new_rgb_override,
203                false => gs::BasicColorRgbOverrideOrHsvModifiersPod::new_hsv_modifiers,
204            }(Vec3::from_slice(&args.rgb_or_hsv)),
205            args.alpha,
206            args.contrast,
207            args.exposure,
208            args.gamma,
209        );
210
211    log::debug!("Creating shape selection buffers");
212    let shape_selection_buffers = (0..repeat)
213        .map(|i| {
214            let offset_pos = pos + offset * i as f32;
215            let buffer = gs::InvTransformBuffer::new(&device);
216            buffer.update_with_scale_rot_pos(&queue, scale, rot, offset_pos);
217            buffer
218        })
219        .collect::<Vec<_>>();
220
221    log::debug!("Creating shape selection bind groups");
222    let shape_selection_bind_groups = shape_selection_buffers
223        .iter()
224        .map(|buffer| {
225            basic_selection_modifier.selection.bundles[0]
226                .create_bind_group(
227                    &device,
228                    // index 0 is the Gaussians buffer, so we use 1,
229                    // see docs of create_sphere_bundle or create_box_bundle
230                    1,
231                    [buffer.buffer().as_entire_binding()],
232                )
233                .expect("bind group")
234        })
235        .collect::<Vec<_>>();
236
237    log::debug!("Creating selection expression");
238    basic_selection_modifier.selection_expr = shape_selection_bind_groups.into_iter().fold(
239        gs::SelectionExpr::Identity,
240        |acc, bind_group| {
241            acc.union(gs::SelectionExpr::selection(
242                0, // the 0 here is the bundle index in the selection bundle
243                vec![bind_group],
244            ))
245        },
246    );
247
248    log::info!("Starting editing process");
249    let time = std::time::Instant::now();
250
251    log::debug!("Editing Gaussians");
252    let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
253        label: Some("Edit Encoder"),
254    });
255
256    editor.apply(
257        &device,
258        &mut encoder,
259        [&basic_selection_modifier as &dyn gs::Modifier<GaussianPod>],
260    );
261
262    queue.submit(Some(encoder.finish()));
263
264    device
265        .poll(wgpu::PollType::wait_indefinitely())
266        .expect("poll");
267
268    log::info!("Editing process completed in {:?}", time.elapsed());
269
270    log::debug!("Downloading Gaussians");
271    let modified_gaussians = editor
272        .gaussians_buffer
273        .download_gaussians(&device, &queue)
274        .await
275        .map(|gs| {
276            match &args.output[args.output.len().saturating_sub(4)..] {
277                ".ply" => {
278                    gs::core::Gaussians::Ply(gs::core::PlyGaussians::from_iter(gs.into_iter()))
279                }
280                ".spz" => {
281                    gs::core::Gaussians::Spz(
282                        gs::core::SpzGaussians::from_gaussians_with_options(
283                            gs,
284                            &gs::core::SpzGaussiansFromGaussianSliceOptions {
285                                version: 2, // Version 2 is more widely supported as of now
286                                ..Default::default()
287                            },
288                        )
289                        .expect("SpzGaussians from gaussians"),
290                    )
291                }
292                _ => panic!("Unsupported output file extension, expected .ply or .spz"),
293            }
294        })
295        .expect("gaussians download");
296
297    log::debug!("Writing modified Gaussians to output file");
298    modified_gaussians
299        .write_to_file(&args.output)
300        .expect("write modified Gaussians to output file");
301
302    log::info!("Modified Gaussians written to {}", args.output);
303}
Source

pub fn intersection(self, other: Self) -> Self

Source

pub fn difference(self, other: Self) -> Self

Source

pub fn symmetric_difference(self, other: Self) -> Self

Source

pub fn complement(self) -> Self

Source

pub fn unary(self, op: usize, bind_groups: Vec<BindGroup>) -> Self

Create a new SelectionExpr::Unary.

Source

pub fn binary(self, op: usize, other: Self, bind_groups: Vec<BindGroup>) -> Self

Create a new SelectionExpr::Binary.

Source

pub fn selection(op: usize, bind_groups: Vec<BindGroup>) -> Self

Examples found in repository?
examples/filter_selection.rs (lines 186-189)
98async fn main() {
99    env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init();
100
101    let args = Args::parse();
102    let model_path = &args.model;
103    let pos = Vec3::from_slice(&args.pos);
104    let rot = Quat::from_slice(&args.rot);
105    let scale = Vec3::from_slice(&args.scale);
106    let shape = match args.shape {
107        Shape::Sphere => gs::SelectionBundle::<GaussianPod>::create_sphere_bundle,
108        Shape::Box => gs::SelectionBundle::<GaussianPod>::create_box_bundle,
109    };
110    let repeat = args.repeat;
111    let offset = Vec3::from_slice(&args.offset);
112
113    log::debug!("Creating wgpu instance");
114    let instance = wgpu::Instance::new(&wgpu::InstanceDescriptor::default());
115
116    log::debug!("Requesting adapter");
117    let adapter = instance
118        .request_adapter(&wgpu::RequestAdapterOptions::default())
119        .await
120        .expect("adapter");
121
122    log::debug!("Requesting device");
123    let (device, queue) = adapter
124        .request_device(&wgpu::DeviceDescriptor {
125            label: Some("Device"),
126            required_limits: adapter.limits(),
127            ..Default::default()
128        })
129        .await
130        .expect("device");
131
132    log::debug!("Creating gaussians");
133    let gaussians = [
134        gs::core::GaussiansSource::Ply,
135        gs::core::GaussiansSource::Spz,
136    ]
137    .into_iter()
138    .find_map(|source| gs::core::Gaussians::read_from_file(model_path, source).ok())
139    .expect("gaussians");
140
141    log::debug!("Creating gaussians buffer");
142    let gaussians_buffer = gs::core::GaussiansBuffer::<GaussianPod>::new(&device, &gaussians);
143
144    log::debug!("Creating model transform buffer");
145    let model_transform = gs::core::ModelTransformBuffer::new(&device);
146
147    log::debug!("Creating Gaussian transform buffer");
148    let gaussian_transform = gs::core::GaussianTransformBuffer::new(&device);
149
150    log::debug!("Creating shape selection compute bundle");
151    let shape_selection = shape(&device);
152
153    log::debug!("Creating selection bundle");
154    let selection_bundle = gs::SelectionBundle::<GaussianPod>::new(&device, vec![shape_selection]);
155
156    log::debug!("Creating shape selection buffers");
157    let shape_selection_buffers = (0..repeat)
158        .map(|i| {
159            let offset_pos = pos + offset * i as f32;
160            let buffer = gs::InvTransformBuffer::new(&device);
161            buffer.update_with_scale_rot_pos(&queue, scale, rot, offset_pos);
162            buffer
163        })
164        .collect::<Vec<_>>();
165
166    log::debug!("Creating shape selection bind groups");
167    let shape_selection_bind_groups = shape_selection_buffers
168        .iter()
169        .map(|buffer| {
170            selection_bundle.bundles[0]
171                .create_bind_group(
172                    &device,
173                    // index 0 is the Gaussians buffer, so we use 1,
174                    // see docs of create_sphere_bundle or create_box_bundle
175                    1,
176                    [buffer.buffer().as_entire_binding()],
177                )
178                .expect("bind group")
179        })
180        .collect::<Vec<_>>();
181
182    log::debug!("Creating selection expression");
183    let selection_expr = shape_selection_bind_groups.into_iter().fold(
184        gs::SelectionExpr::Identity,
185        |acc, bind_group| {
186            acc.union(gs::SelectionExpr::selection(
187                0, // the 0 here is the bundle index in the selection bundle
188                vec![bind_group],
189            ))
190        },
191    );
192
193    log::debug!("Creating destination buffer");
194    let dest = gs::SelectionBuffer::new(&device, gaussians_buffer.len() as u32);
195
196    log::info!("Starting selection process");
197    let time = std::time::Instant::now();
198
199    log::debug!("Selecting Gaussians");
200    let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
201        label: Some("Selection Encoder"),
202    });
203
204    selection_bundle.evaluate(
205        &device,
206        &mut encoder,
207        &selection_expr,
208        &dest,
209        &model_transform,
210        &gaussian_transform,
211        &gaussians_buffer,
212    );
213
214    queue.submit(Some(encoder.finish()));
215
216    device
217        .poll(wgpu::PollType::wait_indefinitely())
218        .expect("poll");
219
220    log::info!("Editing process completed in {:?}", time.elapsed());
221
222    log::debug!("Filtering Gaussians");
223    let selected_gaussians = dest
224        .download::<u32>(&device, &queue)
225        .await
226        .expect("selected download")
227        .iter()
228        .flat_map(|group| {
229            std::iter::repeat_n(group, 32)
230                .enumerate()
231                .map(|(i, g)| g & (1 << i) != 0)
232        })
233        .zip(gaussians.iter_gaussian())
234        .filter(|(selected, _)| *selected)
235        .map(|(_, g)| g)
236        .collect::<Vec<_>>();
237
238    let selected_gaussians = match &args.output[args.output.len().saturating_sub(4)..] {
239        ".ply" => gs::core::Gaussians::Ply(gs::core::PlyGaussians::from_iter(
240            selected_gaussians.into_iter(),
241        )),
242        ".spz" => {
243            gs::core::Gaussians::Spz(
244                gs::core::SpzGaussians::from_gaussians_with_options(
245                    selected_gaussians,
246                    &gs::core::SpzGaussiansFromGaussianSliceOptions {
247                        version: 2, // Version 2 is more widely supported as of now
248                        ..Default::default()
249                    },
250                )
251                .expect("SpzGaussians from gaussians"),
252            )
253        }
254        _ => panic!("Unsupported output file extension, expected .ply or .spz"),
255    };
256
257    log::debug!("Writing modified Gaussians to output file");
258    selected_gaussians
259        .write_to_file(&args.output)
260        .expect("write modified Gaussians to output file");
261
262    log::info!("Filtered Gaussians written to {}", args.output);
263}
More examples
Hide additional examples
examples/modify_selection.rs (lines 241-244)
137async fn main() {
138    env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init();
139
140    let args = Args::parse();
141    let model_path = &args.model;
142    let pos = Vec3::from_slice(&args.pos);
143    let rot = Quat::from_slice(&args.rot);
144    let scale = Vec3::from_slice(&args.scale);
145    let shape = match args.shape {
146        Shape::Sphere => gs::SelectionBundle::<GaussianPod>::create_sphere_bundle,
147        Shape::Box => gs::SelectionBundle::<GaussianPod>::create_box_bundle,
148    };
149    let repeat = args.repeat;
150    let offset = Vec3::from_slice(&args.offset);
151
152    log::debug!("Creating wgpu instance");
153    let instance = wgpu::Instance::new(&wgpu::InstanceDescriptor::default());
154
155    log::debug!("Requesting adapter");
156    let adapter = instance
157        .request_adapter(&wgpu::RequestAdapterOptions::default())
158        .await
159        .expect("adapter");
160
161    log::debug!("Requesting device");
162    let (device, queue) = adapter
163        .request_device(&wgpu::DeviceDescriptor {
164            label: Some("Device"),
165            required_limits: adapter.limits(),
166            ..Default::default()
167        })
168        .await
169        .expect("device");
170
171    log::debug!("Creating gaussians");
172    let gaussians = [
173        gs::core::GaussiansSource::Ply,
174        gs::core::GaussiansSource::Spz,
175    ]
176    .into_iter()
177    .find_map(|source| gs::core::Gaussians::read_from_file(model_path, source).ok())
178    .expect("gaussians");
179
180    log::debug!("Creating editor");
181    let editor = gs::Editor::<GaussianPod>::new(&device, &gaussians);
182
183    log::debug!("Creating shape selection compute bundle");
184    let shape_selection = shape(&device);
185
186    log::debug!("Creating basic selection modifier");
187    let mut basic_selection_modifier = gs::SelectionModifier::new_with_basic_modifier(
188        &device,
189        &editor.gaussians_buffer,
190        &editor.model_transform_buffer,
191        &editor.gaussian_transform_buffer,
192        vec![shape_selection],
193    );
194
195    log::debug!("Configuring modifiers");
196    basic_selection_modifier
197        .modifier
198        .basic_color_modifiers_buffer
199        .update(
200            &queue,
201            match args.override_rgb {
202                true => gs::BasicColorRgbOverrideOrHsvModifiersPod::new_rgb_override,
203                false => gs::BasicColorRgbOverrideOrHsvModifiersPod::new_hsv_modifiers,
204            }(Vec3::from_slice(&args.rgb_or_hsv)),
205            args.alpha,
206            args.contrast,
207            args.exposure,
208            args.gamma,
209        );
210
211    log::debug!("Creating shape selection buffers");
212    let shape_selection_buffers = (0..repeat)
213        .map(|i| {
214            let offset_pos = pos + offset * i as f32;
215            let buffer = gs::InvTransformBuffer::new(&device);
216            buffer.update_with_scale_rot_pos(&queue, scale, rot, offset_pos);
217            buffer
218        })
219        .collect::<Vec<_>>();
220
221    log::debug!("Creating shape selection bind groups");
222    let shape_selection_bind_groups = shape_selection_buffers
223        .iter()
224        .map(|buffer| {
225            basic_selection_modifier.selection.bundles[0]
226                .create_bind_group(
227                    &device,
228                    // index 0 is the Gaussians buffer, so we use 1,
229                    // see docs of create_sphere_bundle or create_box_bundle
230                    1,
231                    [buffer.buffer().as_entire_binding()],
232                )
233                .expect("bind group")
234        })
235        .collect::<Vec<_>>();
236
237    log::debug!("Creating selection expression");
238    basic_selection_modifier.selection_expr = shape_selection_bind_groups.into_iter().fold(
239        gs::SelectionExpr::Identity,
240        |acc, bind_group| {
241            acc.union(gs::SelectionExpr::selection(
242                0, // the 0 here is the bundle index in the selection bundle
243                vec![bind_group],
244            ))
245        },
246    );
247
248    log::info!("Starting editing process");
249    let time = std::time::Instant::now();
250
251    log::debug!("Editing Gaussians");
252    let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
253        label: Some("Edit Encoder"),
254    });
255
256    editor.apply(
257        &device,
258        &mut encoder,
259        [&basic_selection_modifier as &dyn gs::Modifier<GaussianPod>],
260    );
261
262    queue.submit(Some(encoder.finish()));
263
264    device
265        .poll(wgpu::PollType::wait_indefinitely())
266        .expect("poll");
267
268    log::info!("Editing process completed in {:?}", time.elapsed());
269
270    log::debug!("Downloading Gaussians");
271    let modified_gaussians = editor
272        .gaussians_buffer
273        .download_gaussians(&device, &queue)
274        .await
275        .map(|gs| {
276            match &args.output[args.output.len().saturating_sub(4)..] {
277                ".ply" => {
278                    gs::core::Gaussians::Ply(gs::core::PlyGaussians::from_iter(gs.into_iter()))
279                }
280                ".spz" => {
281                    gs::core::Gaussians::Spz(
282                        gs::core::SpzGaussians::from_gaussians_with_options(
283                            gs,
284                            &gs::core::SpzGaussiansFromGaussianSliceOptions {
285                                version: 2, // Version 2 is more widely supported as of now
286                                ..Default::default()
287                            },
288                        )
289                        .expect("SpzGaussians from gaussians"),
290                    )
291                }
292                _ => panic!("Unsupported output file extension, expected .ply or .spz"),
293            }
294        })
295        .expect("gaussians download");
296
297    log::debug!("Writing modified Gaussians to output file");
298    modified_gaussians
299        .write_to_file(&args.output)
300        .expect("write modified Gaussians to output file");
301
302    log::info!("Modified Gaussians written to {}", args.output);
303}
examples/custom_modify_selection.rs (lines 329-343)
68async fn main() {
69    env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init();
70
71    let args = Args::parse();
72    let model_path = &args.model;
73    let pos = Vec3::from_slice(&args.pos);
74    let radius = args.radius;
75
76    log::debug!("Creating wgpu instance");
77    let instance = wgpu::Instance::new(&wgpu::InstanceDescriptor::default());
78
79    log::debug!("Requesting adapter");
80    let adapter = instance
81        .request_adapter(&wgpu::RequestAdapterOptions::default())
82        .await
83        .expect("adapter");
84
85    log::debug!("Requesting device");
86    let (device, queue) = adapter
87        .request_device(&wgpu::DeviceDescriptor {
88            label: Some("Device"),
89            required_limits: adapter.limits(),
90            ..Default::default()
91        })
92        .await
93        .expect("device");
94
95    log::debug!("Creating gaussians");
96    let gaussians = [
97        gs::core::GaussiansSource::Ply,
98        gs::core::GaussiansSource::Spz,
99    ]
100    .into_iter()
101    .find_map(|source| gs::core::Gaussians::read_from_file(model_path, source).ok())
102    .expect("gaussians");
103
104    log::debug!("Creating editor");
105    let editor = gs::Editor::<GaussianPod>::new(&device, &gaussians);
106
107    log::debug!("Creating buffers");
108    let pos_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
109        label: Some("Position Buffer"),
110        contents: bytemuck::bytes_of(&pos),
111        usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
112    });
113
114    let radius_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
115        label: Some("Radius Buffer"),
116        contents: bytemuck::bytes_of(&radius),
117        usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
118    });
119
120    const BIND_GROUP_LAYOUT_DESCRIPTOR: wgpu::BindGroupLayoutDescriptor =
121        wgpu::BindGroupLayoutDescriptor {
122            label: Some("Bind Group Layout"),
123            entries: &[
124                // Position uniform buffer
125                wgpu::BindGroupLayoutEntry {
126                    binding: 0,
127                    visibility: wgpu::ShaderStages::COMPUTE,
128                    ty: wgpu::BindingType::Buffer {
129                        ty: wgpu::BufferBindingType::Uniform,
130                        has_dynamic_offset: false,
131                        min_binding_size: None,
132                    },
133                    count: None,
134                },
135                // Radius uniform buffer
136                wgpu::BindGroupLayoutEntry {
137                    binding: 1,
138                    visibility: wgpu::ShaderStages::COMPUTE,
139                    ty: wgpu::BindingType::Buffer {
140                        ty: wgpu::BufferBindingType::Uniform,
141                        has_dynamic_offset: false,
142                        min_binding_size: None,
143                    },
144                    count: None,
145                },
146                // Selection buffer (only in modifier pipeline)
147                wgpu::BindGroupLayoutEntry {
148                    binding: 2,
149                    visibility: wgpu::ShaderStages::COMPUTE,
150                    ty: wgpu::BindingType::Buffer {
151                        ty: wgpu::BufferBindingType::Storage { read_only: true },
152                        has_dynamic_offset: false,
153                        min_binding_size: None,
154                    },
155                    count: None,
156                },
157            ],
158        };
159
160    log::debug!("Creating cylinder selection compute bundle");
161    let cylinder_selection_bundle = gs::core::ComputeBundleBuilder::new()
162        .label("Selection")
163        .bind_group_layouts([
164            &gs::SelectionBundle::<GaussianPod>::GAUSSIANS_BIND_GROUP_LAYOUT_DESCRIPTOR,
165            &wgpu::BindGroupLayoutDescriptor {
166                entries: &BIND_GROUP_LAYOUT_DESCRIPTOR.entries[..2],
167                ..BIND_GROUP_LAYOUT_DESCRIPTOR
168            },
169        ])
170        .main_shader("package::selection".parse().unwrap())
171        .entry_point("main")
172        .wesl_compile_options(wesl::CompileOptions {
173            features: GaussianPod::wesl_features(),
174            ..Default::default()
175        })
176        .resolver({
177            let mut resolver =
178                wesl::StandardResolver::new("examples/shader/custom_modify_selection");
179            resolver.add_package(&gs::core::shader::PACKAGE);
180            resolver
181        })
182        .build_without_bind_groups(&device)
183        .map_err(|e| log::error!("{e}"))
184        .expect("selection bundle");
185
186    log::debug!("Creating custom modifier");
187    #[allow(dead_code)]
188    let modifier_factory = |selection_buffer: &gs::SelectionBuffer| /* -> impl gs::Modifier<GaussianPod> */ {
189            log::debug!("Creating custom modifier compute bundle");
190            let modifier_bundle = gs::core::ComputeBundleBuilder::new()
191                .label("Modifier")
192                .bind_group_layouts([
193                    &gs::MODIFIER_GAUSSIANS_BIND_GROUP_LAYOUT_DESCRIPTOR,
194                    &BIND_GROUP_LAYOUT_DESCRIPTOR,
195                ])
196                .resolver({
197                    let mut resolver =
198                        wesl::StandardResolver::new("examples/shader/custom_modify_selection");
199                    resolver.add_package(&gs::core::shader::PACKAGE);
200                    resolver.add_package(&gs::shader::PACKAGE);
201                    resolver
202                })
203                .main_shader("package::modifier".parse().unwrap())
204                .entry_point("main")
205                .wesl_compile_options(wesl::CompileOptions {
206                    features: GaussianPod::wesl_features(),
207                    ..Default::default()
208                })
209                .build(
210                    &device,
211                    [
212                        vec![
213                            editor.gaussians_buffer.buffer().as_entire_binding(),
214                            editor.model_transform_buffer.buffer().as_entire_binding(),
215                            editor
216                                .gaussian_transform_buffer
217                                .buffer()
218                                .as_entire_binding(),
219                        ],
220                        vec![
221                            pos_buffer.as_entire_binding(),
222                            radius_buffer.as_entire_binding(),
223                            selection_buffer.buffer().as_entire_binding(),
224                        ],
225                    ],
226                )
227                .map_err(|e| log::error!("{e}"))
228                .expect("modifier bundle");
229
230            // This is a modifier closure because this function signature has blanket impl of the modifier trait
231            move |_device: &wgpu::Device,
232                  encoder: &mut wgpu::CommandEncoder,
233                  gaussians: &gs::core::GaussiansBuffer<GaussianPod>,
234                  _model_transform: &gs::core::ModelTransformBuffer,
235                  _gaussian_transform: &gs::core::GaussianTransformBuffer| {
236                  modifier_bundle.dispatch(encoder, gaussians.len() as u32);
237            }
238        };
239
240    #[allow(dead_code)]
241    struct Modifier<G: gs::core::GaussianPod>(gs::core::ComputeBundle, std::marker::PhantomData<G>);
242
243    impl<G: gs::core::GaussianPod> Modifier<G> {
244        #[allow(dead_code)]
245        fn new(
246            device: &wgpu::Device,
247            editor: &gs::Editor<G>,
248            pos_buffer: &wgpu::Buffer,
249            radius_buffer: &wgpu::Buffer,
250            selection_buffer: &gs::SelectionBuffer,
251        ) -> Self {
252            log::debug!("Creating custom modifier compute bundle");
253            let modifier_bundle = gs::core::ComputeBundleBuilder::new()
254                .label("Modifier")
255                .bind_group_layouts([
256                    &gs::MODIFIER_GAUSSIANS_BIND_GROUP_LAYOUT_DESCRIPTOR,
257                    &BIND_GROUP_LAYOUT_DESCRIPTOR,
258                ])
259                .resolver({
260                    let mut resolver =
261                        wesl::StandardResolver::new("examples/shader/custom_modify_selection");
262                    resolver.add_package(&gs::core::shader::PACKAGE);
263                    resolver.add_package(&gs::shader::PACKAGE);
264                    resolver
265                })
266                .main_shader("package::modifier".parse().unwrap())
267                .entry_point("main")
268                .wesl_compile_options(wesl::CompileOptions {
269                    features: GaussianPod::wesl_features(),
270                    ..Default::default()
271                })
272                .build(
273                    device,
274                    [
275                        vec![
276                            editor.gaussians_buffer.buffer().as_entire_binding(),
277                            editor.model_transform_buffer.buffer().as_entire_binding(),
278                            editor
279                                .gaussian_transform_buffer
280                                .buffer()
281                                .as_entire_binding(),
282                        ],
283                        vec![
284                            pos_buffer.as_entire_binding(),
285                            radius_buffer.as_entire_binding(),
286                            selection_buffer.buffer().as_entire_binding(),
287                        ],
288                    ],
289                )
290                .map_err(|e| log::error!("{e}"))
291                .expect("modifier bundle");
292
293            Self(modifier_bundle, std::marker::PhantomData)
294        }
295    }
296
297    impl<G: gs::core::GaussianPod> gs::Modifier<G> for Modifier<G> {
298        fn apply(
299            &self,
300            _device: &wgpu::Device,
301            encoder: &mut wgpu::CommandEncoder,
302            gaussians: &gs::core::GaussiansBuffer<G>,
303            _model_transform: &gs::core::ModelTransformBuffer,
304            _gaussian_transform: &gs::core::GaussianTransformBuffer,
305        ) {
306            self.0.dispatch(encoder, gaussians.len() as u32);
307        }
308    }
309
310    log::debug!("Creating selection modifier");
311    let mut selection_modifier = gs::SelectionModifier::<GaussianPod, _>::new(
312        &device,
313        &editor.gaussians_buffer,
314        vec![cylinder_selection_bundle],
315        modifier_factory,
316        // Uncomment the following line to use modifier struct instead of closure
317        // |selection_buffer| {
318        //     Modifier::new(
319        //         &device,
320        //         &editor,
321        //         &pos_buffer,
322        //         &radius_buffer,
323        //         selection_buffer,
324        //     )
325        // },
326    );
327
328    log::debug!("Creating selection expression");
329    selection_modifier.selection_expr = gs::SelectionExpr::selection(
330        0,
331        vec![
332            selection_modifier.selection.bundles[0]
333                .create_bind_group(
334                    &device,
335                    1, // index 0 is the Gaussians buffer, so we use 1,
336                    [
337                        pos_buffer.as_entire_binding(),
338                        radius_buffer.as_entire_binding(),
339                    ],
340                )
341                .expect("selection expr bind group"),
342        ],
343    );
344
345    log::info!("Starting editing process");
346    let time = std::time::Instant::now();
347
348    log::debug!("Editing Gaussians");
349    let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
350        label: Some("Edit Encoder"),
351    });
352
353    editor.apply(
354        &device,
355        &mut encoder,
356        [&selection_modifier as &dyn gs::Modifier<GaussianPod>],
357    );
358
359    queue.submit(Some(encoder.finish()));
360
361    device
362        .poll(wgpu::PollType::wait_indefinitely())
363        .expect("poll");
364
365    log::info!("Editing process completed in {:?}", time.elapsed());
366
367    log::debug!("Downloading Gaussians");
368    let modified_gaussians = editor
369        .gaussians_buffer
370        .download_gaussians(&device, &queue)
371        .await
372        .map(|gs| {
373            match &args.output[args.output.len().saturating_sub(4)..] {
374                ".ply" => {
375                    gs::core::Gaussians::Ply(gs::core::PlyGaussians::from_iter(gs.into_iter()))
376                }
377                ".spz" => {
378                    gs::core::Gaussians::Spz(
379                        gs::core::SpzGaussians::from_gaussians_with_options(
380                            gs,
381                            &gs::core::SpzGaussiansFromGaussianSliceOptions {
382                                version: 2, // Version 2 is more widely supported as of now
383                                ..Default::default()
384                            },
385                        )
386                        .expect("SpzGaussians from gaussians"),
387                    )
388                }
389                _ => panic!("Unsupported output file extension, expected .ply or .spz"),
390            }
391        })
392        .expect("gaussians download");
393
394    log::debug!("Writing modified Gaussians to output file");
395    modified_gaussians
396        .write_to_file(&args.output)
397        .expect("write modified Gaussians to output file");
398
399    log::info!("Modified Gaussians written to {}", args.output);
400}
Source

pub fn buffer(buffer: SelectionBuffer) -> Self

Create a new SelectionExpr::Buffer.

Source

pub fn update_with(&mut self, f: impl FnOnce(Self) -> Self)

Update the expression in place.

Source

pub fn as_u32(&self) -> Option<u32>

Get the u32 associated with this expression’s operation.

The value returned is not the same as that returned by SelectionExpr::custom_op_index, but rather a value that can be used to identify the operation by the compute shader, custom operation’s index are offset by SelectionExpr::CUSTOM_OP_START.

You usually do not need to use this method, it is used internally for evaluation of the compute shader.

Source

pub fn is_identity(&self) -> bool

Whether this expression is an identity operation.

Source

pub fn is_primitive(&self) -> bool

Whether this expression is a primitive operation.

Source

pub fn is_custom(&self) -> bool

Whether this expression is a custom operation.

Source

pub fn is_operation(&self) -> bool

Whether this expression is a selection operation.

Source

pub fn is_buffer(&self) -> bool

Whether this expression is a selection buffer.

Source

pub fn custom_op_index(&self) -> Option<usize>

Get the custom operation index.

This is the index of the custom operation in SelectionBundle::bundles vector.

Source

pub fn custom_bind_groups(&self) -> Option<&Vec<BindGroup>>

Get the custom operation bind groups for this expression.

Source

pub fn custom_op_index_and_bind_groups( &self, ) -> Option<(usize, &Vec<BindGroup>)>

Get the custom operation index and bind groups for this expression.

Trait Implementations§

Source§

impl Debug for SelectionExpr

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for SelectionExpr

Source§

fn default() -> SelectionExpr

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> Downcast<T> for T

Source§

fn downcast(&self) -> &T

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> Upcast<T> for T

Source§

fn upcast(&self) -> Option<&T>

Source§

impl<T> WasmNotSend for T
where T: Send,

Source§

impl<T> WasmNotSendSync for T

Source§

impl<T> WasmNotSync for T
where T: Sync,