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