5.1 KiB
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:
- Collects all per-face-UV cubes in the project (skips box-UV cubes; works in mixed-mode projects)
- Heuristic share-merge — faces with the same UV rect (modulo flip) collapse to one packed slot. Median 80% rect dedupe across the training corpus.
- ML share-merge suggestions (if
share_model.jsonis loaded) — surfaces candidate merges the heuristic missed. A pixel-similarity gate filters out false positives. Each suggestion shows a thumbnail preview before you accept. - 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.
- 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.
- 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.
- Pow2 crop — final texture canvas is shrunk to next-power-of-2 of the actual packed bbox.
- Single Undo entry covers everything.
Install
- In Blockbench: File → Plugins → Load Plugin from File
- Pick
decocraft_uv_packer.js - (One-time) Tools → Load Share Model JSON → pick both
ml/share_model.jsonandml/inference_test_cases.json(multi-select). The model is cached tolocalStorageafter 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:
# 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.