Skip to content

Physics system - #3

Open
sstarosz wants to merge 18 commits into
mainfrom
feature/physics-system
Open

Physics system#3
sstarosz wants to merge 18 commits into
mainfrom
feature/physics-system

Conversation

@sstarosz

@sstarosz sstarosz commented Aug 7, 2026

Copy link
Copy Markdown
Owner

No description provided.

@sstarosz sstarosz self-assigned this Aug 7, 2026
@sstarosz sstarosz added the Physics Physics system label Aug 7, 2026
@sstarosz sstarosz modified the milestones: mik, 0.2.0 Aug 7, 2026
sstarosz added 17 commits August 8, 2026 00:42
- Phase 3: remove guide transforms and write-back constraints; node writes solved joint-local poses directly into joints, deriving parent inverse from parent body's Bullet transform
- Phase 4: hash config inputs (FNV-1a); rebuild Bullet world in-place when bodies/joints/gravity/fps change, keeping chains glued to current skeleton pose
- Kinematic anchors now feed from joints' world matrices with baked body<->bone offsets
- Rewrite physics discovery to trace node connections instead of guide transforms
- Skeleton reset rewinds solver by toggling fps to force config rebuild
- Update behavioral tests to swing root bone and verify cycle fix, no rewind teleport, and config edits take effect
- Import speedup: scalar body children via OpenMaya plug API, joints still on cmds.setAttr
- Add btTransformToRowMatrix and rowMatrixMultiply helpers with unit tests
- Update docs/changelog for Phase 3/4 changes
- Extract Bullet engine, math, and shared value types into mmd/core static library
- Decouple physics_node as a Maya adapter over mmd::core::Simulation
- Rename mmdPhysicsNode -> pmxPhysicsNode (node, commands, files, docs, tests)
- Move physics_node and rigid body commands under pmx prefix to match PMX naming
- Add unit tests for math and simulation engine (Maya-free)
- Add integration tests for pmxRigidBody / pmxRigidBodyConstraint commands
- Document the core/adaptor split and the new node name across all docs
sstarosz added a commit that referenced this pull request Aug 9, 2026
- cmake/FindMaya.cmake: prefer the cached SDK matching MAYA_VERSION before
  scanning the other cached SDKs (newest-first) as a fallback, so a Maya-2027
  build never resolves the 2026 SDK just because it was cached earlier.
- CMakePresets.json: drop the unused ci preset (configure + build) and the
  redundant BUILD_NATIVE_MODULE=ON override (the option already defaults to
  ON), and add explicit Debug/Release configuration to the build presets.
- docs/CPPDevelopment.md: replace the removed ci-preset instructions with
  the maya2026-release -DBUILD_TESTS=ON flow.
- CHANGELOG.md: note the SDK-resolution fix and the preset cleanup.

