One room, nine kinds of 3D
Every 3D product we could build from a single iPhone LiDAR scan, side by side (2026-10-14)
- 524 video frames (1920×1440) + the camera position and orientation the iPhone recorded for each (real metres)
- 44 high-resolution photos (2016×1512) + camera poses
- 12,132,505 LiDAR points (with colour)
- The app's own mesh, 58,319 triangles
End-to-end pipeline
flowchart LR A["iPhone + Modelar app
~11 min walking scan"] --> B["One 544 MB archive
Windows D: → arcAI server"] B --> C["Format decoding
Cloud.log · Mesh.scn · camera json"] C --> M1["① App mesh
extracted as is"] C --> M2["② LiDAR points
padding removed"] C --> P["568 camera poses
ARKit → RS · COLMAP conventions"] P --> M3["③ RealityScan
locked poses → mesh → LiDAR colours"] P --> M4["④ Gaussian splat
gsplat 30k steps"] M2 --> M4 M2 --> M5["⑤ Splat + LiDAR depth
+ pose refinement"] P --> M5 M2 --> M6["⑥ LiDAR mesh
Open3D Poisson"] P --> M7["⑦ WebODM (ODM)
iPhone poses as fake GPS"] P --> M8["⑧ 2D Gaussian splat
surface-aligned"] M2 --> M8 C --> M9["⑨ VGGT (AI)
depth AI · pose iPhone · scale LiDAR"] P --> M9 M2 --> M9 M1 & M2 & M3 & M4 & M5 & M6 & M7 & M8 & M9 --> W["Web compression
GLB · PLY · splat"] W --> X["Cloudflare Pages
this page"] classDef app fill:#fef3c7,stroke:#f59e0b,stroke-width:3px,color:#78350f classDef lidar fill:#d1fae5,stroke:#10b981,stroke-width:3px,color:#064e3b classDef rs fill:#dbeafe,stroke:#3b82f6,stroke-width:3px,color:#1e3a8a classDef gs fill:#fce7f3,stroke:#ec4899,stroke-width:3px,color:#831843 classDef gsd fill:#ede9fe,stroke:#8b5cf6,stroke-width:3px,color:#4c1d95 classDef lmesh fill:#ccfbf1,stroke:#14b8a6,stroke-width:3px,color:#134e4a classDef odm fill:#fee2e2,stroke:#ef4444,stroke-width:3px,color:#7f1d1d classDef gs2d fill:#e0f2fe,stroke:#0ea5e9,stroke-width:3px,color:#0c4a6e classDef vggt fill:#ecfccb,stroke:#84cc16,stroke-width:3px,color:#365314 class M1 app class M2 lidar class M3 rs class M4 gs class M5 gsd class M6 lmesh class M7 odm class M8 gs2d class M9 vggt
Compare in 3D
Pick a tab to load that method. Drag to rotate, wheel to zoom, right-drag to pan. Two fingers on a phone. Splats (④⑤⑧) look most photographic near where photos were taken, so they open at the 'Capture viewpoint'.
Each method in detail
① App mesh
How it was made: The mesh Modelar builds live during capture, extracted as is. Its Mesh.scn is an Apple SceneKit archive no other tool reads, so its structure was decoded and the 94 parts merged (read_modelar_mesh.py).
- Zero extra processing; exactly what the app shows
- Smallest file (1.2 MB)
- Overall shape (room size, wall positions) is right
- Only 58k triangles; built on a 5 cm voxel grid
- Colour only at vertices, so objects blur
- No official way to export it; had to be decoded
What to look at
- Bird's-eye: can you read the room outline and furniture layout
- How furniture turns into blobs
- Treat it as the baseline: what the app alone gives you
Numbers: 33,363 vertices / 58,319 triangles
② LiDAR points
How it was made: The app's LiDAR point file Cloud.log was decoded byte by byte (no public spec) and verified by matching the block point total to the app's own count (21,029,180). 8,896,675 of them (42.3%) were (0,0,0) padding and were removed. 1,300,000 random points are shown on the web.
- Measured by the sensor, so scale is real metres from the start
- Every other result here shares its coordinates (RS mesh within a 1.5 cm median)
- The most trustworthy source for measurements and floor plans
- Points, so gaps show up close
- Range (5 m app setting) and resolution blur small object edges
- Glass, mirrors and black surfaces drop or scatter points
What to look at
- Hide ceiling + bird's-eye: do walls come out straight like a floor plan
- Holes or stray points at monitors and windows
- Go inside and look at point spacing up close
Numbers: 12,132,505 points (web 1,300,000, 19.5 MB)
③ RealityScan mesh
How it was made: 568 images went into RealityScan 2.2 for Linux on arcAI. Photos alone aligned only 65 images into one component, so the iPhone poses were converted to RS prior files (XMP) and locked. The iPhone rotation convention (column-major, camera-to-world, ARKit axes) was confirmed against the 65 images RS had aligned (median rotation difference 1.68°). Then mesh (Normal) → simplify to 1.5M triangles. RS exported only white, so each vertex takes the colour of its four nearest LiDAR points (97.7% of vertices).
- The densest surface; edges and small objects keep their shape
- A mesh, so measuring and exporting to other tools is easy
- Same frame as LiDAR, 1.5 cm median difference
- Textureless white walls and floors are weak for photogrammetry: bumpy or missing
- Texture export fails in the Linux command line ('Feature not implemented') and vertex colours came out white, so LiDAR colours were borrowed: text and patterns blur
- Poses were locked, so iPhone pose error stays in
What to look at
- Small objects on the desk such as the keyboard and monitor stand (compare with ①)
- Bumps on white walls and ceiling (compare with ② LiDAR)
- Areas past the door: LiDAR stops at 5 m, photos see further
Numbers: 568/568 aligned · reprojection 1.03 px · align 60 s · mesh 192 s · colour 74 s · 1,499,250 triangles · web 6.35 MB
④ Gaussian splat
How it was made: Gaussian splatting represents the scene as millions of small translucent colour blobs trained to reproduce the photos. The iPhone poses were used directly (no photo alignment) and training started from 388,339 LiDAR points (2 cm grid). The gsplat 1.5.3 engine has no prebuilt package for this GPU, so it was built with CUDA 13. 30k steps; one image in eight was held out for evaluation. For the web it was reduced to .splat, base colour only.
- Looks like the photos, including shine, translucency and thin things (cables)
- You can truly walk around inside
- Smooth even where photogrammetry struggles, such as white walls
- Blobs, not surfaces, so hard to use for measuring or plans
- Off the captured viewpoints you see blurry floaters
- iPhone pose error becomes blur
- Needs a GPU and tens of minutes
What to look at
- Inside view: do monitor glow, chair mesh and cables look photographic
- Floaters when you turn toward the ceiling or corners
- Switch with ③ at the same spot: looks versus shape
Numbers: PSNR 15.43 · SSIM 0.76 · 2,723,832 gaussians · 35 min · web 48.0 MB
⑤ Splat + LiDAR depth
How it was made: Same data as ④ with two additions. (1) LiDAR points visible in each photo are linked so training also matches the distance to those points (depth supervision). (2) The iPhone camera poses are refined during training. Same idea as DN-Splatter, which research uses for indoor iPhone LiDAR. Same 30k steps and held-out images.
- Walls and floor should stick to LiDAR, reducing floaters
- Pose refinement should reduce blur
- Directly comparable with ④ (same held-out images)
- Still blobs, not for measuring
- Where LiDAR is wrong (glass, black surfaces) it pulls toward wrong depths
- One more setting, slightly slower
What to look at
- Toggle with ④ at the same spot: fewer floaters on white walls and floor
- Sharper corners and door frames
- The PSNR difference in the table below
Numbers: PSNR 18.33 · SSIM 0.8 · 3,385,261 gaussians · 55 min · web 48.0 MB
⑥ LiDAR mesh
How it was made: ② LiDAR points were thinned to a 1 cm grid (1.73M points), normals were estimated and flipped toward the nearest iPhone camera, and Open3D Poisson reconstruction wrapped a smooth surface. Fake surfaces in sparse areas (lowest 3% density) were removed and the mesh reduced to 1M triangles. Colours come from the LiDAR points.
- Surfaces from LiDAR alone, no photogrammetry: white walls come out straight and smooth
- Dimensions are LiDAR's, ready for plans and areas (total area 94.7 m²)
- Fast (CPU 2.7 min)
- Poisson tends to bulge surfaces to close holes, so phantom surfaces can appear past the door or behind furniture
- Small items (cables, pens) are below LiDAR resolution and blur
- Colour from points, blurrier than photos
What to look at
- Same spot as ③ RS: ragged white walls in RS versus straight here?
- Bulged phantom surfaces behind furniture or past the door
- Toggle with ② points to see how well the surface follows them
Numbers: 1,000,000 triangles · 2.7 min (CPU) · web 4.5 MB
⑦ WebODM
How it was made: The WebODM engine already on arcAI (ODM 3.8.3) processed the same 568 images. ODM only takes camera positions as GPS, so the iPhone poses were written into image copies as GPS around an arbitrary origin (lat 1°, lon 1°, unrelated to the real location) and run with --force-gps at 5 cm. No orthophoto indoors.
- Free and open source, mesh and texture from one command
- Textures come straight from the photos (what RS on Linux could not do)
- Same engine as the drone run, easy to compare
- CPU only, slow
- Same photogrammetry limits as RS indoors on white walls
- Needs the fake-GPS workaround for the iPhone poses
What to look at
- Compare shape with ③ RS at the same spot
- Are text and patterns sharper than RS thanks to textures
- Holes and sheets on white walls
Numbers: 568장 중 304장 정렬 · 텍스처 메시 81만 삼각형(149 조각) · 라이다까지 중앙 2.2 cm (90% 8.6 cm) · 60 min · web 12.5 MB
⑧ 2D Gaussian
How it was made: 2D Gaussian splatting (2DGS) trains flat discs that stick to surfaces. Run with gsplat's 2DGS trainer on the same data and steps (30k) as ④.
- Discs stick to surfaces, so shape is crisper than ④ (per the literature)
- Fewer floaters on white walls and floors
- Slightly less photographic than ④
- The web viewer is not 2DGS-specific, so it is approximated as regular splats
What to look at
- Toggle with ④: are walls and floor flatter
- Are corners sharper
Numbers: PSNR in progress · SSIM in progress · in progress min · web in progress MB
⑨ VGGT (AI)
How it was made: VGGT (Meta, 2025) estimates camera poses and depth from a set of photos in one pass. Only about 16 photos fit the 16 GB GPU, so two variants were tried. (a) Chunk stitching: 22 overlapping 16-frame chunks, with the AI poses fitted to the iPhone poses; six chunks off by more than 15 cm or 15° were dropped. (b) Fill (this tab): the AI poses are ignored and each photo is placed with depth from VGGT, position from the iPhone, scale from LiDAR. LiDAR points projected into each photo give the VGGT-to-LiDAR depth ratio; photos where the ratio varies by more than 15% are dropped (343 of 524 used). Same idea as MapAnything and Prompt Depth Anything from the research: photos + known poses + LiDAR together.
- Sharper objects than LiDAR, at photo resolution
- Fast: whole room in 5 min 14 s (about 10 s per chunk)
- Depth itself comes from photos alone; works for phones and cameras without LiDAR
- On its own it has no metric scale and cannot join chunks; the iPhone poses and LiDAR did that here
- Photos per pass are limited by GPU memory
- 35% of photos (181) disagreed with LiDAR and were dropped; AI pose estimation failed for 27% of chunks and entirely with spread-out frames (99 cm, 127°)
What to look at
- Objects, text and colour are sharper than ② LiDAR because depth is estimated at photo resolution
- Are the gaps from chunk stitching filled (LiDAR surface covered 60.0% → 84.7%)
- Toggle with ② LiDAR: does it sit in the same place (1.1 cm median)
Numbers: 채움 방식: 524장 중 343장 · 라이다 표면 84.7% 덮음 · 라이다까지 중앙 1.1 cm (90% 4.2 cm) · 5분 14초 / 묶음 방식: 60.0% · 3.6 cm (90% 19.0 cm)
At a glance
| Method | Extra processing | Appearance | Measuring / plans | Web size |
|---|---|---|---|---|
| ① App mesh | 0 | Coarse | Rough | 1.2 MB |
| ② LiDAR points | Decoding only | Points, gaps up close | Most trustworthy | 19.5 MB |
| ③ RealityScan | 6 min | Good shape, blurry colour | Good (mesh) | 6.35 MB |
| ④ Splat | 35 min | Photographic | Hard | 48.0 MB |
| ⑤ Splat + depth | 55 min | Photographic | Hard | 48.0 MB |
| ⑥ LiDAR mesh | 2.7 min | Smooth, blurry colour | Good (LiDAR dimensions) | 4.5 MB |
| ⑦ WebODM | 60 min | 텍스처 있음 | Good (mesh) | 12.5 MB |
| ⑧ 2D splat | in progress min | Photographic, crisper surfaces | Hard | in progress MB |
| ⑨ VGGT (AI) | 5.2 min | Coarse points | No scale | 22.5 MB |
What went wrong on the way (kept as is)
- With photos only, the largest RS component was 65 of 568 images; with iPhone poses as initial priors, 62. Only locked poses aligned all 568. Indoor white walls and blurry video frames lack features
- Texture image export from the RS Linux command line failed every time with 'Feature not implemented' (PNG, JPG, explicit codecs, single texture off). Vertex colouring ran (74 s) but the exported colours were all white, so nearest-LiDAR colours were used. 742 stray triangles (edges up to 7.9 m) were also removed
- 42.3% of the LiDAR point file was (0,0,0) padding, not points. The first decoded count (21,029,180) matched the app's record, which nearly hid it; a median of exactly 0 gave it away
- While installing the training tools another package silently upgraded torch from 2.11 to 2.12, breaking the CUDA extensions; reverted and rebuilt
- The pip CUDA 13 compiler (13.0) pulled companion parts (nvvm, crt) at 13.4, breaking compilation; fixed by pinning versions
- The COLMAP text reader bundled with the trainer is broken under Python 3, so the binary format was written instead
- VGGT with 16 frames spread over the whole capture failed (99 cm position, 127° rotation); 16 overlapping frames reached 6.8 cm and 5°
- WebODM (ODM) cannot align everything from photos alone either, so the iPhone poses were fed in as fake GPS around an arbitrary origin
Next
- Measure two or three walls with a tape to quantify ② LiDAR and ③ RS error
- ③ texture: export as 3D Tiles to keep textures, or cross-check once in Windows RS
- Show view-dependent colour (SH) for ④/⑤ on the web (larger formats such as SOG)
- Wire into the vacant-space service: send from the app and arcAI builds all five and refreshes this page