fix: half-angle helper bones at the knees kill the candy-wrapper collapse
This is the leg squashing. It was at the KNEE, and every previous measurement missed it because they averaged a ring of vertices, which hides a collapse that only affects part of the ring. Measured per vertex instead, against an exact rest-transform baseline: 532 of Taila's leg vertices lose more than 20% of their distance from the bone axis and the worst lose 40%, all at y=0.54 — exactly the knee — and worst in the air pose. That is "squashing while running or jumping, easy to see from the side". Cause is inherent to linear-blend skinning: it averages TRANSFORMS, not shapes. A vertex half on the thigh and half on the shin is placed at the average of two rotations, and at a hard bend that average falls well inside the leg, pinching it to a ribbon. SkinKneeHelper adds a bone at each knee, parented to the thigh and holding the shin's rest transform, driven every frame to HALF the shin's rotation from inside the skeleton's modification pass. Blend-zone vertices are re-weighted off the thigh/shin pair and onto the helper, taking equal weight from each side and reusing the slot that falls to zero — so no extra influence slot is needed and the weights still sum to exactly 1. The sharpest blend any vertex now sees is half the knee angle, and halving the angle roughly quarters the collapse. Result: vertices losing more than 20% of their radius go from 532 to 0 on the body. The worst anywhere is now 0.79, on the outline shell, which is hidden. Verified visually too, legs rendered bare from the side through rest, run and jump: knees hold their volume and the bind is intact. FSM tests 11/11, spawn smoke test 0 failures, Miku unaffected. Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
e707229283
commit
050011666c
@@ -86,6 +86,8 @@ var loaded: bool = false
|
||||
var _resolved_clips: Dictionary = {} # canonical name -> actual clip name
|
||||
var _current_clip: String = ""
|
||||
var _weapon_attachment: BoneAttachment3D
|
||||
## [shin_bone, helper_bone] pairs driven every frame by the pose modifier.
|
||||
var _knee_helpers: Array = []
|
||||
var is_holding_weapon: bool = false
|
||||
|
||||
# Animation blending: locomotion plays full-body through a Transition node;
|
||||
@@ -168,7 +170,11 @@ func load_model(path: String) -> void:
|
||||
if fixed[0] > 0 or fixed[1] > 0:
|
||||
print("SkinnedPlayerModel: '%s' — snapped %d cross-leg vertices, dropped %d bridging triangles"
|
||||
% [path.get_file(), fixed[0], fixed[1]])
|
||||
# Half-angle helper bones at the knees. Without them the knee pinches to
|
||||
# a ribbon at a hard bend — see SkinKneeHelper.
|
||||
_knee_helpers = SkinKneeHelper.install(scene, skeleton)
|
||||
_pose_mod = ShooterPoseModifier.new()
|
||||
_pose_mod.knee_helpers = _knee_helpers
|
||||
_pose_mod.name = "ShooterPose"
|
||||
skeleton.add_child(_pose_mod)
|
||||
|
||||
@@ -755,6 +761,8 @@ class ShooterPoseModifier extends SkeletonModifier3D:
|
||||
var gun_stock: float = 0.20
|
||||
# 0..1 through a reload — drives the support hand to the mag well and back.
|
||||
var reload_phase: float = 0.0
|
||||
# [shin_bone, helper_bone] pairs; see SkinKneeHelper.
|
||||
var knee_helpers: Array = []
|
||||
|
||||
# Tuning (radians). Positive pitch leans forward; positive roll leans right.
|
||||
# The lean is the ONLY thing that tells a viewer which way this character is
|
||||
@@ -813,6 +821,12 @@ class ShooterPoseModifier extends SkeletonModifier3D:
|
||||
_apply_recoil(skel)
|
||||
recoil = lerpf(recoil, 0.0, 0.25)
|
||||
|
||||
# Knees LAST, and inside the modification pass: the helper has to track
|
||||
# whatever final rotation the shin ended up with, or it deforms the leg
|
||||
# instead of saving it.
|
||||
if not knee_helpers.is_empty():
|
||||
SkinKneeHelper.update(skel, knee_helpers)
|
||||
|
||||
|
||||
# Upper body follows the camera pitch: distributed over spine/neck/head
|
||||
# so looking up/down reads on the whole silhouette, not just the head.
|
||||
|
||||
Reference in New Issue
Block a user