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