Editor

Struct Editor 

Source
pub struct Editor<G: GaussianPod> {
    pub model_transform_buffer: ModelTransformBuffer,
    pub gaussian_transform_buffer: GaussianTransformBuffer,
    pub gaussians_buffer: GaussiansBuffer<G>,
}
Expand description

An editor for Gaussians.

This enables the application of a sequence of Modifiers to the Gaussians by storing the necessary buffers, including:

If you wish to manage these buffers yourself, you do not need to use this struct.

Note that some GaussianPod configurations may not be able to be downloaded after modification, see documentations of core::GaussianShConfig and core::GaussianCov3dConfig for details.

Fields§

§model_transform_buffer: ModelTransformBuffer§gaussian_transform_buffer: GaussianTransformBuffer§gaussians_buffer: GaussiansBuffer<G>

Implementations§

Source§

impl<G: GaussianPod> Editor<G>

Source

pub fn new(device: &Device, gaussians: &Gaussians) -> Self

Create a new editor.

Examples found in repository?
examples/modify.rs (line 101)
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
74    log::debug!("Creating wgpu instance");
75    let instance = wgpu::Instance::new(&wgpu::InstanceDescriptor::default());
76
77    log::debug!("Requesting adapter");
78    let adapter = instance
79        .request_adapter(&wgpu::RequestAdapterOptions::default())
80        .await
81        .expect("adapter");
82
83    log::debug!("Requesting device");
84    let (device, queue) = adapter
85        .request_device(&wgpu::DeviceDescriptor {
86            label: Some("Device"),
87            required_features: wgpu::Features::empty(),
88            required_limits: adapter.limits(),
89            memory_hints: wgpu::MemoryHints::default(),
90            trace: wgpu::Trace::Off,
91        })
92        .await
93        .expect("device");
94
95    log::debug!("Creating gaussians");
96    let f = std::fs::File::open(model_path).expect("ply file");
97    let mut reader = std::io::BufReader::new(f);
98    let gaussians = gs::core::Gaussians::read_ply(&mut reader).expect("gaussians");
99
100    log::debug!("Creating editor");
101    let editor = gs::Editor::<GaussianPod>::new(&device, &gaussians);
102
103    log::debug!("Creating basic modifier");
104    let basic_modifier = gs::BasicModifier::<GaussianPod>::new(
105        &device,
106        &editor.gaussians_buffer,
107        &editor.model_transform_buffer,
108        &editor.gaussian_transform_buffer,
109    );
110
111    log::debug!("Configuring modifiers");
112    match args.override_rgb {
113        true => basic_modifier
114            .basic_color_modifiers_buffer
115            .update_with_override_rgb(
116                &queue,
117                Vec3::from_slice(&args.rgb_or_hsv),
118                args.alpha,
119                args.contrast,
120                args.exposure,
121                args.gamma,
122            ),
123        false => basic_modifier
124            .basic_color_modifiers_buffer
125            .update_with_hsv_modifiers(
126                &queue,
127                Vec3::from_slice(&args.rgb_or_hsv),
128                args.alpha,
129                args.contrast,
130                args.exposure,
131                args.gamma,
132            ),
133    }
134
135    log::info!("Starting editing process");
136    let time = std::time::Instant::now();
137
138    log::debug!("Editing Gaussians");
139    let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
140        label: Some("Edit Encoder"),
141    });
142
143    editor.apply(
144        &device,
145        &mut encoder,
146        [&basic_modifier as &dyn gs::Modifier<GaussianPod>],
147    );
148
149    queue.submit(Some(encoder.finish()));
150
151    #[allow(unused_must_use)]
152    device.poll(wgpu::PollType::Wait);
153
154    log::info!("Editing process completed in {:?}", time.elapsed());
155
156    log::debug!("Downloading Gaussians");
157    let modified_gaussians = gs::core::Gaussians {
158        gaussians: editor
159            .gaussians_buffer
160            .download_gaussians(&device, &queue)
161            .await
162            .expect("gaussians download"),
163    };
164
165    log::debug!("Writing modified Gaussians to output file");
166    let output_file = std::fs::File::create(&args.output).expect("output file");
167    let mut writer = std::io::BufWriter::new(output_file);
168    modified_gaussians
169        .write_ply(&mut writer)
170        .expect("write modified Gaussians to output file");
171
172    log::info!("Modified Gaussians written to {}", args.output);
173}
More examples
Hide additional examples
examples/modify_selection.rs (line 167)
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 (line 88)
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 apply<'a>( &self, device: &Device, encoder: &mut CommandEncoder, modifiers: impl IntoIterator<Item = &'a dyn Modifier<G>>, )