Extracted from feature/physics-system (PR #3) so the build-system fixes can
be reviewed independently of the physics feature.
sstarosz added a commit that referenced this pull request Aug 9, 2026
- vcpkg.json: add Bullet 3.25 (float precision) as the first C/C++ dependency.
- CMakeLists.txt: fail with clear instructions when no CMake toolchain is
  configured, then resolve Bullet via find_package(Bullet CONFIG REQUIRED).
- CMakePresets.json: add the hidden with-vcpkg preset that activates the
  vcpkg toolchain from \, and make all maya* presets inherit it.
- .github/workflows: set up vcpkg (lukka/run-vcpkg) in pr-checks and release.
- .gitignore: ignore third_party/ and vcpkg_installed/.
- docs/CPPDevelopment.md: document vcpkg setup + troubleshooting.
- README.md: list vcpkg as a prerequisite and note auto-install of deps.
- CHANGELOG.md: note vcpkg dependency management under [Unreleased].
- tests/CMakeLists.txt: drop the stale 'Re-enable the CI preset (ci)' comment
  (the ci preset was removed in PR #4).

Part of the feature/physics-system (PR #3) split — stacked on PR #4
(fix/cmake-build-fixes).
sstarosz added a commit that referenced this pull request Aug 9, 2026
- vcpkg.json: add Bullet 3.25 (float precision) as the first C/C++ dependency.
- CMakeLists.txt: fail with clear instructions when no CMake toolchain is
  configured, then resolve Bullet via find_package(Bullet CONFIG REQUIRED).
- CMakePresets.json: add the hidden with-vcpkg preset that activates the
  vcpkg toolchain from \, and make all maya* presets inherit it.
- .github/workflows: set up vcpkg (lukka/run-vcpkg) in pr-checks and release.
- .gitignore: ignore third_party/ and vcpkg_installed/.
- docs/CPPDevelopment.md: document vcpkg setup + troubleshooting.
- README.md: list vcpkg as a prerequisite and note auto-install of deps.
- CHANGELOG.md: note vcpkg dependency management under [Unreleased].
- tests/CMakeLists.txt: drop the stale 'Re-enable the CI preset (ci)' comment
  (the ci preset was removed in PR #4).

Part of the feature/physics-system (PR #3) split — stacked on PR #4
(fix/cmake-build-fixes).
This was referenced Aug 9, 2026
sstarosz added a commit that referenced this pull request Aug 10, 2026
* Cmd: add native pmxRigidBody command (create mode, data + kinematic anchors)

Native C++ pmxRigidBody command — the single body-modification path for
pmxPhysicsNode.  Create mode only, SIMULATION IS DISABLED: writes the full
body DATA (PMX shape_size verbatim into bodyShapeSize, group/mask, physics
mode via the core Simulation::PhysicsMode enum) and binds FOLLOW_BONE bodies
to their related joint through the kinematic-anchor input.  Dynamic bodies
are data-only (no write-back, no stepping) — edit/query/remove and the
rigid-body-constraint command are later PRs.

Adapted from the PR #3 draft to the merged node schema:
  - bodyShapeSize (single float3) instead of bodyRadius/bodyExtents/bodyLength
  - core Simulation::PhysicsMode (no node-side enum)
  - single groupInverseWorldMatrix instead of per-anchor anchorParentInverseMatrix

Registration in MayaMMD.cpp + CMake source list + integration tests wired
into the 'cmd' suite (11 new tests).

* Cmd: apply clang-format reflow to rigid_body_cmd.cpp

* Cmd: refactor pmxRigidBody to pure interface + populate bodies at import

Design cleanup of the pmxRigidBody command (per review):

- Rename rigid_body_cmd.h -> rigid_body_cmd.hpp and make it a PURE
  interface: all private static helpers (resolveSolver, doCreate,
  matrixFromTR, worldMatrix, connectOrReplace, jointPmxBoneIndex,
  resolveBone) moved into the .cpp's anonymous namespace.  The header now
  exposes only kName/creator/syntaxCreator/doIt/isUndoable.
- Add shared plug utilities to maya_utils.hpp (setPlugMatrixValue,
  setPlugDouble3, connectOrReplace) so the constraint command reuses them
  in the next PR instead of duplicating.
- const/constexpr pass: use physics_math deg2rad/rad2deg (constexpr),
  constexpr clamp01, const locals, 3-arg findPlug (non-deprecated).
- Bring back rigid-body population in rigid_body_builder.py: every PMX
  rigid body is now added to the node via pmxRigidBody at import (data +
  kinematic anchors for FOLLOW_BONE).  Simulation still disabled (no
  joints/write-back/time).  Dict lookups keyed by enum VALUE so a duplicate
  enum class (mayapy double-load of mmd.core) cannot break the mapping.
- Import test now asserts bodies mirror the PMX rigid bodies (count + first
  body data).
- Expand cmd integration tests: write-back K offset baked, wiring-field
  defaults, per-collider shape_size verbatim, MMD->Maya rest-pose
  conversion, kinematic anchor ordering with multiple bodies.

Verified: node/cmd/import suites pass, C++ unit tests 31/31, clang-tidy
clean, ruff/clang-format clean.

* style: format cmd suite registration in TEST_SUITES

* Fix: reload rigid_body_builder in plugin init so bodies appear after plugin reload

mmd.maya.pmx.rigid_body_builder was missing from plugin.py's _MMD_MODULES
reload list.  In a live Maya session the module stays cached in sys.modules
with the OLD (empty-node) create_physics_from_pmx_data, so recompiling the
.mll and reloading the plugin kept importing the stale builder and bodies
never appeared on the node.

Add it to the list, BEFORE pmx_scene_builder (which imports
create_physics_from_pmx_data from it) so the fresh module is picked up when
pmx_scene_builder is reloaded.

* Review: make connectOrReplace truly idempotent + add 4 more cmd tests

- connectOrReplace now returns early when dst is already driven by the SAME
  source, instead of queuing a duplicate connect that fails.  This makes the
  repeated groupInverseWorldMatrix re-connect (one per kinematic body create)
  a real no-op instead of a swallowed kFailure.
- Add cmd integration tests: numeric -bone <pmxBoneIdx> resolution, query/edit
  rejection, invalid-target rejection, missing-solver-argument rejection.

* Review: fix anchor offset group-scale round-trip, clamp -group to 0..15

- rigid_body_cmd.cpp: anchor offsets (joint-anchored AND static-collider)
  now build the world matrix directly from world-space T/R via
  matrixFromTR(worldT, worldR) instead of the group-space round-trip
  matrixFromTR(localT, localR) * groupWorld, which dropped scale from
  the offset (the exact bug the K-offset write-back comment documents).
- rigid_body_cmd.cpp: clamp -group to the PMX 0..15 range with plain
  ifs (replaces a nested ternary that tripped clang-tidy).
- rigid_body_cmd.hpp: document -group range in the header.
- test_pmx_rigid_body_cmd_integration.py: add test_group_clamped
  (-group=-5 -> 0, -group=99 -> 15); format.

* Docs: add pmxRigidBody command entries to CHANGELOG
sstarosz added a commit that referenced this pull request Aug 11, 2026
* Sim: wire the physics simulation (time-driven + Phase-3 write-back)

Makes the imported pmxPhysicsNode simulation actually RUN — ported from the
PR #3 draft's wiring and adapted to the current builder:

- _create_physics_solver: connect time1.outTime -> node.time (the node
  declares itself non-cacheable, so the evaluation manager steps the
  Bullet world every frame; an empty world is a valid no-op).
- _wire_dynamic_write_back (called after every body and joint exists):
  * group.worldMatrix[0] -> groupWorldMatrix (DG-fallback write-back);
  * bodies[i].bodyParentBodyIndex = the parent bone's rigid body, so the
    node derives M_parent = K[parentBodyIndex] from the parent BODY's
    solved transform (no DG feedback cycle);
  * joint.parentInverseMatrix -> bodyParentInverseMatrix DG fallback ONLY
    when the parent bone has no rigid body;
  * bodies[i].bodyResetAnchorIndex = nearest kinematic ancestor (scrub-back
    rewind);
  * outTranslate/outRotate -> joint.translate/rotate LAST (PHYSICS_BONE is
    rotation-only).  Maya auto-inserts the standard unitConversion between
    the float3 outputs and the joint angle attrs.
- _compute_reset_anchor_map, step_physics, write_back_physics helpers.
- Physics-mode comparisons keyed by .value (duplicate-enum safe).

Tests (import suite, real model):
- Physics Wiring: time + groupWorldMatrix connected; 285 dynamic joints
  driven (262 with translate); 281 parent-body refs; 4 DG fallbacks; 285
  reset anchors; no DG parentInverse when the parent has a body.
- Simulation Steps: BEHAVIOURAL — 248/285 dynamic joints move when the
  root bone swings (sim is alive).
- Write-back Moves Bone: BEHAVIOURAL — the solver drives a skirt joint
  ~40 deg in 30 frames (mesh-binding signal).
- 11 passed (8 prior + 3 new); cmd + node suites green.

* Review: unit-typed write-back outputs (no unitConversion), enable caching, drop unused helper

Addresses review feedback on PR #10:

1. UNIT-TYPED OUTPUTS — the pmxPhysicsNode outTranslate/outRotate children
   were unitless k3Double, so connecting them to joint.translate/rotate
   forced Maya to auto-insert a unitConversion per body.  The children are
   now MFnUnitAttribute kDistance (outTranslateX/Y/Z) / kAngle
   (outRotateX/Y/Z), exactly like transform.translate/rotate, and the
   builder connects the compounds DIRECTLY — no conversion nodes.  Values
   are identical (verified behaviourally: dR=40.684 both before and after).
   Angles are written in degrees explicitly: MAngle's default constructor
   unit is RADIANS, which silently inflated every angle by 180/pi (caught
   by the write-back test: dR 2331 vs 40.7).

2. CACHING — the explicit setAttr(node.caching, 0) is gone: the node's
   getCacheSetup() already declares the STATEFUL solver non-cacheable via
   setUnsafeNode (caching its outputs would freeze the sim — the mayaBullet
   bug this node was built to fix), so the attribute stays at its default.

3. write_back_physics removed (unused); step_physics kept and now used by
   the import behavioural tests (replacing a local copy).

Tests: wiring test now asserts each outTranslate/outRotate destination is
the JOINT directly (never a unitConversion — the 84 unitConversions from
the bone builder's IK controls are unrelated).  cmd/import/node all green.

* Refactor: drop anchorOffset + groupInverseWorldMatrix inputs (derive, don't store)

Big simplification of the pmxPhysicsNode schema (breaking — re-import
required).  Two matrix inputs were redundant:

1. anchorOffset — the kinematic body<->joint rest offset
   (bodyRestWorld * jointRestWorld^-1) is the EXACT INVERSE of
   bodyWriteBackOffset (K = jointRestWorld * bodyRestWorld^-1), which is
   already baked per body for the write-back.  The node now derives each
   kinematic anchor's offset as K[bodyIndex]^-1 (the anchor loop already
   knows the body index); identity for joint-less static colliders, exactly
   as before.

2. groupInverseWorldMatrix — the exact inverse of groupWorldMatrix (a
   single input the builder already connects for every model).  The node
   derives the inverse internally.

Removed: the two attributes + their registration/affects/signature entries,
the pmxRigidBody command's anchorOffset writes and group-inverse
connectOrReplace, and the node's anchorOffset/groupInverse reads.  The
command now only writes anchorWorldMatrix (joint world or pinned rest).

Verified data-equivalent: 248/285 joints move, write-back dR=40.684 —
identical before/after.  cmd/import/node suites green; clang-tidy clean.

* Refactor: drop bodyParentInverseMatrix DG fallback (derive parent, don't store)

* Refactor: drop configVersion hashing (compare definitions, don't hash bytes)

* Refactor: run the Bullet world in world space (drop the groupWorldMatrix input)

* Refactor: evaluate the write-back chain directly on btTransforms (drop the MMatrix round-trip)

* Refactor: drop legacy rigid-body visual-guide path (obsolete since native solver)

* Docs: mark rigid body/joint simulation as implemented, drop legacy "not supported" validation entries

* Refactor: store bodyParentBodyIndex as long, read as int (drop short truncation)

* Style: wrap long print statement for consistent formatting
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Physics Physics system

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant