Skip to main content

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 = 5

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