feat(viz): drone-relative LiDAR scan frame - #75
Conversation
LidarScan.scan(origin, rot?) now accepts an optional quaternion. The canonical scan pattern (built in a drone-local frame at construction) is rotated by `rot` per call so the cone yaws / pitches / rolls with the drone. Pass identity (or omit `rot`) for the existing world-axis- aligned behaviour. Why now: - The LiDAR demo cone landed in PR #72 was world-axis-aligned, which reads correctly when a drone is hovering with identity orientation but looks visibly wrong as soon as the drone yaws. Mounting the scan on the drone's `rot` quaternion takes the cone with it — smallest visible-impact PR on the loose-ends list. Implementation: - `_rays[i].direction` is now an independent mutable Vec3 tuple instead of aliasing the canonical `dirs[i]`. Each scan() either copies dirs[i] (when no rot) or applies the Rodrigues rotation formula (when rot is provided) into that tuple. ~12k tuple writes per 4096-ray scan — negligible. - effects.ts:_updateLidar passes drone.rot if it looks well-formed (length-4 array), otherwise undefined. Bundle: main 808,803 B (under 819,200 cap, +487 bytes for the rotation branch + the slightly larger ray-prep loop). Validation: typecheck, vite build, dotnet Release all pass. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Warning Rate limit exceeded
To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Code Review
This pull request enables orientation-aware LiDAR scans by allowing an optional rotation quaternion to be passed to the scan method, ensuring the scan pattern follows the drone's yaw, pitch, and roll. The implementation uses the Rodrigues rotation formula to transform pre-allocated ray directions in real-time. Feedback was provided to optimize the rotation loop by pre-calculating doubled quaternion components, which reduces the number of multiplications performed per ray.
…p) (#76) * perf(viz): hoist `2*q.xyz` outside the LiDAR rotation loop Addresses Gemini's medium-priority comment on PR #75: the Rodrigues form `v' = v + 2 * q.xyz × (q.xyz × v + q.w * v)` had `2 *` evaluated inside the loop. Pre-computing `qx2 = qx*2`, `qy2`, `qz2` once outside the loop and using them in the final cross-product writes saves 3 multiplications per ray ≈ 12k per 4096-ray scan. Mathematical equivalence — `2 * (qy * tz - qz * ty)` becomes `qy2 * tz - qz2 * ty`. Same numerical result. Tiny perf win, but a clean follow-up. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * perf(viz): use 3x3 rotation matrix for LiDAR scan rotation Replace the per-ray Rodrigues form with a quaternion-derived 3x3 rotation matrix computed once outside the loop. The rotation is constant for every ray in a scan, so the matrix-vector multiply (9 mul + 6 add per ray) beats Rodrigues (15 mul + 12 add per ray) — saves ~24k mults on a 4096-ray scan beyond what `1d48a2c` already trimmed. Output equivalent for unit quaternions; observable behaviour unchanged. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Summary
LidarScan.scan(origin, rot?)now accepts an optional quaternion. Thecanonical scan pattern (built in a drone-local frame at construction)
is rotated by
rotper call so the cone yaws / pitches / rolls withthe drone. Pass identity (or omit
rot) for the previousworld-axis-aligned behaviour.
This is item #1 from the loose-ends list — smallest visible-impact PR.
The PR #72 demo had the cone reading correctly when a drone hovers
with identity orientation, but visibly wrong the moment the drone
yaws. With this PR, the LiDAR cloud follows the drone's heading.
What changed
client/webgpu/lidar.ts:_rays[i].directionis now an independent mutableVec3(no longeraliases the canonical
dirs[i]).scan()gains optionalrot?: Quatsecond arg. When provided, eachdirection is rotated via the standard Rodrigues form:
v' = v + 2 * q.xyz × (q.xyz × v + q.w * v)(used by gl-matrix /Three.js — valid for unit quaternions). When omitted,
dirs[i]iscopied verbatim.
rays[i].directionsothey match the actual ray that was traced, not the canonical
pattern.
client/effects.ts:_updateLidarpassesdrone.rotif it looks well-formed(length-4 array). Falls back to
undefined(world-axis scan) forany malformed-or-missing rotation.
Performance
~12 k tuple writes per 4096-ray scan (3 per ray × 4096) plus ~30 FLOPS
each when rotating. At 1 Hz that's ~120 KFLOPS — comfortably below
noise level. No new GPU buffer allocations; no GC pressure (still
mutating pre-allocated tuples in place from PR #73).
Bundle impact
+487 B for the rotation branch + the slightly larger ray-prep loop.
Test plan
npm run typecheckpassesnpm run buildpasses (no new warnings)dotnet build -c Releasepasses (pre-push hook)LiDAR cloud rotating with the drone (cone follows the drone's
heading, not stuck to world axes).
fallback unchanged.
rot(e.g.null, missing field):_updateLidardetects the length-mismatch and falls back to world-axis scan
with no crash.
What's deferred
by a fixed body-frame vector). Trivial extension once a sensor
mount spec lands.
scan resolutions/ranges). Currently one global LidarScan instance.
ring-buffered
LosQueryManager(lidarslot, capacity 4096,slotCount 3) is sized for one scan in flight at a time; multi-drone
needs either a higher slotCount or per-drone managers.
🤖 Generated with Claude Code