Feat/outline thickness and tp weapon hold #22

Merged
Dotts merged 43 commits from feat/outline-thickness-and-tp-weapon-hold into main 2026-07-27 23:22:53 -07:00
2 changed files with 28 additions and 9 deletions
Showing only changes of commit 1e12c36cca - Show all commits
+2
View File
@@ -35,6 +35,8 @@ class_name SkinLegRepair
## 3. Drop any triangle still spanning the two legs below the knee. Those are ## 3. Drop any triangle still spanning the two legs below the knee. Those are
## the midline band between the ankles, which has no correct pose either ## the midline band between the ankles, which has no correct pose either
## way. ## way.
##
## Measure with debug/limb_deform_check.gd.
const LEG_BONE_HINTS := ["thigh", "shin", "foot", "toe"] const LEG_BONE_HINTS := ["thigh", "shin", "foot", "toe"]
## Ignore influences below this — they are rounding, not real weighting. ## Ignore influences below this — they are rounding, not real weighting.
+26 -9
View File
@@ -16,10 +16,23 @@ extends SceneTree
## collapse that linear-blend skinning causes at a bent joint; ## collapse that linear-blend skinning causes at a bent joint;
## 0.85-1.00 is normal, well below that is a weighting fault. ## 0.85-1.00 is normal, well below that is a weighting fault.
## ##
## Written after four rounds of chasing reported leg "squashing". Renders were ## Written after several rounds of chasing reported leg "squashing". Renders
## repeatedly misleading — a slim anime leg at full stride genuinely looks ## were repeatedly misleading — a slim anime leg at full stride genuinely looks
## stretched — so measure before changing anything, and prefer this over ## stretched — so measure before changing anything.
## eyeballing a screenshot. ##
## READ THIS BEFORE TRUSTING ANY NUMBER YOU ADD HERE. Two earlier versions of
## this measurement were themselves wrong and nearly caused a bad "fix":
##
## * Comparing skinned lengths against BIND-POSE lengths. The character is
## never in bind pose, so ordinary posing showed up as 0.4x-2.5x
## "deformation" even with the animation frozen.
## * Flagging vertices weighted across "non-adjacent" leg bones by testing
## max_slot - min_slot >= 2. That flags shin+foot+toe, which is a perfectly
## normal contiguous run.
##
## So the baseline here is the skeleton's REST transforms, which makes every
## ratio exactly 1.00 when the pose is the rest pose — the tool validates
## itself. If you add a metric, prove it reads 1.00 on an unposed model first.
var _frames := 0 var _frames := 0
var _model: SkinnedPlayerModel = null var _model: SkinnedPlayerModel = null
@@ -51,7 +64,7 @@ func _process(_delta: float) -> bool:
if _frames < 10: if _frames < 10:
return false return false
if _frames == 10: if _frames == 10:
_measure(true) _measure(true) # baseline from the skeleton's REST transforms
return false return false
var phase: int = clampi((_frames - 20) / FRAMES_PER_STATE, 0, SWEEP.size() - 1) var phase: int = clampi((_frames - 20) / FRAMES_PER_STATE, 0, SWEEP.size() - 1)
_model.update_state(SWEEP[phase][0], SWEEP[phase][1], false) _model.update_state(SWEEP[phase][0], SWEEP[phase][1], false)
@@ -107,9 +120,12 @@ func _measure(store_rest: bool) -> void:
_rings(skel, skin, bone_of, mname, verts, bones, weights, per, store_rest) _rings(skel, skin, bone_of, mname, verts, bones, weights, per, store_rest)
## `rest` skins against the skeleton's rest transforms instead of its current
## pose, which is what makes the baseline exact: ratios come out 1.00 on an
## unposed model, so a wrong reading is visible immediately.
func _skinned(skel: Skeleton3D, skin: Skin, bone_of: Dictionary, p: Vector3, func _skinned(skel: Skeleton3D, skin: Skin, bone_of: Dictionary, p: Vector3,
bones: PackedInt32Array, weights: PackedFloat32Array, bones: PackedInt32Array, weights: PackedFloat32Array,
base: int, per: int) -> Vector3: base: int, per: int, rest: bool = false) -> Vector3:
var q := Vector3.ZERO var q := Vector3.ZERO
for k in per: for k in per:
var w: float = weights[base + k] var w: float = weights[base + k]
@@ -119,7 +135,8 @@ func _skinned(skel: Skeleton3D, skin: Skin, bone_of: Dictionary, p: Vector3,
var bi: int = bone_of[bind] var bi: int = bone_of[bind]
if bi < 0: if bi < 0:
continue continue
q += (skel.get_bone_global_pose(bi) * skin.get_bind_pose(bind) * p) * w var m: Transform3D = skel.get_bone_global_rest(bi) if rest else skel.get_bone_global_pose(bi)
q += (m * skin.get_bind_pose(bind) * p) * w
return q return q
@@ -140,7 +157,7 @@ func _span(skel: Skeleton3D, skin: Skin, bone_of: Dictionary, mname: String,
var t: float = clampf((p - ha).dot(hf) / hf.length_squared(), 0.0, 1.0) var t: float = clampf((p - ha).dot(hf) / hf.length_squared(), 0.0, 1.0)
if p.distance_to(ha + hf * t) > 0.10: if p.distance_to(ha + hf * t) > 0.10:
continue continue
var q := _skinned(skel, skin, bone_of, p, bones, weights, v * per, per) var q := _skinned(skel, skin, bone_of, p, bones, weights, v * per, per, store_rest)
lo = Vector3(minf(lo.x, q.x), minf(lo.y, q.y), minf(lo.z, q.z)) lo = Vector3(minf(lo.x, q.x), minf(lo.y, q.y), minf(lo.z, q.z))
hi = Vector3(maxf(hi.x, q.x), maxf(hi.y, q.y), maxf(hi.z, q.z)) hi = Vector3(maxf(hi.x, q.x), maxf(hi.y, q.y), maxf(hi.z, q.z))
n += 1 n += 1
@@ -177,7 +194,7 @@ func _rings(skel: Skeleton3D, skin: Skin, bone_of: Dictionary, mname: String,
continue continue
if p.distance_to(a + ab * t) > 0.09: if p.distance_to(a + ab * t) > 0.09:
continue continue
var q := _skinned(skel, skin, bone_of, p, bones, weights, v * per, per) var q := _skinned(skel, skin, bone_of, p, bones, weights, v * per, per, store_rest)
sp.append(q) sp.append(q)
c += q c += q
if sp.size() < 3: if sp.size() < 3: