Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 75 additions & 0 deletions pull-request-description.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# PR: Improve rig fitting, helper controls, and weight smoothing

## Summary

This pull request improves the rig fitting workflow for manually positioned skeletons and softens several problem areas in generated skin weights.

The main functional changes are:

- added mesh-drag vertex snapping with a user-controlled snap strength slider
- added condensed main-chain visibility toggles in Position Joints mode
- centered pelvis, spine, chest, neck, and head placement against the mesh instead of the front surface
- reduced finger joint helper circle size and made helper visibility respect hidden chains
- prevented branching parent bones such as chest and pelvis from being auto-rotated when child bones are moved independently
- expanded weight smoothing around pelvis, thighs, buttocks, shoulders, clavicles, neck, and upper arms
- added focused regression tests for the new placement, chain grouping, rotation, and smoothing behavior

## Why

These changes target the issues seen during rig fitting and auto-weighting on humanoid avatars:

- joint placement needed stronger assistance when dragging bones over the mesh
- main chains needed to be easier to isolate visually during joint positioning
- centerline bones were drifting too far toward the front of the character
- shoulder and hip areas needed softer, more natural blending similar to the imported DAE reference
- chest and shoulder orientation could drift when moving branching child bones

## What changed

### Position Joints workflow

- Added a snap strength slider with a `0` to `20` range for mesh-drag snapping.
- Added visible-chain checkboxes for condensed main chains, with fingers grouped into the hand chain.
- Wired helper visibility changes so hidden chains are removed from the active helper display.

### Bone placement and orientation

- Added nearest-vertex snap blending during mesh drag.
- Added mesh-centerline targeting for primary centerline bones.
- Applied automatic centerline snapping after skeleton load for pelvis, spine, chest, neck, and head chains.
- Preserved template orientation on branching parent bones during independent child movement.

### Weight smoothing

- Expanded boundary smoothing to keep more multi-bone influence at seam regions.
- Added along-bone gradients so bone centers stay dominant while joints retain blended influence.
- Added stronger symmetric socket smoothing for:
- pelvis to thigh
- spine/chest/neck to shoulder chain
- clavicle to upper arm
- Added pelvis-basin smoothing to improve the glute and central pelvis region.
- Strengthened torso-to-upperarm blending in the front shoulder area.

### Helper and utility updates

- Added condensed chain grouping utilities for visibility and labeling.
- Added smaller helper points for finger joints.
- Ensured hidden chain roots affect helper rendering consistently.

### Investigation support

- Added temporary scripts under `tmp/` for comparing skeleton topology and weight profiles during debugging.

## Testing

- `npm run build`
- Focused regression tests were added for:
- chain grouping utilities
- mesh drag snapping and centerline helpers
- independent branching-bone movement behavior
- advanced weight smoothing boundaries

## Notes for review

- This PR includes temporary analysis scripts in `tmp/` because they were used to validate skeleton and weight-profile differences during the investigation.
- The changes are concentrated in the rig-editing and skin-weight smoothing flow rather than import/export behavior.
57 changes: 57 additions & 0 deletions restore-point-2026-05-08-position-joints-topbar.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# Restore Point - 2026-05-08 (Position Joints Topbar)

Date: 2026-05-08
Workspace: c:\Users\jeffa\mesh2motion-app

## Summary

This restore point captures the Position Joints UI refactor into a create-only topbar layout, with a dedicated stylesheet and horizontal Visible Chains layout matching the reference screenshot.

## Key behavior

- Position Joints UI renders as a topbar only on the Create page during Edit Skeleton.
- The right-side tool panel is hidden in Edit Skeleton on Create page.
- Visible Chains checkboxes flow horizontally across the topbar row.
- Controls row is centered with compact spacing; Back/Finish sit to the far right after undo/redo.

## Files touched

- src/create.html
- src/create-position-joints.css
- src/Mesh2MotionEngine.ts
- src/lib/processes/edit-skeleton/StepEditSkeleton.ts

## Detailed notes

### Create page topbar layout

