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