| Name | Message | Date |
|---|---|---|
| 📁 capture | 1 day ago | |
| 📁 render | 1 day ago | |
| 📁 replay | 1 day ago | |
| 📁 sink | 1 day ago | |
| 📁 splatgen | 1 day ago | |
| 📄 .gitignore | 1 day ago | |
| 📄 Cargo.lock | 1 day ago | |
| 📄 Cargo.toml | 1 day ago | |
| 📄 PLAN.md | 1 day ago | |
| 📄 README.md | 1 day ago |
Plan — kinect-view
Working plan for the project. The build order doubles as a rough roadmap: check items off as they land.
Goal
A Rust program that captures a fixed 3-camera rig, constructs a live Gaussian-splat scene each frame, and renders it from a virtual camera positioned anywhere between the physical cameras.
Output:
- an egui UI for viewing and steering the virtual camera
- a virtual webcam for Teams/Slack on Linux
Runs on Windows/ARM and Ubuntu 24/x86.
Core design
No 3DGS training. Per-frame construction of the Gaussian field (surfel splatting), handed to Brush's renderer as a library.
Smoothness comes from footprint-sized anisotropic splats:
- two tangential scales = depth × pixel_size / focal_length
- flat disk aligned to the depth-map normal
- few-mm thickness along the normal
- opacity ~0.9–0.99
- front-to-back alpha blend
Occluded far side of the face — the MVP uses an ellipsoid proxy: fit a head/shoulders ellipsoid per frame to the Kinect head point cluster; side-camera pixels are projected onto the proxy for position and recolored from the side camera.
Head mirroring is a future upgrade — kinect-one/libfreenect2 provide no head
tracking (verified against the crate source: RGB-D only), so there's no
head-orientation input to drive a symmetry plane. If mirroring is added
later, it needs a head-pose estimator added on top (e.g., a lightweight
head tracker or a face-landmark model), not a driver feature.
Longer-term upgrade path beyond both: monocular depth (ort) on side
cameras, metric-anchored to the Kinect head position.
Pipeline per frame
- Capture — Kinect v2 RGB+depth via kinect-one; two webcams via nokhwa. Extrinsics known exactly from the existing offline calibration; camera overlap regions remain a runtime sanity check.
- Depth preprocess — bilateral filter (3–5 px), flier removal, background culling → ~50–150k active splats.
- Splat construction — footprint-sized surfels from Kinect depth; occluded-region splats from the ellipsoid proxy, recolored from side cameras, inflated thickness, lower confidence weight.
- Render — Brush renderer (WebGPU/Burn), fresh Gaussian list per frame, 30–60 fps target; virtual camera pose from the UI.
- Sinks — egui UI (virtual-camera control); Linux: v4l2loopback virtual webcam. Windows: no built-in sink; capture the UI window via OBS yourself.
Workspace layout
The workspace root of this repository is the kinect-view/ tree:
kinect-view/
├── capture/ # kinect-one, webcams, frame sync
├── replay/ # recorded/synthetic datasets — dev & CI without hardware
├── splatgen/ # depth filter, normals, surfels, ellipsoid proxy fill
├── render/ # Brush integration, virtual camera
└── sink/ # egui UI + v4l2loopback (Linux)
Build order
- 1. replay + render + UI with synthetic data
- 2. splatgen on recorded Kinect frames
- 3. Live Kinect capture + ellipsoid proxy recoloring from side cameras
- 4. v4l2loopback sink
- 5. Polish: cross-camera color calibration, WB-lock webcams, seam tuning
Risks (ranked)
- kinect-one on Windows/ARM64 → replay mode first, fork-and-fix.
- Ellipsoid-proxy quality at nose/cheek contours → mirroring (with added head-pose estimation) or mono-depth as future upgrades.
- Cross-camera color seams → calibration vs Kinect.
- Frame sync across three async sensors → timestamp-align, tolerate 1-frame skew.
Out of scope
- Training/optimization
- 360° reconstruction
- Windows virtual-webcam driver
- Head mirroring in the MVP (future upgrade requiring a head-pose estimator)