added mesh export preview

This commit is contained in:
ykcheungab
2026-09-20 13:46:58 +08:00
parent 39caecbfda
commit f9662df08c
16 changed files with 2025 additions and 11 deletions
+62
View File
@@ -299,6 +299,68 @@ every object separately, such as cutting or weeding. A failing `min_feature_mm`
alongside a passing `nominal_cell.dots` means the artwork is fragmented, not that
the pattern itself is unprintable.
## Preview the export
`orisys-design preview` opens the built export in a minimal PyOpenGL window so a
revision can be checked before it reaches Studio: the sensing surface highlighted,
the exported housing around it, and the exported camera frustum.
```powershell
python -m pip install -e .[preview] # numpy, PyQt5, PyOpenGL
orisys-design preview sensors/finger-xynova/r01
```
Controls: left-drag orbit, middle/right-drag pan, wheel zoom, `H` toggle housing,
`W` wireframe, `C` frustum. `--self-test` renders one frame, reports how many
mesh pixels were drawn, and exits without waiting for a window — use it to check
a machine's GL setup. `--screenshot PATH` writes that frame to a PNG so a view
can be reviewed or shared without describing it. `--no-housing` and
`--no-frustum` simplify the view.
Normals are crease-aware: faces are grouped per vertex and split where the
dihedral angle exceeds `--crease-angle` (default 35°), so machined edges read as
creases instead of smooth roll-offs. `--smooth` disables splitting. This matters
because the housing is sharp and the sensing surface is not — 13.5% of `frame_L`
edges exceed 30° while the sensing surface has none, and the default leaves its
2508 vertices untouched.
Exit codes: `2` for a missing optional dependency, `3` for a payload that has not
been exported, `4` when no OpenGL context can be created (the offscreen/minimal
Qt platform cannot create one at all, so run on a desktop session).
### Housing is a separate artifact
`export` also writes **`housing.npz`** for the objects in the `ASSEMBLY`
collection, transformed into the same sensor frame as the sensing surface. It is
deliberately *not* merged into `mesh.npz`: `orisys-sdk`'s unroll consumes
`mesh.npz` vertices as the sensing surface, so housing vertices there would
corrupt it. Declare the collections with `--housing-collections` or via
`design.yaml`'s `collections.assembly`.
### Lighting mirrors Studio, by value
This window reimplements a small renderer rather than importing Studio's, so the
look is copied rather than shared. Every mirrored value — clear colour, light
direction, the `0.35 + 0.65 * lambert` shading, housing graphite — lives in
`preview/appearance.py` with the `gl_backend.py` line it came from, and
`tests/test_preview.py` re-reads Studio's source and fails if it changes. That
keeps the duplication honest and makes adopting real reuse a one-module swap.
The sensing surface is drawn in a preview-only highlight colour; Studio colours
it from the measurement LUT instead. Treat this as a design-time check, not the
authoritative renderer.
### One caveat about export units
The exported sensor frame is **not metres**. `origin_sensor` carries a uniform
scale, so a ~21 mm assembly exports with bounds around ±574 units and
`world_to_cam` is a scaled (non-rigid) pose: its rotation column norms are
`0.003937` on Xynova, not `1`. Projection is still self-consistent — all 2508
sensing vertices land inside the 1000×1000 frame — but any consumer that assumes
metres will be wrong. The preview therefore frames the model from its own
bounding sphere rather than Studio's fixed metre limits, and prints a warning
when the pose is not rigid.
Collection check:
```powershell