- What: `VIEW_SHOWS_3D` 加入 `replay`;`app_window` 新增 `_shows_3d()`(可见性与布局共用一个判据) 与 `_splitter_sizes_for()`(预设表里的 3D 槽是"二维布局"的描述,面板打开时从最宽的面板借 `DEFAULT_3D_PANE_WIDTH=340`);`ThreeDPanel` 新增第三个来源标签(实时采集 / 回放:录像不含三维场 / 重算通道:由录像重算,非记录值)与 `set_source_kind()`;`ThreeDCoordinator.show_rest()` 把参考模型 放回屏幕并停止主张测量值(重算停止时调用,否则最后一帧会留在屏幕上);`Mesh3dPanel` 转发这两者, 并新增"加载中"状态的修正:切换传感器再切回来时若该包已加载,直接显示已就绪的画面而不是一条永远 不会被替换的"正在加载"。 - Why: 录像里没有三维场(raw_*.mp4 是原始相机图像,`depth.stored=false`,CSV 只有力值),所以纯回放只能 显示参考模型;但「从视频重算力值」本来就把同一个运行路径指向录像的原始视频,而采集线程上的三维 sink 早已注册——因此重算一开始面板就会收到真实的形变帧。这两件事必须由界面区分:一个是"没有测量", 一个是"当前算法对这段录像会说什么",把后者当成记录值展示就是另一种 `display_illustrative`。 - Verification: apps/studio 全量通过(test_scene3d_view.py 32 项,含"回放里面板可见且标注正确""重算时 标注切换""停止重算后清回参考模型""实时视图标为实时";test_scene3d_coordinator.py 15 项,含 show_rest 与"停止时在飞的帧不会随后被显示");ui_check 570 项 0 失败(新增"已安装包必须被加载并标注来源"); locale_check 0 缺失;仓库内工程包经 validate_scene 全部 ok。 - Not in this change: 逐帧保存展开场/深度(记录格式变更,设计文档明确否掉);重算通道本身(已存在,本次 只是把它的帧接到面板上);示意位移(仍需 SDK lift + 已确认尺度)。
5.9 KiB
Scene asset tools
Offline tools for the three-dimensional view. They never run in the application:
the app loads a compiled package (.oryscene) and nothing else.
| tool | what it is for |
|---|---|
compile_scene.py |
a Blender export (+ optional housing GLB) → one .oryscene package |
validate_scene.py |
the checks the loader and the compiler must agree on; the release gate |
probe_gl.py |
what this machine's OpenGL actually is (exit 0 GPU, 3 software, 4 no context) |
bench_scene.py |
per-stage p50/p95 of the running view (--cpu-only for the pure CPU cost) |
soak_scene.py |
long run: RSS trend and the queue bound |
Run them with the repository's own interpreter, from orisys-app:
$py = '.venv-build\Scripts\python.exe'
Compiling the shipped finger sensor
The runtime asset is sensors/finger/assets/30fps-0703: it is what
sensors/finger/manifest.json names (assets_dir), and its unroll map
(unroll_map_uv_s0.4.npz, out size 300×280, source_scale 0.4) matches
camera.resolution_stitch in sensor.json, which is the grid the live optical flow
is computed on.
Do not compile assets/visualization/flatten_remap.npz: it is a 1024×1024
domain, so every live frame would be refused with field_domain_mismatch
(300x280 vs 1024x1024). That map belongs to offline visualisation.
$sdk = 'D:\orisys_ws\orisys-sdk\sensors\finger\assets\30fps-0703' # or the copy in apps/studio/config
# 1) state the unit (the importer never guesses it) and read what it measured
& $py tools\scene_assets\validate_scene.py --legacy-dir $sdk --map "$sdk\unroll_map_uv_s0.4.npz"
# 2) compile
& $py tools\scene_assets\compile_scene.py `
--legacy-dir $sdk `
--map "$sdk\unroll_map_uv_s0.4.npz" `
--meters-per-source-unit 0.001 `
--output apps\studio\config\sensors\finger\scene\finger-display-1.0.0.oryscene
# 3) verify
& $py tools\scene_assets\validate_scene.py apps\studio\config\sensors\finger\scene\finger-display-1.0.0.oryscene
--meters-per-source-unit is a physical statement about the sensor, not a
formatting choice. The measured mesh extent is 15.81 × 15.0 × 7.5 source units
(1032 vertices, 1974 triangles); the shipped finger surface is about 15.8 mm across,
so one source unit is one millimetre and the value is 0.001. If the mechanical
drawing says otherwise, state that number instead — nothing downstream can tell the
difference, and a wrong factor looks plausible.
Expected result: 1032 vertices, 1974 triangles, geometry_id starting
1a2e0e92…, a 56 KB package, and validate_scene.py reporting every check ok.
Where the application looks for a package
preference.json→"scene3d_package": "<path>"(an absolute path; also the way to point a developer build at a freshly compiled package);<config>/sensors/<sensor>/scene/*.oryscene— for the studio app that isapps/studio/config/sensors/finger/scene/;- nothing: the pane reports the directory it searched and the compile command above, and the two-dimensional views keep working.
The SDK's own sensors/ tree is not searched (the app prefers its local
config/sensors bundles). Compile into the app's scene/ directory, or set
scene3d_package.
Release packages (signature, optional encryption, platform lock)
All three are optional and independent of the plain package above:
& $py tools\scene_assets\compile_scene.py --legacy-dir $sdk --map "$sdk\unroll_map_uv_s0.4.npz" `
--meters-per-source-unit 0.001 `
--sign-key keys\build-ed25519.pem --sign-key-id build-2024 `
--write-verify-key keys\build-ed25519.pub.pem `
--encrypt-key-id finger-display --key-file keys\finger-display.key `
--lock-from-probe docs\architecture\gl-report-windows-dev.json `
--output apps\studio\config\sensors\finger\scene\finger-display-1.0.0.oryscene
--sign-keysigns the manifest (and therefore every entry hash, the compatibility information and the platform lock). The private key stays on the build machine; the client ships only--write-verify-key's public half.--encrypt-key-id+--key-fileadditionally seal the content with AES-256-GCM. Encryption never replaces signing. Reading a sealed package needs theprotected-assetsextra (cryptography); a plain package does not.--lock-from-probetakes the platform lock (OS, architecture, GL profile, vendor, renderer, minimum texture size, "no software rasteriser") from aprobe_gl.pyreport. A machine the lock excludes loses the 3D pane, with the reason, and keeps everything else.--encrypt-key-idwithout--key-file, or with no crypto backend installed, is refused rather than silently writing a plain package that looks protected.
Release gate:
& $py tools\scene_assets\validate_scene.py <package> `
--key-file keys\finger-display.key --key-id finger-display `
--verify-key keys\build-ed25519.pub.pem --require-signature
Performance and long runs
# per-stage p50/p95 of the running view (needs a real window system)
$env:QT_QPA_PLATFORM = 'windows'
& $py tools\scene_assets\bench_scene.py --frames 600 --output perf.json
& $py tools\scene_assets\bench_scene.py --cpu-only --frames 500 --vertices 20000 --output perf-cpu.json
& $py tools\scene_assets\bench_scene.py --package <package> --key-file keys\finger-display.key `
--key-id finger-display --verify-key keys\build-ed25519.pub.pem --output perf-real.json
# long run: the release gate is two hours in the GUI mode (it is the stricter one)
& $py tools\scene_assets\soak_scene.py --minutes 120 --fps 30 --output soak.json
& $py tools\scene_assets\soak_scene.py --no-window --minutes 10 --fps 60 --output soak-cpu.json
The committed reports for the developer machine are
docs/architecture/perf-report-windows-dev.json and
docs/architecture/soak-report-windows-dev.json; the stage-by-stage acceptance, the
failure samples and the compatibility notes are in
docs/architecture/studio-3d-stages.md.