|
|
# Blockbench UV Packer
|
|
|
|
|
|
A Blockbench plugin that auto-packs per-face UV models with ML-assisted share-merge suggestions, mirror detection, multi-variant texture support, and pow2 canvas cropping. One button, end-to-end.
|
|
|
|
|
|
Originally built for the Decocraft project's bbmodel corpus (~600 models). The ML model in `ml/share_model.json` is trained on that corpus; you can retrain on your own corpus with the scripts in `ml/`.
|
|
|
|
|
|
## What it does
|
|
|
|
|
|
When you click **Tools → Pack UVs (Decocraft)**, the plugin:
|
|
|
|
|
|
1. Collects all per-face-UV cubes in the project (skips box-UV cubes; works in mixed-mode projects)
|
|
|
2. **Heuristic share-merge** — faces with the same UV rect (modulo flip) collapse to one packed slot. Median 80% rect dedupe across the training corpus.
|
|
|
3. **ML share-merge suggestions** (if `share_model.json` is loaded) — surfaces candidate merges the heuristic missed. A pixel-similarity gate filters out false positives. Each suggestion shows a thumbnail preview before you accept.
|
|
|
4. **Mirror-orientation detection** — for cross-rect merges, the planner samples each member's pixels in 4 orientations and picks the one that minimizes RGBA diff against the canonical, so mirror-painted symmetric regions stay mirror-correct after merging.
|
|
|
5. **Skyline pack** — biggest-first, top-to-bottom, left-to-right. Outliner-group ordering clusters same-group faces. Auto-expands the working canvas if rects don't fit.
|
|
|
6. **Variant texture rearrangement** — alternate skin textures (any texture in the project with no faces pointing to it) get the same pixel rearrangement as the driver texture, so swapping skins still lines up.
|
|
|
7. **Pow2 crop** — final texture canvas is shrunk to next-power-of-2 of the actual packed bbox.
|
|
|
8. Single Undo entry covers everything.
|
|
|
|
|
|
## Install
|
|
|
|
|
|
1. In Blockbench: **File → Plugins → Load Plugin from File**
|
|
|
2. Pick `decocraft_uv_packer.js`
|
|
|
3. (One-time) **Tools → Load Share Model JSON** → pick both `ml/share_model.json` and `ml/inference_test_cases.json` (multi-select). The model is cached to `localStorage` after first load. The plugin self-tests the JS LightGBM evaluator against the test cases on every load — if it doesn't match LightGBM exactly, it refuses to use the model.
|
|
|
|
|
|
## Workflow
|
|
|
|
|
|
- Open a project that uses per-face UVs
|
|
|
- **Tools → Pack UVs (Decocraft)**
|
|
|
- If the ML model finds candidates, a dialog opens with thumbnails. Uncheck any pair where the previews disagree visually. Click **Accept & Pack** (or **Pack without merging** to skip ML suggestions).
|
|
|
- The plugin packs, crops to pow2, and rearranges variants. Toast reports `Packed N faces into M slots · canvas A×B → C×D`.
|
|
|
|
|
|
## Retraining the ML model on your own corpus
|
|
|
|
|
|
If you have your own bbmodel collection and want a model trained on its conventions:
|
|
|
|
|
|
```sh
|
|
|
# 1. Inspect the corpus statistics (optional)
|
|
|
node analyze_uvs.mjs path/to/your/bbmodel/folder
|
|
|
|
|
|
# 2. Extract face-pair training data (~250k labeled pairs from ~600 models)
|
|
|
node ml/extract_pairs.mjs path/to/your/bbmodel/folder
|
|
|
# → produces ml/pairs.csv (~30 MB on a 600-model corpus)
|
|
|
|
|
|
# 3. Train (Python: pip install lightgbm pandas scikit-learn)
|
|
|
cd ml
|
|
|
python train_share_classifier.py
|
|
|
# → updates share_model.json, eval_report.txt, inference_test_cases.json
|
|
|
|
|
|
# 4. In Blockbench: Tools → Load Share Model JSON → pick the new files
|
|
|
```
|
|
|
|
|
|
The training script splits **by model** (not by pair) for held-out evaluation — so the precision/recall numbers in `eval_report.txt` reflect actual generalization to unseen models, not just unseen pairs from already-seen models. The bundled `share_model.json` was trained on the Decocraft corpus and reaches AUC 0.985 / precision 0.96 @ recall 0.88 on 123 held-out models.
|
|
|
|
|
|
## File layout
|
|
|
|
|
|
```
|
|
|
blockbench-uv-packer/
|
|
|
├── decocraft_uv_packer.js Blockbench plugin (single file)
|
|
|
├── analyze_uvs.mjs Corpus stats (per-model density, group overlap, share fraction…)
|
|
|
└── ml/
|
|
|
├── extract_pairs.mjs Build pairs.csv from a bbmodel directory
|
|
|
├── train_share_classifier.py LightGBM trainer + eval + JSON export
|
|
|
├── validate_js_eval.mjs Verifies the JS evaluator matches LightGBM bit-for-bit
|
|
|
├── share_model.json Trained model (350 trees, ~2.5 MB)
|
|
|
├── inference_test_cases.json 50 self-test cases for the plugin
|
|
|
└── eval_report.txt Precision/recall sweep + feature importance from last train
|
|
|
```
|
|
|
|
|
|
## Limitations / non-goals
|
|
|
|
|
|
- **Per-face UV only.** Cubes set to box-UV mode are skipped (counted in the success toast).
|
|
|
- **Same-dimension share-merges only.** The merger collapses faces whose source rects have the same dims (with optional 90°-mirror); it doesn't rotate-to-fit different aspect ratios.
|
|
|
- **Reorient-cubes feature was attempted and dropped.** Auto-rotating cubes for tighter packing fights against either Blockbench's `cube.roll()` (which rotates visually, breaking model assemblies) or requires deriving the full per-(perm × slot) D4-symmetry texture transform (which kept hitting subtle bugs across iterations). If you want a cube reoriented, use Blockbench's built-in Transform → Rotate tools manually before running Pack UVs.
|
|
|
|
|
|
## License
|
|
|
|
|
|
TBD — add the license your project uses.
|