Parent epic: #554
Depends on: Slice A (#555). Best-with: Paint v2 Slice C (#546).
Goal
Paint skin weights with a proper brush — radius, strength, falloff, symmetry, pressure — plus the standard weight-paint utility ops: normalize, mirror, smooth, lock per-bone. Today's BoneWeightOverlay is read-only; this slice makes it interactive.
Scope
- New singleton
SkinWeightController (src/SkinWeightController.{h,cpp}).
- Brush integration:
- Tools:
- Paint (add to active bone's weight, ramping with strength).
- Smear / blur (low-pass filter the weights under the brush).
- Erase (paint zero — bone influence drops to zero, weight redistributed to remaining bones to keep normalized).
- Fill connected (flood-fill a UV-connected island at the active bone, with falloff from the click point).
- Utility ops (no brush — applied to selection or whole mesh):
- Normalize — every vertex's bone weights sum to 1.0.
- Mirror weights — depends on Slice E's bone naming; mirror weights across an axis using
_l/_r (or any configured naming) bone pairs.
- Smooth weights — Laplacian smoothing over the mesh's vertex adjacency (via
HalfEdgeMesh).
- Lock bone — selected bones can't be modified by paint ops (their weights are frozen; other bones absorb redistributions).
- Limit weights — clamp each vertex to at most N influences (default 4 — game-engine constraint).
- Live visualization: extends
BoneWeightOverlay to show active bone weight under the cursor (number readout + heatmap toggle).
- Per-vertex weight inspector: select a vertex (Edit Mode integration), see its bone-weight list, edit a single value numerically.
- Undo:
PaintWeightStrokeCommand (per-stroke, like Paint v2), WeightOpCommand (utility ops). Both mergeable for drags.
Acceptance Criteria
Effort
~10 days, plus 2 buffer if BrushEngine integration needs prototype-then-migrate.
Parent epic: #554
Depends on: Slice A (#555). Best-with: Paint v2 Slice C (#546).
Goal
Paint skin weights with a proper brush — radius, strength, falloff, symmetry, pressure — plus the standard weight-paint utility ops: normalize, mirror, smooth, lock per-bone. Today's
BoneWeightOverlayis read-only; this slice makes it interactive.Scope
SkinWeightController(src/SkinWeightController.{h,cpp}).BrushEngine(Epic: Paint v2 — Gradients, textured brushes, layers, full PBR painting #543 / Slice C Paint v2: Slice C — Layer stack (named, blend modes, opacity, masks, reorder) #546): radius / strength / falloff / pressure / symmetry come for free.TexturePaintControllerand migrate when it lands._l/_r(or any configured naming) bone pairs.HalfEdgeMesh).BoneWeightOverlayto show active bone weight under the cursor (number readout + heatmap toggle).PaintWeightStrokeCommand(per-stroke, like Paint v2),WeightOpCommand(utility ops). Both mergeable for drags.Acceptance Criteria
scene.skel.weight.*.Effort
~10 days, plus 2 buffer if
BrushEngineintegration needs prototype-then-migrate.