Skip to content

Commit 82f17dc

Browse files
authored
DataLoaders 3: add 3D point cloud DataLoader (.ply) (#4519)
`.ply` support, but point clouds only, at least for now. No feature flag: I had some, and tbh it only made thing needlessly hard to work with for very little gains. `.ply` are so common anyway, they always come up in user requests. Here's an example from [there](https://github.com/HuangCongQing/Point-Clouds-Visualization/blob/master/2open3D/data/fragment.ply): ![image](https://github.com/rerun-io/rerun/assets/2910679/8242c5a2-037d-46c6-9816-ab9b240a7473) Checks: - [x] `cargo r -p rerun-cli --no-default-features --features native_viewer -- examples/assets/example.{glb,gltf,obj,jpg,png,rrd,txt,md,ply}` - [x] Native: `File > Open > examples/assets/*` - [x] Native: `Drag-n-drop > examples/assets/*` - [x] Web: `File > Open > examples/assets/*` - [x] Web: `Drag-n-drop > examples/assets/*` --- Part of a series of PRs to make it possible to load _any_ file from the local filesystem, by any means, on web and native: - #4516 - #4517 - #4518 - #4519 - #4520 - #4521 - TODO: register custom loaders - TODO: high level docs and guides for everything related to loading files
1 parent 8f4f4e9 commit 82f17dc

File tree

9 files changed

+404
-21
lines changed

9 files changed

+404
-21
lines changed

Cargo.lock

Lines changed: 86 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ itertools = "0.11" # updating it
146146
js-sys = "0.3"
147147
# No lazy_static - use `std::sync::OnceLock` or `once_cell` instead
148148
libc = "0.2"
149+
linked-hash-map = { version = "0.5", default-features = false }
149150
log = "0.4"
150151
log-once = "0.4"
151152
lz4_flex = "0.11"
@@ -167,6 +168,7 @@ ordered-float = "4.2"
167168
parking_lot = "0.12"
168169
pathdiff = "0.2"
169170
pico-args = "0.5"
171+
ply-rs = { version = "0.1", default-features = false }
170172
polars-core = "0.29"
171173
polars-lazy = "0.29"
172174
polars-ops = "0.29"

crates/re_data_source/src/data_loader/loader_archetype.rs

Lines changed: 38 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -80,22 +80,25 @@ impl DataLoader for ArchetypeLoader {
8080

8181
let mut rows = Vec::new();
8282

83-
if crate::SUPPORTED_MESH_EXTENSIONS.contains(&extension.as_str()) {
84-
re_log::debug!(?filepath, loader = self.name(), "Loading 3D model…",);
85-
rows.extend(load_mesh(
86-
filepath,
83+
if crate::SUPPORTED_IMAGE_EXTENSIONS.contains(&extension.as_str()) {
84+
re_log::debug!(?filepath, loader = self.name(), "Loading image…",);
85+
rows.extend(load_image(
86+
&filepath,
8787
timepoint,
8888
entity_path,
8989
contents.into_owned(),
9090
)?);
91-
} else if crate::SUPPORTED_IMAGE_EXTENSIONS.contains(&extension.as_str()) {
92-
re_log::debug!(?filepath, loader = self.name(), "Loading image…",);
93-
rows.extend(load_image(
94-
&filepath,
91+
} else if crate::SUPPORTED_MESH_EXTENSIONS.contains(&extension.as_str()) {
92+
re_log::debug!(?filepath, loader = self.name(), "Loading 3D model…",);
93+
rows.extend(load_mesh(
94+
filepath,
9595
timepoint,
9696
entity_path,
9797
contents.into_owned(),
9898
)?);
99+
} else if crate::SUPPORTED_POINT_CLOUD_EXTENSIONS.contains(&extension.as_str()) {
100+
re_log::debug!(?filepath, loader = self.name(), "Loading 3D point cloud…",);
101+
rows.extend(load_point_cloud(timepoint, entity_path, &contents)?);
99102
} else if crate::SUPPORTED_TEXT_EXTENSIONS.contains(&extension.as_str()) {
100103
re_log::debug!(?filepath, loader = self.name(), "Loading text document…",);
101104
rows.extend(load_text_document(
@@ -118,6 +121,28 @@ impl DataLoader for ArchetypeLoader {
118121

119122
// ---
120123

124+
fn load_image(
125+
filepath: &std::path::Path,
126+
timepoint: TimePoint,
127+
entity_path: EntityPath,
128+
contents: Vec<u8>,
129+
) -> Result<impl ExactSizeIterator<Item = DataRow>, DataLoaderError> {
130+
re_tracing::profile_function!();
131+
132+
let rows = [
133+
{
134+
let arch = re_types::archetypes::Image::from_file_contents(
135+
contents,
136+
image::ImageFormat::from_path(filepath).ok(),
137+
)?;
138+
DataRow::from_archetype(RowId::new(), timepoint, entity_path, &arch)?
139+
},
140+
//
141+
];
142+
143+
Ok(rows.into_iter())
144+
}
145+
121146
fn load_mesh(
122147
filepath: std::path::PathBuf,
123148
timepoint: TimePoint,
@@ -140,21 +165,18 @@ fn load_mesh(
140165
Ok(rows.into_iter())
141166
}
142167

143-
fn load_image(
144-
filepath: &std::path::Path,
168+
fn load_point_cloud(
145169
timepoint: TimePoint,
146170
entity_path: EntityPath,
147-
contents: Vec<u8>,
171+
contents: &[u8],
148172
) -> Result<impl ExactSizeIterator<Item = DataRow>, DataLoaderError> {
149173
re_tracing::profile_function!();
150174

151175
let rows = [
152176
{
153-
let arch = re_types::archetypes::Image::from_file_contents(
154-
contents,
155-
image::ImageFormat::from_path(filepath).ok(),
156-
)?;
157-
DataRow::from_archetype(RowId::new(), timepoint, entity_path, &arch)?
177+
// TODO(#4532): `.ply` data loader should support 2D point cloud & meshes
178+
let points3d = re_types::archetypes::Points3D::from_file_contents(contents)?;
179+
DataRow::from_archetype(RowId::new(), timepoint, entity_path, &points3d)?
158180
},
159181
//
160182
];

crates/re_data_source/src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ pub const SUPPORTED_IMAGE_EXTENSIONS: &[&str] = &[
4545

4646
pub const SUPPORTED_MESH_EXTENSIONS: &[&str] = &["glb", "gltf", "obj"];
4747

48+
// TODO(#4532): `.ply` data loader should support 2D point cloud & meshes
49+
pub const SUPPORTED_POINT_CLOUD_EXTENSIONS: &[&str] = &["ply"];
50+
4851
pub const SUPPORTED_RERUN_EXTENSIONS: &[&str] = &["rrd"];
4952

5053
// TODO(#4555): Add catch-all builtin `DataLoader` for text files
@@ -64,6 +67,7 @@ pub fn supported_extensions() -> impl Iterator<Item = &'static str> {
6467
pub fn is_supported_file_extension(extension: &str) -> bool {
6568
SUPPORTED_IMAGE_EXTENSIONS.contains(&extension)
6669
|| SUPPORTED_MESH_EXTENSIONS.contains(&extension)
70+
|| SUPPORTED_POINT_CLOUD_EXTENSIONS.contains(&extension)
6771
|| SUPPORTED_RERUN_EXTENSIONS.contains(&extension)
6872
|| SUPPORTED_TEXT_EXTENSIONS.contains(&extension)
6973
}

crates/re_types/Cargo.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,12 +62,14 @@ arrow2 = { workspace = true, features = [
6262
] }
6363
bytemuck = { workspace = true, features = ["derive", "extern_crate_alloc"] }
6464
document-features.workspace = true
65+
half = { workspace = true, features = ["bytemuck"] }
6566
infer.workspace = true
6667
itertools.workspace = true
67-
half = { workspace = true, features = ["bytemuck"] }
68+
linked-hash-map.workspace = true
6869
mime_guess2.workspace = true
6970
ndarray.workspace = true
7071
once_cell.workspace = true
72+
ply-rs.workspace = true
7173
smallvec.workspace = true
7274
thiserror.workspace = true
7375
uuid = { workspace = true, features = ["serde", "v4", "js"] }
@@ -100,8 +102,6 @@ re_types_builder.workspace = true
100102
rayon.workspace = true
101103

102104
# `machete` is not a fan of `build-dependencies`.
103-
104-
105105
[package.metadata.cargo-machete]
106106
ignored = ["rayon", "re_build_tools", "re_types_builder"]
107107

crates/re_types/src/archetypes/mod.rs

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)