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?
88async fn main() {
89 env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init();
90
91 let args = Args::parse();
92 let model_path = &args.model;
93 let pos = Vec3::from_slice(&args.pos);
94 let rot = Quat::from_slice(&args.rot);
95 let scale = Vec3::from_slice(&args.scale);
96 let shape = match args.shape {
97 Shape::Sphere => gs::SelectionBundle::<GaussianPod>::create_sphere_bundle,
98 Shape::Box => gs::SelectionBundle::<GaussianPod>::create_box_bundle,
99 };
100 let repeat = args.repeat;
101 let offset = Vec3::from_slice(&args.offset);
102
103 log::debug!("Creating wgpu instance");
104 let instance = wgpu::Instance::new(&wgpu::InstanceDescriptor::default());
105
106 log::debug!("Requesting adapter");
107 let adapter = instance
108 .request_adapter(&wgpu::RequestAdapterOptions::default())
109 .await
110 .expect("adapter");
111
112 log::debug!("Requesting device");
113 let (device, queue) = adapter
114 .request_device(&wgpu::DeviceDescriptor {
115 label: Some("Device"),
116 required_features: wgpu::Features::empty(),
117 required_limits: adapter.limits(),
118 memory_hints: wgpu::MemoryHints::default(),
119 trace: wgpu::Trace::Off,
120 })
121 .await
122 .expect("device");
123
124 log::debug!("Creating gaussians");
125 let f = std::fs::File::open(model_path).expect("ply file");
126 let mut reader = std::io::BufReader::new(f);
127 let gaussians = gs::core::Gaussians::read_ply(&mut reader).expect("gaussians");
128
129 log::debug!("Creating gaussians buffer");
130 let gaussians_buffer =
131 gs::core::GaussiansBuffer::<GaussianPod>::new(&device, &gaussians.gaussians);
132
133 log::debug!("Creating model transform buffer");
134 let model_transform = gs::core::ModelTransformBuffer::new(&device);
135
136 log::debug!("Creating Gaussian transform buffer");
137 let gaussian_transform = gs::core::GaussianTransformBuffer::new(&device);
138
139 log::debug!("Creating shape selection compute bundle");
140 let shape_selection = shape(&device);
141
142 log::debug!("Creating selection bundle");
143 let selection_bundle = gs::SelectionBundle::<GaussianPod>::new(&device, vec![shape_selection]);
144
145 log::debug!("Creating shape selection buffers");
146 let shape_selection_buffers = (0..repeat)
147 .map(|i| {
148 let offset_pos = pos + offset * i as f32;
149 let buffer = gs::InvTransformBuffer::new(&device);
150 buffer.update_with_scale_rot_pos(&queue, scale, rot, offset_pos);
151 buffer
152 })
153 .collect::<Vec<_>>();
154
155 log::debug!("Creating shape selection bind groups");
156 let shape_selection_bind_groups = shape_selection_buffers
157 .iter()
158 .map(|buffer| {
159 selection_bundle.bundles[0]
160 .create_bind_group(
161 &device,
162 // index 0 is the Gaussians buffer, so we use 1,
163 // see docs of create_sphere_bundle or create_box_bundle
164 1,
165 [buffer.buffer().as_entire_binding()],
166 )
167 .expect("bind group")
168 })
169 .collect::<Vec<_>>();
170
171 log::debug!("Creating selection expression");
172 let selection_expr = shape_selection_bind_groups.into_iter().fold(
173 gs::SelectionExpr::Identity,
174 |acc, bind_group| {
175 acc.union(gs::SelectionExpr::selection(
176 0, // the 0 here is the bundle index in the selection bundle
177 vec![bind_group],
178 ))
179 },
180 );
181
182 log::debug!("Creating destination buffer");
183 let dest = gs::SelectionBuffer::new(&device, gaussians_buffer.len() as u32);
184
185 log::info!("Starting selection process");
186 let time = std::time::Instant::now();
187
188 log::debug!("Selecting Gaussians");
189 let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
190 label: Some("Selection Encoder"),
191 });
192
193 selection_bundle.evaluate(
194 &device,
195 &mut encoder,
196 &selection_expr,
197 &dest,
198 &model_transform,
199 &gaussian_transform,
200 &gaussians_buffer,
201 );
202
203 queue.submit(Some(encoder.finish()));
204
205 #[allow(unused_must_use)]
206 device.poll(wgpu::PollType::Wait);
207
208 log::info!("Editing process completed in {:?}", time.elapsed());
209
210 log::debug!("Filtering Gaussians");
211 let selected_gaussians = gs::core::Gaussians {
212 gaussians: dest
213 .download::<u32>(&device, &queue)
214 .await
215 .expect("selected download")
216 .iter()
217 .flat_map(|group| {
218 std::iter::repeat_n(group, 32)
219 .enumerate()
220 .map(|(i, g)| g & (1 << i) != 0)
221 })
222 .zip(gaussians.gaussians.iter())
223 .filter(|(selected, _)| *selected)
224 .map(|(_, g)| g.clone())
225 .collect::<Vec<_>>(),
226 };
227
228 log::debug!("Writing modified Gaussians to output file");
229 let output_file = std::fs::File::create(&args.output).expect("output file");
230 let mut writer = std::io::BufWriter::new(output_file);
231 selected_gaussians
232 .write_ply(&mut writer)
233 .expect("write modified Gaussians to output file");
234
235 log::info!("Filtered Gaussians written to {}", args.output);
236}More examples
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}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?
88async fn main() {
89 env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init();
90
91 let args = Args::parse();
92 let model_path = &args.model;
93 let pos = Vec3::from_slice(&args.pos);
94 let rot = Quat::from_slice(&args.rot);
95 let scale = Vec3::from_slice(&args.scale);
96 let shape = match args.shape {
97 Shape::Sphere => gs::SelectionBundle::<GaussianPod>::create_sphere_bundle,
98 Shape::Box => gs::SelectionBundle::<GaussianPod>::create_box_bundle,
99 };
100 let repeat = args.repeat;
101 let offset = Vec3::from_slice(&args.offset);
102
103 log::debug!("Creating wgpu instance");
104 let instance = wgpu::Instance::new(&wgpu::InstanceDescriptor::default());
105
106 log::debug!("Requesting adapter");
107 let adapter = instance
108 .request_adapter(&wgpu::RequestAdapterOptions::default())
109 .await
110 .expect("adapter");
111
112 log::debug!("Requesting device");
113 let (device, queue) = adapter
114 .request_device(&wgpu::DeviceDescriptor {
115 label: Some("Device"),
116 required_features: wgpu::Features::empty(),
117 required_limits: adapter.limits(),
118 memory_hints: wgpu::MemoryHints::default(),
119 trace: wgpu::Trace::Off,
120 })
121 .await
122 .expect("device");
123
124 log::debug!("Creating gaussians");
125 let f = std::fs::File::open(model_path).expect("ply file");
126 let mut reader = std::io::BufReader::new(f);
127 let gaussians = gs::core::Gaussians::read_ply(&mut reader).expect("gaussians");
128
129 log::debug!("Creating gaussians buffer");
130 let gaussians_buffer =
131 gs::core::GaussiansBuffer::<GaussianPod>::new(&device, &gaussians.gaussians);
132
133 log::debug!("Creating model transform buffer");
134 let model_transform = gs::core::ModelTransformBuffer::new(&device);
135
136 log::debug!("Creating Gaussian transform buffer");
137 let gaussian_transform = gs::core::GaussianTransformBuffer::new(&device);
138
139 log::debug!("Creating shape selection compute bundle");
140 let shape_selection = shape(&device);
141
142 log::debug!("Creating selection bundle");
143 let selection_bundle = gs::SelectionBundle::<GaussianPod>::new(&device, vec![shape_selection]);
144
145 log::debug!("Creating shape selection buffers");
146 let shape_selection_buffers = (0..repeat)
147 .map(|i| {
148 let offset_pos = pos + offset * i as f32;
149 let buffer = gs::InvTransformBuffer::new(&device);
150 buffer.update_with_scale_rot_pos(&queue, scale, rot, offset_pos);
151 buffer
152 })
153 .collect::<Vec<_>>();
154
155 log::debug!("Creating shape selection bind groups");
156 let shape_selection_bind_groups = shape_selection_buffers
157 .iter()
158 .map(|buffer| {
159 selection_bundle.bundles[0]
160 .create_bind_group(
161 &device,
162 // index 0 is the Gaussians buffer, so we use 1,
163 // see docs of create_sphere_bundle or create_box_bundle
164 1,
165 [buffer.buffer().as_entire_binding()],
166 )
167 .expect("bind group")
168 })
169 .collect::<Vec<_>>();
170
171 log::debug!("Creating selection expression");
172 let selection_expr = shape_selection_bind_groups.into_iter().fold(
173 gs::SelectionExpr::Identity,
174 |acc, bind_group| {
175 acc.union(gs::SelectionExpr::selection(
176 0, // the 0 here is the bundle index in the selection bundle
177 vec![bind_group],
178 ))
179 },
180 );
181
182 log::debug!("Creating destination buffer");
183 let dest = gs::SelectionBuffer::new(&device, gaussians_buffer.len() as u32);
184
185 log::info!("Starting selection process");
186 let time = std::time::Instant::now();
187
188 log::debug!("Selecting Gaussians");
189 let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
190 label: Some("Selection Encoder"),
191 });
192
193 selection_bundle.evaluate(
194 &device,
195 &mut encoder,
196 &selection_expr,
197 &dest,
198 &model_transform,
199 &gaussian_transform,
200 &gaussians_buffer,
201 );
202
203 queue.submit(Some(encoder.finish()));
204
205 #[allow(unused_must_use)]
206 device.poll(wgpu::PollType::Wait);
207
208 log::info!("Editing process completed in {:?}", time.elapsed());
209
210 log::debug!("Filtering Gaussians");
211 let selected_gaussians = gs::core::Gaussians {
212 gaussians: dest
213 .download::<u32>(&device, &queue)
214 .await
215 .expect("selected download")
216 .iter()
217 .flat_map(|group| {
218 std::iter::repeat_n(group, 32)
219 .enumerate()
220 .map(|(i, g)| g & (1 << i) != 0)
221 })
222 .zip(gaussians.gaussians.iter())
223 .filter(|(selected, _)| *selected)
224 .map(|(_, g)| g.clone())
225 .collect::<Vec<_>>(),
226 };
227
228 log::debug!("Writing modified Gaussians to output file");
229 let output_file = std::fs::File::create(&args.output).expect("output file");
230 let mut writer = std::io::BufWriter::new(output_file);
231 selected_gaussians
232 .write_ply(&mut writer)
233 .expect("write modified Gaussians to output file");
234
235 log::info!("Filtered Gaussians written to {}", args.output);
236}More examples
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}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 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