Added pmxRigidBodyConstraint command - #9
Merged
Conversation
…ata) - rigid_body_constraint_cmd.hpp/.cpp: native C++ pmxRigidBodyConstraint command (create mode only — the default). Appends ONE PMX joint to an pmxPhysicsNode's 'joints' array at the next free index, replacing the former Python _set_joint_attributes. Pure-interface header; all helpers in an anonymous namespace (same design as pmxRigidBody). Conversions match the old Python writer exactly: frame translate Z-flip, frame rotate MMD radians -> Maya degrees with the handedness flip, and limits/springs VERBATIM (angular stays in PMX radians — the node hands angular values to Bullet unchanged). Validates: joint type 0..5, bodyA/bodyB against the current body count, -index == next free index. - MayaMMD.cpp: register/deregister the command. - rigid_body_builder.py: populate the 'joints' array through the command after every body exists (constraints reference bodies by index). - Import suite: assert joints count + first-joint data mirror the PMX. - 11 new command integration tests (mock scene, no PMX); cmd suite 47 passed, import suite passes with 319 bodies / 496 joints on Miku. - CHANGELOG entry.
…nt names, self-constraint guard Harsh-review findings (PR #9) and fixes: 1. P1 BUG — asymmetric limits were stored MIRRORED. The MMD->Maya conversion is the reflection F = diag(1,1,-1) (Z-flip + rotation negation on X/Y), and the joint limits live in the FRAME's local space, so they must transform under the same reflection. The old writer (and this PR's first cut) passed them through verbatim: a rotation about local X/Y negates under conjugation, so the [min,max] interval negates AND swaps; linear Z negates (local Z axis reverses) so its interval negates AND swaps; angular Z and springs are invariant. On the test model 429/496 joints have asymmetric angular limits (e.g. chest min -0.524..max +0.087) — without the fix they allow rotation in the wrong sense. Confirmed against blender_mmd_tools (which applies the mapping to location limits and negates+swaps rotation limits). Fix: linearMin' = (x, y, -max.z), linearMax' = (x, y, -min.z); angularMin' = (-max.x, -max.y, min.z), angularMax' = (-min.x, -min.y, max.z); springs verbatim. 2. P2 CONSISTENCY — the joint frame was stored in world space while the bodies store group-space rest poses (pmxRigidBody converts). With an identity physics group (import) they coincide; a transformed group would detach the frames from the bodies. Fix: store the frame in group space (world * groupWorld^-1), mirroring pmxRigidBody. 3. P3 DATA FIDELITY — PMX joint names were dropped (the node had no joint-name attributes; bodies store theirs). Fix: add jointNameLocal/jointNameUniversal to the node (additive, not hashed in the config signature like the body names) + -name/-nameUniversal flags + the builder passes them. 4. P4 HARDENING — bodyA == bodyB (a body constraining itself) is degenerate; PMX never produces it (0/496). Fix: reject it. Coverage added: asymmetric limit reflection (real-model chest values), linear-Z swap, group-space frame with a transformed group, self-constraint rejection, joint names; the import suite now asserts the first joint's name/frame/angular-limit reflection against real PMX data. cmd suite 50 passed (36 body + 14 constraint), import 8, node 17.
Second review pass on PR #9: - Refactor: matrixFromTR (translate + XYZ euler degrees -> MMatrix) was duplicated in the rigid_body_cmd and rigid_body_constraint_cmd anonymous namespaces. Consolidated into mmd::maya::matrixFromTR in maya_utils.hpp; both commands now use the shared helper (unused deg2rad using-decls removed). - Hardening: a PMX body that fails to create during import (the builder logs and continues) silently shifts every later PMX body index, so the constraints (and future write-back) would reference WRONG bodies. _populate_rigid_bodies now returns the number created, and create_physics_from_pmx_data logs a prominent warning when it does not match len(pmx_data.rigid_bodies). Verified: all 12,548 joints across every asset model have valid, distinct body references (0 self-joints, 0 out-of-range) — the bodyA!=bodyB and range validations are import-safe for the whole database. cmd 50 passed, import + node suites pass, clang-tidy clean.
Convert the pmxPhysicsNode joints[] jointType child from a plain long to an MFnEnumAttribute, matching the bodyGroupId/bodyColliderType/ bodyPhysicsMode pattern: one field per PMX JointType (Spring6Dof/SixDof/ P2P/ConeTwist/Slider/Hinge, values 0..5), so the Attribute Editor shows a dropdown instead of a raw integer. The command writes it via setShort (like bodyGroupId); readJointData / config signature read it via asInt, unchanged. Storable/keyable set in the enum block (kept out of the numeric loop). - jointType is an enum dropdown in the Attribute Editor. - New cmd test: attributeQuery(listEnum) exposes the six fields; writing type=4 (Slider) round-trips as 4. - cmd suite 51 passed (36 body + 15 constraint), import + node pass.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds the
pmxRigidBodyConstraintcommand that populates thepmxPhysicsNode'sjointsarray with PMX rigid-body constraint data at import time.What
pmxRigidBodyConstraintcommand (create mode only) — native C++ (rigid_body_constraint_cmd.hpp/.cpp), pure-interface header + anonymous-namespace helpers, same design aspmxRigidBody(Added pmxRigidBody command #8).joints[]at the next free index; returns the new index.jointBodyA/jointBodyB,jointType, joint frame, linear/angular limits and springs.bodyA/bodyBin range against the current body count;-indexmust be the next free index. Edit/query rejected (not implemented yet).MayaMMD.cpp+CMakeLists.txt.rigid_body_builder.pypopulatesjoints[]through the command after every body exists (constraints reference bodies by index).