- Added `create-page` class on `body` in `create.html`.
- Injected a dedicated stylesheet `create-position-joints.css`.
- Moved Edit Skeleton UI (`#skeleton-step-actions`) into `#position-joints-topbar`.
- Topbar rows:
- Row 1: Selected bone label centered.
- Row 2: Visible Chains checkbox list (label removed).
- Row 3: Controls row with Position by mesh volume, Preview toggle, Vertex Snap slider, Mirror/Move options, Undo/Redo, Back/Finish.

### Scoped CSS

- All topbar styles scoped under `body.create-page` to avoid bleeding into other pages.
- `body.create-page.edit-skeleton-topbar` toggles topbar visibility and hides `#tool-panel`.
- Visible Chains list forced to horizontal layout via flex row and a custom fieldset class.
- Controls row centered with 10px gaps between items.

### Process step hook

- `Mesh2MotionEngine` toggles `edit-skeleton-topbar` on the Create page when entering/leaving `ProcessStep.EditSkeleton`.

### Visible Chains rendering

- `StepEditSkeleton` renders the chain checkboxes into a fieldset with class `position-joints-chain-fieldset` to enforce horizontal layout and avoid duplicate labels.

## Verification checklist

- Create page (Use Your Model) shows topbar only in Edit Skeleton step.
- Explore and Retarget pages are unaffected.
- Visible Chains checkboxes flow horizontally in one row.
- Back/Finish buttons appear to the right of undo/redo.
- Controls row items are centered and tightly spaced.
35 changes: 35 additions & 0 deletions restore-point-2026-05-08.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Restore Point - 2026-05-08

Date: 2026-05-08
Workspace: c:\Users\jeffa\mesh2motion-app

## Summary

This restore point captures the state after tightening the Visible Chains UI and improving default spine layout for the Fox rig.

## Visible Chains grouping changes

- Condensed spine, head, and quadruped leg chains into fewer checkboxes by grouping chain roots.
- Spine chains now anchor to the rootmost spine bone so multiple spine segments appear under one checkbox.
- Head chains anchor to the main head bone (tips/end bones grouped under head).
- Quadruped front legs group under front leg shoulder anchors (left/right).
- Quadruped back legs group under back leg pelvis anchors (left/right).

Files touched:
- src/lib/Utilities.ts
- src/lib/Utilities.test.ts

## Fox spine default layout

- Added a fox-specific spine spread on skeleton load to place spine bones horizontally.
- The spine chain spreads along the mesh horizontal axis and interpolates height between pelvis and head.
- Runs after centerline snapping during the skeletonLoaded flow.

Files touched:
- src/lib/processes/edit-skeleton/MeshDragBonePlacement.ts
- src/lib/EventListeners.ts

## Notes

- Fox spine distribution uses mesh bounds and pelvis/head positions as hints.
- If rig bone names differ from spine/pelvis/head naming, adjust the matchers in MeshDragBonePlacement.
12 changes: 12 additions & 0 deletions restore-point-2026-05-09-edited-armature-skinning.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Restore Point - 2026-05-09 (Edited Armature Skinning)

Date: 2026-05-09
Workspace: c:\Users\jeffa\mesh2motion-app

## Summary

This restore point captures the fix that uses the edited skeleton transforms when generating the armature for skinning, preventing collapsed meshes after finishing joint placement.

## Files touched

- src/lib/processes/edit-skeleton/StepEditSkeleton.ts
15 changes: 15 additions & 0 deletions restore-point-2026-05-09-orbit-target-axis-gizmo.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Restore Point - 2026-05-09 (Orbit Target Axis Gizmo)

Date: 2026-05-09
Workspace: c:\Users\jeffa\mesh2motion-app

## Summary

This restore point captures the updated work area layout with the axis gizmo snapped to the current orbit target and the view helper sized at 2x.

## Files touched

- src/lib/SceneEnvironmentManager.ts
- src/Mesh2MotionEngine.ts
- src/lib/CustomViewHelper.ts
- src/styles.css
13 changes: 13 additions & 0 deletions restore-point-2026-05-09-view-helper-2x.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Restore Point - 2026-05-09 (View Helper 2x)

Date: 2026-05-09
Workspace: c:\Users\jeffa\mesh2motion-app

## Summary

This restore point captures the view helper axis gizmo at 2x size with snap-to-axis behavior preserved.

## Files touched

