Skip to content

Commit f7cdc66

Browse files
authored
Use gpu picking for points, streamline/share picking code some more (#1814)
* use gpu picking for picking points * gpu based picking no longer works like a fallback but integrates with other picking sources * fix incorrect cursor rounding for picking * refactor picking context to be a pub struct with exposed state * unify ui picking method for 2d & 3d space views * less indentation for picking method * picking rect size is dynamically chosen * fix accidental z scaling in projection correction for picking & make cropped_projection_from_projection easier to read
1 parent c472b07 commit f7cdc66

20 files changed

+598
-659
lines changed

crates/re_renderer/examples/2d.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ impl framework::Example for Render2D {
149149
// Moving the windows to a high dpi screen makes the second one bigger.
150150
// Also, it looks different under perspective projection.
151151
// The third point is automatic thickness which is determined by the point renderer implementation.
152-
let mut point_cloud_builder = PointCloudBuilder::<()>::new(re_ctx);
152+
let mut point_cloud_builder = PointCloudBuilder::new(re_ctx);
153153
point_cloud_builder
154154
.batch("points")
155155
.add_points_2d(

crates/re_renderer/examples/depth_cloud.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ impl RenderDepthClouds {
9898
})
9999
.multiunzip();
100100

101-
let mut builder = PointCloudBuilder::<()>::new(re_ctx);
101+
let mut builder = PointCloudBuilder::new(re_ctx);
102102
builder
103103
.batch("backprojected point cloud")
104104
.add_points(num_points as _, points.into_iter())

crates/re_renderer/examples/framework.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -210,10 +210,10 @@ impl<E: Example + 'static> Application<E> {
210210
Event::WindowEvent {
211211
event: WindowEvent::CursorMoved { position, .. },
212212
..
213-
} => self.example.on_cursor_moved(glam::uvec2(
214-
position.x.round() as u32,
215-
position.y.round() as u32,
216-
)),
213+
} => self
214+
.example
215+
// Don't round the position: The entire range from 0 to excluding 1 should fall into pixel coordinate 0!
216+
.on_cursor_moved(glam::uvec2(position.x as u32, position.y as u32)),
217217
Event::WindowEvent {
218218
event:
219219
WindowEvent::ScaleFactorChanged {

crates/re_renderer/examples/multiview.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,7 @@ impl Example for Multiview {
316316
let skybox = GenericSkyboxDrawData::new(re_ctx);
317317
let lines = build_lines(re_ctx, seconds_since_startup);
318318

319-
let mut builder = PointCloudBuilder::<()>::new(re_ctx);
319+
let mut builder = PointCloudBuilder::new(re_ctx);
320320
builder
321321
.batch("Random Points")
322322
.world_from_obj(glam::Mat4::from_rotation_x(seconds_since_startup))

crates/re_renderer/examples/picking.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ impl framework::Example for Picking {
157157
.schedule_picking_rect(re_ctx, picking_rect, READBACK_IDENTIFIER, (), false)
158158
.unwrap();
159159

160-
let mut point_builder = PointCloudBuilder::<()>::new(re_ctx);
160+
let mut point_builder = PointCloudBuilder::new(re_ctx);
161161
for (i, point_set) in self.point_sets.iter().enumerate() {
162162
point_builder
163163
.batch(format!("Random Points {i}"))

crates/re_renderer/src/draw_phases/picking_layer.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -224,18 +224,18 @@ impl PickingLayerProcessor {
224224
DepthReadbackWorkaround::new(ctx, picking_rect.extent, picking_depth_target.handle)
225225
});
226226

227-
let rect_min = picking_rect.top_left_corner.as_vec2();
227+
let rect_min = picking_rect.left_top.as_vec2();
228228
let rect_max = rect_min + picking_rect.extent.as_vec2();
229229
let screen_resolution = screen_resolution.as_vec2();
230230
// y axis is flipped in NDC, therefore we need to flip the y axis of the rect.
231231
let rect_min_ndc =
232232
pixel_coord_to_ndc(glam::vec2(rect_min.x, rect_max.y), screen_resolution);
233233
let rect_max_ndc =
234234
pixel_coord_to_ndc(glam::vec2(rect_max.x, rect_min.y), screen_resolution);
235-
let rect_center_ndc = (rect_min_ndc + rect_max_ndc) * 0.5;
236-
let cropped_projection_from_projection =
237-
glam::Mat4::from_scale(2.0 / (rect_max_ndc - rect_min_ndc).extend(1.0))
238-
* glam::Mat4::from_translation(-rect_center_ndc.extend(0.0));
235+
let scale = 2.0 / (rect_max_ndc - rect_min_ndc);
236+
let translation = -0.5 * (rect_min_ndc + rect_max_ndc);
237+
let cropped_projection_from_projection = glam::Mat4::from_scale(scale.extend(1.0))
238+
* glam::Mat4::from_translation(translation.extend(0.0));
239239

240240
// Setup frame uniform buffer
241241
let previous_projection_from_world: glam::Mat4 =

crates/re_renderer/src/point_cloud_builder.rs

+27-98
Original file line numberDiff line numberDiff line change
@@ -9,23 +9,19 @@ use crate::{
99
};
1010

1111
/// Builder for point clouds, making it easy to create [`crate::renderer::PointCloudDrawData`].
12-
pub struct PointCloudBuilder<PerPointUserData> {
13-
// Size of `point`/color`/`per_point_user_data` must be equal.
12+
pub struct PointCloudBuilder {
13+
// Size of `point`/color` must be equal.
1414
pub vertices: Vec<PointCloudVertex>,
1515

1616
pub(crate) color_buffer: CpuWriteGpuReadBuffer<Color32>,
1717
pub(crate) picking_instance_ids_buffer: CpuWriteGpuReadBuffer<PickingLayerInstanceId>,
18-
pub user_data: Vec<PerPointUserData>,
1918

2019
pub(crate) batches: Vec<PointCloudBatchInfo>,
2120

2221
pub(crate) radius_boost_in_ui_points_for_outlines: f32,
2322
}
2423

25-
impl<PerPointUserData> PointCloudBuilder<PerPointUserData>
26-
where
27-
PerPointUserData: Default + Copy,
28-
{
24+
impl PointCloudBuilder {
2925
pub fn new(ctx: &RenderContext) -> Self {
3026
const RESERVE_SIZE: usize = 512;
3127

@@ -48,7 +44,6 @@ where
4844
vertices: Vec::with_capacity(RESERVE_SIZE),
4945
color_buffer,
5046
picking_instance_ids_buffer,
51-
user_data: Vec::with_capacity(RESERVE_SIZE),
5247
batches: Vec::with_capacity(16),
5348
radius_boost_in_ui_points_for_outlines: 0.0,
5449
}
@@ -65,10 +60,7 @@ where
6560

6661
/// Start of a new batch.
6762
#[inline]
68-
pub fn batch(
69-
&mut self,
70-
label: impl Into<DebugLabel>,
71-
) -> PointCloudBatchBuilder<'_, PerPointUserData> {
63+
pub fn batch(&mut self, label: impl Into<DebugLabel>) -> PointCloudBatchBuilder<'_> {
7264
self.batches.push(PointCloudBatchInfo {
7365
label: label.into(),
7466
world_from_obj: glam::Mat4::IDENTITY,
@@ -105,30 +97,6 @@ where
10597
})
10698
}
10799

108-
// Iterate over all batches, yielding the batch info and a point vertex iterator zipped with its user data.
109-
pub fn iter_vertices_and_userdata_by_batch(
110-
&self,
111-
) -> impl Iterator<
112-
Item = (
113-
&PointCloudBatchInfo,
114-
impl Iterator<Item = (&PointCloudVertex, &PerPointUserData)>,
115-
),
116-
> {
117-
let mut vertex_offset = 0;
118-
self.batches.iter().map(move |batch| {
119-
let out = (
120-
batch,
121-
self.vertices
122-
.iter()
123-
.zip(self.user_data.iter())
124-
.skip(vertex_offset)
125-
.take(batch.point_count as usize),
126-
);
127-
vertex_offset += batch.point_count as usize;
128-
out
129-
})
130-
}
131-
132100
/// Finalizes the builder and returns a point cloud draw data with all the points added so far.
133101
pub fn to_draw_data(
134102
self,
@@ -138,16 +106,9 @@ where
138106
}
139107
}
140108

141-
pub struct PointCloudBatchBuilder<'a, PerPointUserData>(
142-
&'a mut PointCloudBuilder<PerPointUserData>,
143-
)
144-
where
145-
PerPointUserData: Default + Copy;
109+
pub struct PointCloudBatchBuilder<'a>(&'a mut PointCloudBuilder);
146110

147-
impl<'a, PerPointUserData> Drop for PointCloudBatchBuilder<'a, PerPointUserData>
148-
where
149-
PerPointUserData: Default + Copy,
150-
{
111+
impl<'a> Drop for PointCloudBatchBuilder<'a> {
151112
fn drop(&mut self) {
152113
// Remove batch again if it wasn't actually used.
153114
if self.0.batches.last().unwrap().point_count == 0 {
@@ -157,10 +118,7 @@ where
157118
}
158119
}
159120

160-
impl<'a, PerPointUserData> PointCloudBatchBuilder<'a, PerPointUserData>
161-
where
162-
PerPointUserData: Default + Copy,
163-
{
121+
impl<'a> PointCloudBatchBuilder<'a> {
164122
#[inline]
165123
fn batch_mut(&mut self) -> &mut PointCloudBatchInfo {
166124
self.0
@@ -200,13 +158,6 @@ where
200158
self.0.vertices.len() - self.0.picking_instance_ids_buffer.num_written(),
201159
));
202160
}
203-
204-
if self.0.user_data.len() < self.0.vertices.len() {
205-
self.0.user_data.extend(
206-
std::iter::repeat(PerPointUserData::default())
207-
.take(self.0.vertices.len() - self.0.user_data.len()),
208-
);
209-
}
210161
}
211162

212163
#[inline]
@@ -222,7 +173,7 @@ where
222173
&mut self,
223174
size_hint: usize,
224175
positions: impl Iterator<Item = glam::Vec3>,
225-
) -> PointsBuilder<'_, PerPointUserData> {
176+
) -> PointsBuilder<'_> {
226177
// TODO(jleibs): Figure out if we can plumb-through proper support for `Iterator::size_hints()`
227178
// or potentially make `FixedSizedIterator` work correctly. This should be possible size the
228179
// underlying arrow structures are of known-size, but carries some complexity with the amount of
@@ -232,7 +183,6 @@ where
232183
self.extend_defaults();
233184

234185
debug_assert_eq!(self.0.vertices.len(), self.0.color_buffer.num_written());
235-
debug_assert_eq!(self.0.vertices.len(), self.0.user_data.len());
236186

237187
let old_size = self.0.vertices.len();
238188

@@ -245,8 +195,6 @@ where
245195
let num_points = self.0.vertices.len() - old_size;
246196
self.batch_mut().point_count += num_points as u32;
247197

248-
self.0.user_data.reserve(num_points);
249-
250198
let new_range = old_size..self.0.vertices.len();
251199

252200
let max_points = self.0.vertices.len();
@@ -256,7 +204,6 @@ where
256204
max_points,
257205
colors: &mut self.0.color_buffer,
258206
picking_instance_ids: &mut self.0.picking_instance_ids_buffer,
259-
user_data: &mut self.0.user_data,
260207
additional_outline_mask_ids: &mut self
261208
.0
262209
.batches
@@ -268,24 +215,22 @@ where
268215
}
269216

270217
#[inline]
271-
pub fn add_point(&mut self, position: glam::Vec3) -> PointBuilder<'_, PerPointUserData> {
218+
pub fn add_point(&mut self, position: glam::Vec3) -> PointBuilder<'_> {
272219
self.extend_defaults();
273220

274221
debug_assert_eq!(self.0.vertices.len(), self.0.color_buffer.num_written());
275-
debug_assert_eq!(self.0.vertices.len(), self.0.user_data.len());
276222

277223
let vertex_index = self.0.vertices.len() as u32;
278224
self.0.vertices.push(PointCloudVertex {
279225
position,
280226
radius: Size::AUTO,
281227
});
282-
self.0.user_data.push(Default::default());
283228
self.batch_mut().point_count += 1;
284229

285230
PointBuilder {
286231
vertex: self.0.vertices.last_mut().unwrap(),
287232
color: &mut self.0.color_buffer,
288-
user_data: self.0.user_data.last_mut().unwrap(),
233+
picking_instance_id: &mut self.0.picking_instance_ids_buffer,
289234
vertex_index,
290235
additional_outline_mask_ids: &mut self
291236
.0
@@ -308,13 +253,13 @@ where
308253
&mut self,
309254
size_hint: usize,
310255
positions: impl Iterator<Item = glam::Vec2>,
311-
) -> PointsBuilder<'_, PerPointUserData> {
256+
) -> PointsBuilder<'_> {
312257
self.add_points(size_hint, positions.map(|p| p.extend(0.0)))
313258
}
314259

