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: &Gaussians) -> Self
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
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}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)
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
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> 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