- src/lib/CustomViewHelper.ts
- src/styles.css
8 changes: 8 additions & 0 deletions restore-point-2026-05-09.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Restore Point - 2026-05-09

Date: 2026-05-09
Workspace: c:\Users\jeffa\mesh2motion-app

## Summary

This restore point captures the state before adding centerline snapping controls, rotation spinner adjustments, and additional joint placement UI updates.
36 changes: 36 additions & 0 deletions src/Mesh2MotionEngine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,9 @@ export class Mesh2MotionEngine {
this.skeleton_helper.setHideRightSideJoints(
is_edit_skeleton_step && this.edit_skeleton_step.is_mirror_mode_enabled()
)
this.skeleton_helper.setHiddenChainRoots(
is_edit_skeleton_step ? this.edit_skeleton_step.hidden_bone_chain_root_names() : []
)
}

public update_a_pose_options_visibility (): void {
Expand Down Expand Up @@ -251,6 +254,7 @@ export class Mesh2MotionEngine {
this.is_model_gizmo_active = true
this.transform_controls.attach(this.load_model_step.model_meshes())
this.transform_controls.setMode('translate')
this.transform_controls.size = 1
this.transform_controls.enabled = true
}

Expand Down Expand Up @@ -292,6 +296,11 @@ export class Mesh2MotionEngine {
this.is_transform_controls_dragging = false
}

public update_orbit_controls_state (allow_orbit: boolean): void {
const orbit_disabled = this.edit_skeleton_step.is_orbit_rotation_disabled()
this.enable_orbit_controls(allow_orbit && !orbit_disabled)
}

public get is_mesh_drag_mode_dragging (): boolean {
return this.mesh_drag_bone_placement.is_dragging()
}
Expand Down Expand Up @@ -343,6 +352,7 @@ export class Mesh2MotionEngine {

// update the current process step variable
this.update_current_process_step(process_step)
this.update_position_joints_topbar_state(process_step)

// clean up things related to steps in since we can navigate back and forth
this.edit_skeleton_step.cleanup_on_exit_step()
Expand Down Expand Up @@ -403,6 +413,8 @@ export class Mesh2MotionEngine {
this.edit_skeleton_step.begin(this.scene, this.load_skeleton_step.skeleton_type())
this.update_edit_bone_interaction_mode()
this.transform_controls.setMode(this.transform_controls_type) // 'translate', 'rotate'
this.update_transform_controls_size()
this.update_orbit_controls_state(true)

this.sync_skeleton_helper_joint_visibility()

Expand Down Expand Up @@ -451,6 +463,20 @@ export class Mesh2MotionEngine {
return this.process_step
} // end process_step_changed()

private update_position_joints_topbar_state (process_step: ProcessStep): void {
const body = document.body
if (!body.classList.contains('create-page')) {
return
}

if (process_step === ProcessStep.EditSkeleton) {
body.classList.add('edit-skeleton-topbar')
return
}

body.classList.remove('edit-skeleton-topbar')
}


private animate (): void {
requestAnimationFrame(this.animate)
Expand All @@ -468,6 +494,10 @@ export class Mesh2MotionEngine {
this.renderer.render(this.scene, this.camera)

// view helper
const orbit_target = this.scene_environment.get_orbit_target()
if (orbit_target !== null) {
this.view_helper.center.copy(orbit_target)
}
this.view_helper.render(this.renderer) // updates current viewport
if (this.view_helper.animating) {
this.view_helper.update(delta_time) // updates animation when clicking on axis
Expand All @@ -494,17 +524,23 @@ export class Mesh2MotionEngine {
case 'translate':
this.transform_controls_type = TransformControlType.Translation
this.transform_controls.setMode('translate')
this.update_transform_controls_size()
break
case 'rotation':
this.transform_controls_type = TransformControlType.Rotation
this.transform_controls.setMode('rotate')
this.update_transform_controls_size()
break
default:
console.warn(`Unknown transform mode selected: ${radio_button_selected}`)
break
}
}

private update_transform_controls_size (): void {
this.transform_controls.size = 1
}

public changed_transform_controls_space (radio_button_selected: TransformSpace | undefined): void {
if (radio_button_selected) {
this.transform_space_type = radio_button_selected
Expand Down
Loading