315260
/// Adds a single 2D point. Uses an autogenerated depth value.
316261
#[inline]
317-
pub fn add_point_2d(&mut self, position: glam::Vec2) -> PointBuilder<'_, PerPointUserData> {
262+
pub fn add_point_2d(&mut self, position: glam::Vec2) -> PointBuilder<'_> {
318263
self.add_point(position.extend(0.0))
319264
}
320265

@@ -331,19 +276,17 @@ where
331276
}
332277

333278
// TODO(andreas): Should remove single-point builder, practically this never makes sense as we're almost always dealing with arrays of points.
334-
pub struct PointBuilder<'a, PerPointUserData> {
279+
pub struct PointBuilder<'a> {
335280
vertex: &'a mut PointCloudVertex,
336281
color: &'a mut CpuWriteGpuReadBuffer<Color32>,
337-
user_data: &'a mut PerPointUserData,
282+
picking_instance_id: &'a mut CpuWriteGpuReadBuffer<PickingLayerInstanceId>,
338283
vertex_index: u32,
284+
339285
additional_outline_mask_ids: &'a mut Vec<(std::ops::Range<u32>, OutlineMaskPreference)>,
340286
outline_mask_id: OutlineMaskPreference,
341287
}
342288

343-
impl<'a, PerPointUserData> PointBuilder<'a, PerPointUserData>
344-
where
345-
PerPointUserData: Clone,
346-
{
289+
impl<'a> PointBuilder<'a> {
347290
#[inline]
348291
pub fn radius(self, radius: Size) -> Self {
349292
self.vertex.radius = radius;
@@ -357,21 +300,24 @@ where
357300
self
358301
}
359302

360-
pub fn user_data(self, data: PerPointUserData) -> Self {
361-
*self.user_data = data;
362-
self
363-
}
364-
365303
/// Pushes additional outline mask ids for this point
366304
///
367305
/// Prefer the `overall_outline_mask_ids` setting to set the outline mask ids for the entire batch whenever possible!
306+
#[inline]
368307
pub fn outline_mask_id(mut self, outline_mask_id: OutlineMaskPreference) -> Self {
369308
self.outline_mask_id = outline_mask_id;
370309
self
371310
}
311+
312+
/// This mustn't call this more than once.
313+
#[inline]
314+
pub fn picking_instance_id(self, picking_instance_id: PickingLayerInstanceId) -> Self {
315+
self.picking_instance_id.push(picking_instance_id);
316+
self
317+
}
372318
}
373319

374-
impl<'a, PerPointUserData> Drop for PointBuilder<'a, PerPointUserData> {
320+
impl<'a> Drop for PointBuilder<'a> {
375321
fn drop(&mut self) {
376322
if self.outline_mask_id.is_some() {
377323
self.additional_outline_mask_ids.push((
@@ -382,21 +328,17 @@ impl<'a, PerPointUserData> Drop for PointBuilder<'a, PerPointUserData> {
382328
}
383329
}
384330

385-
pub struct PointsBuilder<'a, PerPointUserData> {
331+
pub struct PointsBuilder<'a> {
386332
// Vertices is a slice, which radii will update
387333
vertices: &'a mut [PointCloudVertex],
388334
max_points: usize,
389335
colors: &'a mut CpuWriteGpuReadBuffer<Color32>,
390336
picking_instance_ids: &'a mut CpuWriteGpuReadBuffer<PickingLayerInstanceId>,
391-
user_data: &'a mut Vec<PerPointUserData>,
392337
additional_outline_mask_ids: &'a mut Vec<(std::ops::Range<u32>, OutlineMaskPreference)>,
393338
start_vertex_index: u32,
394339
}
395340

396-
impl<'a, PerPointUserData> PointsBuilder<'a, PerPointUserData>
397-
where
398-
PerPointUserData: Clone,
399-
{
341+
impl<'a> PointsBuilder<'a> {
400342
/// Assigns radii to all points.
401343
///
402344
/// This mustn't call this more than once.
@@ -440,19 +382,6 @@ where
440382
self
441383
}
442384

443-
/// Assigns user data for all points in this builder.
444-
///
445-
/// This mustn't call this more than once.
446-
///
447-
/// User data is currently not available on the GPU.
448-
#[inline]
449-
pub fn user_data(self, data: impl Iterator<Item = PerPointUserData>) -> Self {
450-
crate::profile_function!();
451-
self.user_data
452-
.extend(data.take(self.max_points - self.user_data.len()));
453-
self
454-
}
455-
456385
/// Pushes additional outline mask ids for a specific range of points.
457386
/// The range is relative to this builder's range, not the entire batch.
458387
///

0 commit comments

Comments
 (0)