From 77f3e726aeeb9177b5085203731de4e33b8184a8 Mon Sep 17 00:00:00 2001 From: Axel Meyer Date: Mon, 18 May 2026 21:57:20 +0200 Subject: [PATCH] fix(vagrant): hip-anchors body-relative; leg-orientation procedural MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit User feedback: 'anchorpoints sind hüftgelenke und können sich nicht frei drehen. hüfte bleibt zum körper statisch'. Architecture: - legs.parent = body (was lower_control). Hip position cascades from body.world.rot, so hips stay at body-frame left/right regardless of body rotation. lower_control virtual bone removed (no longer needed). - Procedural 'leg_orientation' sets leg.local.rot = walk_dir - body.rot each frame, so leg.world.rot = walk_dir (independent of body cascade). Requires puppet v0.4.2 per-channel write_bone (walk_anim writes leg.scl while procedural writes leg.rot — disjoint channels). Result: legs visually attach at body's anatomical left/right hips no matter where body faces; stride oscillation aligns with WASD walk direction. Hip position no longer drifts with walk direction. --- init.lua | 14 +++++++++++--- manifest.module | 2 +- rigs/humanoid.rig.json | 5 ++--- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/init.lua b/init.lua index 118f497..36499dc 100644 --- a/init.lua +++ b/init.lua @@ -154,9 +154,17 @@ function M.init(ctx) puppet.play(state.player, "idle", { loop = true }) puppet.play(state.player, "idle_lower", { loop = true }) - -- Procedural lower_control: applies the per-frame wedge rotation (set by update_lower_anim). - puppet.set_procedural(state.player, "lower_control", function(handle, dt) - puppet.write_bone(handle, "lower_control", { rot = state.lower_control_rot_deg }) + -- Procedural leg-orientation: hips are body-relative (legs.parent=body, so + -- cascade-position follows body); the leg ROTATION is overridden each + -- frame to align with walk-direction (independent of body rotation). + -- leg.local.rot = walk_dir_world - body.world.rot → leg.world.rot = walk_dir. + -- write_bone allowed on leg.rot because walk_fwd_lower only writes leg.scl + -- (per-channel guard v0.4.2). + puppet.set_procedural(state.player, "leg_orientation", function(handle, dt) + local _, _, body_rot = puppet.bone_world_transform(handle, "body") + local leg_local_deg = state.lower_control_rot_deg - math.deg(body_rot) + puppet.write_bone(handle, "leg_l", { rot = leg_local_deg }) + puppet.write_bone(handle, "leg_r", { rot = leg_local_deg }) end) -- Furniture textures. diff --git a/manifest.module b/manifest.module index a5fd30e..792031f 100644 --- a/manifest.module +++ b/manifest.module @@ -15,7 +15,7 @@ {"id": "lib-core.camera", "version": "0.3.0"}, {"id": "lib-core.render", "version": "0.1.0"}, {"id": "lib-core.maps", "version": "0.1.2"}, - {"id": "lib-core.puppet", "version": "0.4.1"}, + {"id": "lib-core.puppet", "version": "0.4.2"}, {"id": "lib-asset.prototype-subterrain", "version": "0.1.1"} ] } diff --git a/rigs/humanoid.rig.json b/rigs/humanoid.rig.json index e3ecbd0..198ba19 100644 --- a/rigs/humanoid.rig.json +++ b/rigs/humanoid.rig.json @@ -3,7 +3,6 @@ "asset_pack": "player", "bones": [ { "id": "root", "parent": null, "rest": {"x": 0, "y": 0, "rot": 0}, "z_order": -1 }, - { "id": "lower_control", "parent": "root", "rest": {"x": 0, "y": 0, "rot": 0}, "virtual": true }, { "id": "body", "parent": "root", "rest": {"x": 0, "y": 0, "rot": 0}, "z_order": 2, "texture": "body_001", "look_at": "soft", "look_at_slerp": 6 }, { "id": "head", "parent": "body", "rest": {"x": 0, "y": -3, "rot": 0, "rot_min": -60, "rot_max": 60}, "z_order": 6, "texture": "head_001", "look_at": "aim" }, { "id": "shoulders", "parent": "body", "rest": {"x": 0, "y": 0, "rot": 0}, "z_order": 5, "texture": "shoulder_001" }, @@ -11,8 +10,8 @@ { "id": "upper_arm_r", "parent": "shoulders", "rest": {"x": 20, "y": -4, "rot": 0}, "z_order": 3, "texture": "upper_arm_001" }, { "id": "lower_arm_l", "parent": "upper_arm_l", "rest": {"x": 14, "y": -18, "rot": 0}, "z_order": 2, "texture": "lower_arm_001" }, { "id": "lower_arm_r", "parent": "upper_arm_r", "rest": {"x": 13, "y": -17, "rot": 0}, "z_order": 2, "texture": "lower_arm_001" }, - { "id": "leg_l", "parent": "lower_control", "rest": {"x": -9, "y": 1, "rot": 0, "scl": [-1, -1]}, "z_order": 1, "texture": "leg_001" }, - { "id": "leg_r", "parent": "lower_control", "rest": {"x": 9, "y": 1, "rot": 0, "scl": [ 1, -1]}, "z_order": 1, "texture": "leg_001" }, + { "id": "leg_l", "parent": "body", "rest": {"x": -9, "y": 1, "rot": 0, "scl": [-1, -1]}, "z_order": 1, "texture": "leg_001" }, + { "id": "leg_r", "parent": "body", "rest": {"x": 9, "y": 1, "rot": 0, "scl": [ 1, -1]}, "z_order": 1, "texture": "leg_001" }, { "id": "foot_l", "parent": "leg_l", "rest": {"x": 0, "y": 25, "rot": 0, "scl": [ 1, -1]}, "z_order": 0, "texture": "foot_001" }, { "id": "foot_r", "parent": "leg_r", "rest": {"x": 0, "y": 26, "rot": 0, "scl": [ 1, -1]}, "z_order": 0, "texture": "foot_001" } ],