Apply the modifiers to the Gaussians.

Examples found in repository?
examples/modify.rs (lines 143-147)
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
74    log::debug!("Creating wgpu instance");
75    let instance = wgpu::Instance::new(&wgpu::InstanceDescriptor::default());
76
77    log::debug!("Requesting adapter");
78    let adapter = instance
79        .request_adapter(&wgpu::RequestAdapterOptions::default())
80        .await
81        .expect("adapter");
82
83    log::debug!("Requesting device");
84    let (device, queue) = adapter
85        .request_device(&wgpu::DeviceDescriptor {
86            label: Some("Device"),
87            required_features: wgpu::Features::empty(),
88            required_limits: adapter.limits(),
89            memory_hints: wgpu::MemoryHints::default(),
90            trace: wgpu::Trace::Off,
91        })
92        .await
93        .expect("device");
94
95    log::debug!("Creating gaussians");
96    let f = std::fs::File::open(model_path).expect("ply file");
97    let mut reader = std::io::BufReader::new(f);
98    let gaussians = gs::core::Gaussians::read_ply(&mut reader).expect("gaussians");
99
100    log::debug!("Creating editor");
101    let editor = gs::Editor::<GaussianPod>::new(&device, &gaussians);
102
103    log::debug!("Creating basic modifier");
104    let basic_modifier = gs::BasicModifier::<GaussianPod>::new(
105        &device,
106        &editor.gaussians_buffer,
107        &editor.model_transform_buffer,
108        &editor.gaussian_transform_buffer,
109    );
110
111    log::debug!("Configuring modifiers");
112    match args.override_rgb {
113        true => basic_modifier
114            .basic_color_modifiers_buffer
115            .update_with_override_rgb(
116                &queue,
117                Vec3::from_slice(&args.rgb_or_hsv),
118                args.alpha,
119                args.contrast,
120                args.exposure,
121                args.gamma,
122            ),
123        false => basic_modifier
124            .basic_color_modifiers_buffer
125            .update_with_hsv_modifiers(
126                &queue,
127                Vec3::from_slice(&args.rgb_or_hsv),
128                args.alpha,
129                args.contrast,
130                args.exposure,
131                args.gamma,
132            ),
133    }
134
135    log::info!("Starting editing process");
136    let time = std::time::Instant::now();
137
138    log::debug!("Editing Gaussians");
139    let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
140        label: Some("Edit Encoder"),
141    });
142
143    editor.apply(
144        &device,
145        &mut encoder,
146        [&basic_modifier as &dyn gs::Modifier<GaussianPod>],
147    );
148
149    queue.submit(Some(encoder.finish()));
150
151    #[allow(unused_must_use)]
152    device.poll(wgpu::PollType::Wait);
153
154    log::info!("Editing process completed in {:?}", time.elapsed());
155
156    log::debug!("Downloading Gaussians");
157    let modified_gaussians = gs::core::Gaussians {
158        gaussians: editor
159            .gaussians_buffer
160            .download_gaussians(&device, &queue)
161            .await
162            .expect("gaussians download"),
163    };
164
165    log::debug!("Writing modified Gaussians to output file");
166    let output_file = std::fs::File::create(&args.output).expect("output file");
167    let mut writer = std::io::BufWriter::new(output_file);
168    modified_gaussians
169        .write_ply(&mut writer)
170        .expect("write modified Gaussians to output file");
171
172    log::info!("Modified Gaussians written to {}", args.output);
173}
More examples
Hide additional examples
examples/modify_selection.rs (lines 252-256)
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 336-340)
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}

Auto Trait Implementations§

§

impl<G> Freeze for Editor<G>

§

impl<G> !RefUnwindSafe for Editor<G>

§

impl<G> Send for Editor<G>

§

impl<G> Sync for Editor<G>

§

impl<G> Unpin for Editor<G>
where G: Unpin,

§

impl<G> !UnwindSafe for Editor<G>

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,