Body rebuild step 0: Generic6DOFJoint3D on Box3D (fork patch 2) — ball w/ cone/twist + torque-capped muscle motor, weld, drive

- addons/godot-box3d/bin/libgodot-box3d.so rebuilt from fork branch generic-6dof-joint
  (weld patch + 6DOF); .vendor/box3d-generic-6dof.patch exported
- SixDofSpike: type, ball pivot/swing, cone+twist limits, muscle holds 2.94 N·m lever at 10 N·m
  cap and fails at 1.5, tracks moving target, drive follows + push-off reaction, weld rigid,
  live flag toggles — PASS x3; all existing spikes PASS x3 on the new binary
- research/godot-box3d-6dof.md (mapping, units, C# muscle recipe); HANDOFF/AGENTS pointers

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
FoxyzandClaude Opus 5.5 committed 2026-10-02 05:10:45 +03:00
1 parent 329b7bf143
commit 3a990c6dbe
7 files changed
+896 -2

No files matched your search

+48
View File
@@ -0,0 +1,48 @@
# Addon patch 2: Generic6DOFJoint3D on Box3D (2026-10-02)
Second local patch to the godot-box3d fork (after the ConeTwist→weld patch, `godot-box3d-weld.md`). Purpose:
the joint primitives for the Project-TX-style muscle ragdoll (`nimso-project-tx.md`, `vr-physics-rig-hexabody.md` §4).
- Fork branch `generic-6dof-joint` (on top of `rigid-weld-joint`) in `.vendor/godot-box3d`, commit "Expose Box3D
joints through Godot's Generic6DOFJoint3D"; patch file `.vendor/box3d-generic-6dof.patch`. NOT pushed to
`github.com/Foxyz1302/godot-box3d` yet (owner decision). Linux binary only (same rebuild recipe as the weld
patch: `cmake --build build --parallel 12` in `.vendor/godot-box3d`, copy `bin/libgodot-box3d.so` to
`addons/godot-box3d/bin/`; stock binaries stay in `addons/godot-box3d/bin-stock/`).
- Files: `src/joints/box3d_generic_6dof_joint_impl_3d.{hpp,cpp}` (new), `src/servers/box3d_physics_server_3d.cpp`
(`_joint_make_generic_6dof` + param/flag get/set dispatch; was a hard error).
## Mapping (configuration-based — Box3D has no general 6-DOF constraint)
| Godot configuration | Box3D joint | Notes |
|---|---|---|
| all 3 linear axes locked (limit on, lower ≥ upper, no linear spring/motor), angular not fully locked or angular motor/spring on | `b3SphericalJoint` = **BALL** | joint **X = twist axis** (angular X limits = twist range); swing cone symmetric, half-angle = largest \|limit\| of angular Y/Z (warned if Y/Z differ); angular spring → rotation spring to the angular equilibrium (Euler, Godot default YXZ); angular **motor = torque-capped velocity motor** |
| everything locked, no angular motor/spring (the Godot default) | `b3WeldJoint` = **WELD** | rigid at the creation pose |
| any linear axis free/springy/motored | `b3MotorJoint` = **DRIVE** | springs pull frame B onto frame A shifted by the equilibrium points (linear + Euler); force/torque caps = Linear/Angular **MotorForceLimit** (0 = uncapped); motor target velocities add a velocity drive; linear limits NOT enforced (warned) |
- **Units differ from Godot/Jolt**: spring STIFFNESS = frequency in **Hz**, DAMPING = **damping ratio** (Box3D
soft constraints are mass-independent). Choose ~5–15 Hz, ratio ~1.
- Motor target velocities are per joint axis in **joint frame A**; the impl converts to Box3D's world-space relative
angular/linear velocity at set time using body A's current rotation → set them EVERY TICK (they are a PD output).
- Flags and limits **rebuild** the Box3D joint (warm start lost — set them once); motor velocities, force limits,
springs and equilibrium points apply **live**. Configure before `AddChild` (as with every joint here).
- Bullet-era params (limit softness/restitution/damping, ERP, angular force limit) are ignored.
## Muscle recipe (C#, used by `scripts/SixDofSpike.cs`)
```csharp
// BALL joint: angular limits as the anatomical range, EnableMotor on X/Y/Z, AngularMotorForceLimit = strength (N·m)
Quaternion rel = frameAWorld.Inverse() * frameBWorld; // current joint rotation, frame-A coordinates
Vector3 err = BodyMath.RotationError(targetRel, rel); // axis*angle in frame-A coordinates
Vector3 w = (err * Kp).LimitLength(maxSpin); // PD velocity
joint.SetParamX(Generic6DofJoint3D.Param.AngularMotorTargetVelocity, w.X); // …Y, …Z
```
The solver applies at most `AngularMotorForceLimit` torque per step — strength is a real cap, leverage emerges.
## Proof — `scenes/sixdof_spike.tscn` ("6DOF: overall PASS", 3× identical)
server type `Type6Dof`; BALL pivot holds (≤ 0.7 mm) while swinging 100°; cone 30° / twist 10° hold under hard torque
(31.3° / 11.6° peak — Box3D soft-limit overshoot); muscle PD holds a 1 kg × 0.6 m lever (2.94 N·m gravity load)
horizontal with a 10 N·m cap (0.0°) and FAILS with 1.5 N·m (drops 107°); tracks a 60° raise to 0.0°; DRIVE follows a
moving target to 0.000 m; a hand driven into a wall never penetrates it and pushes the 10 kg anchor body AWAY
(−0.82 m — push-off reaction; pulling toward a fixed point is the climbing case); all-locked = rigid (0.13°); 90
live flag toggles stay finite. All existing spikes (weld, physics, grab, body, collapse, arm) PASS 3× on the new binary.