diff --git a/CHANGELOG.md b/CHANGELOG.md index dc1213c..25f6ff5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,67 @@ _尚无未发布变更。_ --- +## [1.2.0] — 2026-04-24 + +**Phase 2B complete — Viewport 2.0 visualization + drag-drop installer.** +mRBFNode remains a pure `kDependNode` (Phase 2A contract untouched); +visualization is carried by a new auxiliary locator `mRBFShape` +connected via message attribute and hosting `mRBFDrawOverride`. +Artists get per-center heatmap (HM-1), prediction-field heatmap +(HM-2), and X-Ray rendering. A drag-drop Python installer ships +the plugin + Maya module files to user preferences with zero- +residue uninstall. Validated on Maya 2022 and Maya 2025. + +### Added +- `mRBFShape` locator node (typeId `0x00013A01`) — hosts the + Viewport 2.0 draw override via `drawdb/geometry/rbfmax/mRBFShape` + classification. Connects to a `mRBFNode` via `sourceNode` + message attribute. Per-shape `drawEnabled` / `sphereRadius` / + `heatmapMode` / `gridResolution` / `gridExtent` / `gridZ` / + `xrayMode` attributes (Slice 13 / 14 / 15). +- `mRBFDrawOverride` — renders trained centers as filled spheres in + Viewport 2.0. Three rendering stages: kOff (white), kCenterWeights + (per-center viridis from L2 weight norm — HM-1), kPredictionField + (G² sample grid colored by `predict_batch` output norm — HM-2). + X-Ray depth priority (5 / 10) toggles whether the overlay + renders on top of scene geometry. +- **Drag-drop installer** (`installer/drag_drop_install.py`) — Maya + artists install/uninstall the plugin by dragging a single Python + file onto the Maya viewport. Uses Maya Module System (`.mod` file + + per-version plug-in subdirs under `~/Documents/maya/modules/`). + Zero-residue uninstall. Supports Maya 2022 + 2025. +- **Phase 1 additive getters** (const noexcept): `RBFInterpolator:: + centers()` (Slice 13) and `::weights()` (Slice 14) expose fit + state to viewport consumers without re-parsing saved JSON. + +### Fixed +- Installer path resolution used `os.path.expanduser('~')` which on + Windows honors the `HOME` env var (set by Git Bash / MSYS / Cygwin / + WSL to `Documents`), producing `%USERPROFILE%/Documents/Documents/ + maya/modules/` paths Maya never scans. Switched to + `cmds.internalVar(userAppDir=True)` inside Maya and `USERPROFILE` + as fallback. +- Installer uninstall on Windows now handles `.mll` file locks via + `_safe_rmtree` retry loop and `_force_overwrite_tree` file-level + fallback. Uninstall dialog distinguishes clean removal vs partial + (Maya restart needed). + +### Architectural notes +- **Phase 2A contract preserved**: `mRBFNode` stays a pure + `kDependNode` with `compute()` / `try_load()` unchanged since + Slice 10A-12. Five additive public getters (all const, + noexcept where applicable) bridge the viewport layer. +- **Cross-version `.mll` bit-identity** retired in Slice 13 — the + `OpenMayaRender` + `OpenMayaUI` link libs diverged across the + 2022 / 2025 devkits, so byte-wise equality across versions is + no longer a maintained invariant (only symbolic / API equivalence). +- **mRBFShape R-44 invariant**: zero `MFnTypedAttribute(MFnData:: + kString)` on the locator. Empirical Slice 13 Path A failure + made this the permanent discipline; Slice 14 + 15 attribute + additions obeyed it (enum + bool + double + int only). + +--- + ## [1.1.0] — 2026-04-21 **Phase 2A complete — Maya node integration + training command.** diff --git a/CMakeLists.txt b/CMakeLists.txt index 9c2836d..91fe5be 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,7 +9,7 @@ cmake_minimum_required(VERSION 3.14) project(rbfmax - VERSION 1.1.0 + VERSION 1.2.0 DESCRIPTION "Industrial-grade RBF interpolation kernel and Maya plug-in" LANGUAGES CXX ) diff --git a/DEVLOG.md b/DEVLOG.md index 4978a61..5fd984f 100644 --- a/DEVLOG.md +++ b/DEVLOG.md @@ -14,6 +14,141 @@ --- +## 2026-04-24 · Slice 16 — Phase 2B close-out + v1.2.0 + +**Scope**: Pure retrospective + version bump. Zero functional code changes; zero test changes; zero installer changes. `project(rbfmax VERSION …)` 1.1.0 → 1.2.0, `RBFMAX_MAYA_PLUGIN_VERSION` likewise; new `[1.2.0]` CHANGELOG entry; this DEVLOG entry consolidates Phase 2B. + +### Phase 2B scope summary + +Phase 2B opened with Slice 13 (Path B recovery from a failed architectural attempt) and closes here with v1.2.0. Five PRs merged to `main`: + +| PR | Slice | Date | Summary | +|----|-------|------|---------| +| #11 | Slice 13 | 2026-04-22 | mRBFShape + mRBFDrawOverride (Path B). Zero-touch of mRBFNode; classification `drawdb/geometry/rbfmax/mRBFShape` | +| #12 | Installer | 2026-04-22 | Drag-drop installer with Maya Module System (two follow-up commits for Windows HOME env and .mll file lock, both merged back onto this PR) | +| #13 | Slice 14 | 2026-04-22 | HM-1 per-center viridis coloring | +| #14 | Slice 15 | 2026-04-23 | HM-2 prediction-field grid + X-Ray (XR-1) | +| #? | Slice 16 | 2026-04-24 | This PR — retrospective + v1.2.0 | + +Installer binary sync (Slice 13 snapshot → Slice 15 build) happened in a non-PR session action (`package.py` + mayapy-triggered reinstall, `.mll` is gitignored). The installer deploy state is now consistent with main HEAD. + +### Quantitative summary + +Based on `git diff --stat origin/main..` at each slice merge point: + +| Slice | PR | Files changed | LOC added | LOC removed | Net | +|-------|----|---------------|-----------|-------------|-----| +| 13 | #11 | 16 | 1214 | 14 | +1200 | +| 14 | #13 | 17 | 659 | 7 | +652 | +| 15 | #14 | 12 | 676 | 12 | +664 | +| Installer + 2 follow-ups | #12 | 6 (+2 follow-ups) | ~1050 | ~30 | +~1020 | +| **Phase 2B total (excluding this slice)** | | **~51 unique files** | **~3600** | **~63** | **+~3540** | + +Test count trajectory: +- Slice 13 opened: Phase 1 138 + adapter (H3+C6+D8+E8) = 163 +- Slice 14: +1 Phase 1 (D-group `WeightsGetterReflectsFit`) + 8 F-group = 172 +- Slice 15: +8 G-group = 180 +- **Phase 2B close**: adapter + Phase 1 = **180 tests** (vs 163 at open). 0 regressions. + +F-stop register trajectory: +- #1-4: Phase 2A (documented in earlier slices) +- #5 (Slice 14): viridis polynomial → LUT pivot +- #6 (Slice 15): Windows .mll file lock during rebuild +- #7 (Installer PR #12 follow-up #1): Windows `HOME` env var double-Documents path +- #8 (Installer PR #12 follow-up #2): Windows `.mll` unload + reinstall file lock +- #9 (This session, installer sync): installer binary lag (Slice 13 snapshot vs Slice 15 build) — not a code bug; resolved by `package.py` + reinstall + +All **#5-#9 resolved** at Phase 2B close. None rolled into Phase 2C. + +### Invariant tracking — Phase 2B discipline + +| Invariant | Enforced across | Status | +|-----------|-----------------|--------| +| Phase 1 kernel / solver / interpolator **behavioral** code — zero touch | Slices 13 / 14 / 15 / 16 | ✅ `build` ctest 139/139 every slice; only `centers()` (Slice 13) + `weights()` (Slice 14) additive const getters added | +| Slice 10A / 11 / 12 `mRBFNode::compute()` / `try_load()` / attribute set — zero touch | Slices 13 / 14 / 15 / 16 | ✅ Five additive public getters total: `is_loaded()` + `centers_for_viewport()` (Slice 13) + `weights()` (Slice 14) + `input_dim()` + `predict_batch_samples()` (Slice 15). All const, never enter the DG | +| Slice 13 `mRBFDrawOverride::supportedDrawAPIs` / `boundingBox` / `isBounded` / classification — zero touch | Slices 14 / 15 / 16 | ✅ Only `prepareForDraw` + `addUIDrawables` implementation logic extended per explicit allowance | +| Slice 13 `mRBFShape` pre-existing attrs — zero touch | Slices 14 / 15 / 16 | ✅ `aSourceNode` / `aDrawEnabled` / `aSphereRadius` never modified; new attrs (`aHeatmapMode` Slice 14; `aGridResolution` / `aGridExtent` / `aGridZ` / `aXRayMode` Slice 15) only appended | +| **R-44** — `mRBFShape` zero `MFnTypedAttribute(MFnData::kString)` | All Phase 2B slices | ✅ Enum + bool + double + int + message only. Locked after Slice 13 Path A failure | +| Slice 14 `map_scalar_to_color` / `compute_center_colors` LUT — zero touch | Slice 15 / 16 | ✅ Slice 15 only added `build_grid_sample_points` + `compute_grid_colors` alongside | + +### Tech-debt status table + +| ID | Origin | Description | Phase 2B status | +|----|--------|-------------|-----------------| +| T-10 | Slice 10A | Development-range typeId `0x00013A00`; must request Autodesk permanent block before distribution | **ROLLED to Phase 2C** (pre-distribution block) | +| T-16 | Slice 13 | Manual `connectAttr mRBFNode.message mRBFShape.sourceNode` — convenience command `rbfmaxAttachShape` candidate | **ROLLED to Phase 2C** (Qt UI + command scope) | +| T-17 | Slice 14 | `centers_for_viewport()` returns positions only; HM-1 needs per-center colors path | ✅ **Resolved Slice 14** — separate `compute_center_colors` + `center_colors` vector in `RbfDrawData`; `T-17 closed` | +| T-18 | Slice 14 | DrawOverride uses fixed `(-10, +10)` bbox | **ROLLED to Phase 2C** (tighten once scene-bbox integration lands) | +| T-19 | Slice 14 | Per-frame min/max normalization for HM-1 makes color spread context-dependent | **ROLLED** (alternatives like log / percentile clipping deferred to Phase 2C UX pass) | +| T-20 | Slice 14 | LUT precision only 1e-2 at three anchors; intermediate v values may drift ~0.05 vs matplotlib viridis | **ROLLED** (visual review of HM-1 + HM-2 in production rigs will determine if tighter LUT justified) | +| R-44 | Slice 13 | `MPxLocatorNode` + `MFnTypedAttribute(kString)` triggers Maya `registerNode kFailure` — root cause unresolved | **PERMANENT empirical constraint** — treated as invariant on mRBFShape going forward; no Phase 2C work planned | +| R-45 | Slice 14 | `HeatmapMode::kPredictionField` fallback to kOff | ✅ **Resolved Slice 15** — HM-2 activated; fallback removed | +| **F-stop #6 mitigation candidate** | Slice 15 | Hot-loading `.mll` from build dir locks file → blocks subsequent CMake link | **ROLLED to Phase 2C** as `scripts/dev_unload.py` keybind helper | + +**Phase 2C roll-over items (6 total)**: T-10, T-16, T-18, T-19, T-20, plus the dev_unload.py helper. + +### Phase 2B reviewer discipline — summary + +- **Rule 3 "Maya docs unverified"**: triggered F-stop #5 (polynomial viridis reference in spec did not match matplotlib); triggered A2 pre-flight discovery in Slice 15 that `MUIDrawManager` has no `DepthPriority` enum → raw-integer fallback (5 / 10) locked with comments. +- **Rule 4 "systematic assumption elimination"**: executed in force during Slice 13 Path A (4+ hours ruling out classification / MString / devkit / registration order / Maya version / output-string attrs / inheritance / stale artifacts before Path B retreat); also in Installer PR #12 follow-up #1 (Windows `HOME` env var hunt). +- **Rule 5 formalized** (new, from Slice 13): "For any Maya API feature first attempted in Phase 2, identify the canonical Autodesk sample pattern. When a spec deviates from that pattern, flag the deviation as pre-dispatch risk and prefer the less-ambitious scope matching the sample exactly." Slice 13 Path B (separate `mRBFShape`) matches the `cvColor` / `footPrint` sample pattern; Slice 14 / 15 inherited that correctness. + +### Phase 2C entry conditions + +Phase 2C will build on the viewport + installer foundation. Four **specific deliverables** blocked until Phase 2B v1.2.0 ships: + +1. **Qt UI panel** — shelf button + property editor extension for `mRBFShape`; visualizes grid + heatmap mode picker + reload trigger without channel-box hunting. +2. **Menu bar integration** — `initializePlugin` populates a top-level `RBFMax` menu (Slice 13 explicitly scoped this out; Phase 2C activates via `installer/scripts/` via the pre-reserved directory). +3. **`rbfmaxAttachShape` command** (T-16) — one-shot command to create mRBFShape + connectAttr, given a mRBFNode. Shipped as MPxCommand registered by the plugin. +4. **`scripts/dev_unload.py`** helper (F-stop #6 mitigation) — Maya userSetup keybind that wraps `cmds.unloadPlugin('rbfmax_maya')` + scene cleanup; for developers iterating on the build tree. + +None of the four require Phase 1 changes or further `mRBFNode` / `mRBFShape` attribute additions beyond polish. + +### Validation (Slice 16-specific) + +- `build/` (Phase 1 pure, no Maya): clean reconfigure + build + ctest → **139/139 PASS** after `project() VERSION 1.1.0 → 1.2.0`. +- `build-adapter/`: incremental build + ctest → **180/180 PASS** (unchanged from Slice 15; confirms the test count invariant held across version bump). +- Maya 2022 plugin (`build-maya-2022/` clean reconfigure): **0 warn / 0 err**. +- Maya 2025 plugin (`build-maya-2025/` clean reconfigure): **0 warn / 0 err**. +- Maya 2022 × 4 smokes (hellonode / predict / train / viewport): all PASS. +- Maya 2025 × 4 smokes: all PASS. +- **Version injection assertion** (new, Slice 16 unique step): + ``` + mayapy -c "cmds.loadPlugin(...); assert cmds.pluginInfo(..., version=True) == '1.2.0'" + ``` + Passed on both Maya 2022 and Maya 2025 — confirms `configure_file` → `plugin_info.hpp` → `MFnPlugin::registerNode` version-string path still wires correctly after the CMake bump. + +### `.mll` byte sizes (v1.2.0, reference only) + +- Maya 2022: **528,384 bytes** (unchanged from Slice 15 — `"1.2.0"` and `"1.1.0"` are both 5 chars, no section re-alignment) +- Maya 2025: **529,408 bytes** (likewise unchanged) + +Confirms no accidental code drift between v1.1.0 and v1.2.0 on `main` — the only runtime difference is the version string baked into the DLL. + +### Tag push (out of this PR's scope) + +Deferred until after merge: + +```bash +git tag -a v1.1.0 d624c79 -m "Phase 2A close-out — Slice 12 baseline" +git tag -a v1.2.0 -m "Phase 2B close-out — HM-1 + HM-2 + X-Ray + installer" +git push origin v1.1.0 v1.2.0 +``` + +`v1.1.0` is a retro tag on Slice 12's `d624c79` (the CMake bump commit), per Slice 12 DEVLOG's "tag deferred to Phase 2B end" note — that promise is now fulfilled. + +### File changes summary + +Modified: +- `CMakeLists.txt` — project VERSION 1.1.0 → 1.2.0 (single-line diff) +- `maya_node/CMakeLists.txt` — `RBFMAX_MAYA_PLUGIN_VERSION` 1.1.0 → 1.2.0 (single-line diff) +- `CHANGELOG.md` — new `[1.2.0]` section +- `DEVLOG.md` — this Slice 16 entry + +Zero touches on any Maya / kernel source, any test, any installer file, any smoke script. + +--- + ## 2026-04-22 · Slice 15 — Heatmap HM-2 (prediction field) + X-Ray (XR-1) **Scope**: Phase 2B third slice. Activates `HeatmapMode::kPredictionField` (the field reserved in Slice 14 with a fallback to `kOff`) by sampling the trained interpolator on a 2D grid in local space and rendering each sample as a small viridis-colored sphere. Adds `xrayMode` so the locator's centers + grid render on top of scene geometry. No version bump. diff --git a/README.md b/README.md index 08e639e..cc7d74b 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Industrial-grade Radial Basis Function interpolation kernel for Autodesk Maya and game engines. [![CI](https://github.com/891458249/RBF_MAX/actions/workflows/ci.yml/badge.svg)](https://github.com/891458249/RBF_MAX/actions/workflows/ci.yml) -[![Version](https://img.shields.io/badge/version-1.1.0-blue)](https://github.com/891458249/RBF_MAX/releases/tag/v1.1.0) +[![Version](https://img.shields.io/badge/version-1.2.0-blue)](https://github.com/891458249/RBF_MAX/releases/tag/v1.2.0) [![License](https://img.shields.io/badge/license-Apache%202.0-green)](LICENSE) [![C++](https://img.shields.io/badge/C%2B%2B-11-orange)](https://en.cppreference.com/w/cpp/11) diff --git a/maya_node/CMakeLists.txt b/maya_node/CMakeLists.txt index 311bb29..f8aa89e 100644 --- a/maya_node/CMakeLists.txt +++ b/maya_node/CMakeLists.txt @@ -27,7 +27,7 @@ if(RBF_BUILD_MAYA_NODE) # into the plugin at compile time for MFnPlugin registration and # future diagnostic use. # ------------------------------------------------------------------ - set(RBFMAX_MAYA_PLUGIN_VERSION "1.1.0") + set(RBFMAX_MAYA_PLUGIN_VERSION "1.2.0") set(RBFMAX_MAYA_PLUGIN_VENDOR "891458249 / RBF_MAX") # R-09 self-check: 0x00013A00 = 80384 (< 0x7FFFF development-range cap). set(RBFMAX_MAYA_NODE_TYPEID "0x00013A00")