feat: implement automated 3D character pipeline with retargeting and rig management tools
This commit is contained in:
@@ -108,7 +108,12 @@ func _measure(store_rest: bool) -> void:
|
||||
bone_of[b] = bi
|
||||
for s in range(mi.mesh.get_surface_count()):
|
||||
var mat = mi.mesh.surface_get_material(s)
|
||||
var mname: String = mat.resource_name if mat else "?"
|
||||
# Keyed by MESH as well as material. A model that keeps its per-part
|
||||
# meshes reuses one material across several of them — Taila has
|
||||
# "FullBlack" on three — and keying by material alone compared one
|
||||
# mesh's rest against another mesh's posed span, which reported a
|
||||
# 4.9x stretch on a model that was fine.
|
||||
var mname: String = "%s/%s" % [mi.name, mat.resource_name if mat else "?"]
|
||||
var arrays: Array = mi.mesh.surface_get_arrays(s)
|
||||
var verts: PackedVector3Array = arrays[Mesh.ARRAY_VERTEX]
|
||||
var bones: PackedInt32Array = arrays[Mesh.ARRAY_BONES]
|
||||
@@ -140,6 +145,31 @@ func _skinned(skel: Skeleton3D, skin: Skin, bone_of: Dictionary, p: Vector3,
|
||||
return q
|
||||
|
||||
|
||||
## Is this vertex mostly owned by a LEFT leg bone?
|
||||
func _left_leg_driven(skel: Skeleton3D, skin: Skin, bone_of: Dictionary,
|
||||
bones: PackedInt32Array, weights: PackedFloat32Array,
|
||||
base: int, per: int) -> bool:
|
||||
var best := 0.0
|
||||
var best_name := ""
|
||||
for k in per:
|
||||
var w: float = weights[base + k]
|
||||
if w <= best:
|
||||
continue
|
||||
var bind: int = bones[base + k]
|
||||
var n: String = skin.get_bind_name(bind)
|
||||
if n == "":
|
||||
var bi: int = bone_of[bind]
|
||||
n = skel.get_bone_name(bi) if bi >= 0 else ""
|
||||
best = w
|
||||
best_name = n
|
||||
if not (best_name.ends_with(".L") or best_name.find(".L.") != -1):
|
||||
return false
|
||||
for hint in ["shin", "thigh", "foot", "toe"]:
|
||||
if best_name.findn(hint) != -1:
|
||||
return true
|
||||
return false
|
||||
|
||||
|
||||
func _span(skel: Skeleton3D, skin: Skin, bone_of: Dictionary, mname: String,
|
||||
verts: PackedVector3Array, bones: PackedInt32Array,
|
||||
weights: PackedFloat32Array, per: int, store_rest: bool) -> void:
|
||||
@@ -157,6 +187,13 @@ 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)
|
||||
if p.distance_to(ha + hf * t) > 0.10:
|
||||
continue
|
||||
# Must be DRIVEN by the left leg, not merely near it. Taila's boots are
|
||||
# a single mesh holding both feet, and at rest the right boot sits
|
||||
# within 0.10 m of the left leg axis — so a purely positional filter
|
||||
# collected both, and the span between them read as a 4.9x "stretch"
|
||||
# the moment the legs separated.
|
||||
if not _left_leg_driven(skel, skin, bone_of, bones, weights, v * per, per):
|
||||
continue
|
||||
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))
|
||||
hi = Vector3(maxf(hi.x, q.x), maxf(hi.y, q.y), maxf(hi.z, q.z))
|
||||
|
||||
Reference in New Issue
Block a user