Add StkRigAdapter for runtime skeleton fitting and shape mounting
- Implemented StkRigAdapter class to adapt a master rig to a loaded .stk dictionary. - Added methods for fitting bone lengths, recalibrating IK targets, and mounting vector shapes. - Defined constants for default proportions and bone paths. - Included error handling for missing nodes and invalid data structures.
This commit is contained in:
@@ -42,6 +42,56 @@ const DEFAULT_PART_ORDER: PackedStringArray = [
|
||||
"right_upper_leg", "right_lower_leg"
|
||||
]
|
||||
|
||||
# Phase 7: pose silhouette guide
|
||||
const GUIDE_JOINT_RADIUS: float = 6.0 # screen-space joint dot radius (px)
|
||||
const GUIDE_SCALE: float = 1.0 # master_rig -> preview world scale (1:1, per user decision)
|
||||
const GUIDE_FIGURE_CENTER: Vector2 = Vector2(0.0, -93.75) # master-space bbox center of the 1:1 guide figure
|
||||
const GUIDE_HEAD_RADIUS: float = 100.0 # master-space head circle radius
|
||||
|
||||
const GUIDE_COLOR_LEFT: Color = Color(0.35, 0.70, 1.00, 0.45) # cyan-blue, semi
|
||||
const GUIDE_COLOR_RIGHT: Color = Color(1.00, 0.50, 0.20, 0.45) # orange-red, semi
|
||||
const GUIDE_COLOR_CENTRAL: Color = Color(1.00, 1.00, 1.00, 0.45) # white, semi
|
||||
|
||||
const GUIDE_JOINT_COLOR_LEFT: Color = Color(0.35, 0.70, 1.00, 0.65)
|
||||
const GUIDE_JOINT_COLOR_RIGHT: Color = Color(1.00, 0.50, 0.20, 0.65)
|
||||
const GUIDE_JOINT_COLOR_CENTRAL: Color = Color(1.00, 1.00, 1.00, 0.65)
|
||||
|
||||
const GUIDE_JOINTS: Dictionary = {
|
||||
"Hips": Vector2(0.0, 0.0),
|
||||
"Neck": Vector2(0.0, -391.5),
|
||||
"Head": Vector2(0.0, -463.5),
|
||||
"LeftShoulder": Vector2(0.0, -248.0),
|
||||
"RightShoulder": Vector2(0.0, -248.0),
|
||||
"LeftElbow": Vector2(-168.0, -256.0),
|
||||
"RightElbow": Vector2(168.0, -256.0),
|
||||
"LeftWrist": Vector2(-168.0, -456.0),
|
||||
"RightWrist": Vector2(168.0, -456.0),
|
||||
"LeftKnee": Vector2(-95.0, 176.0),
|
||||
"RightKnee": Vector2(95.0, 176.0),
|
||||
"LeftAnkle": Vector2(-96.0, 376.0),
|
||||
"RightAnkle": Vector2(96.0, 376.0),
|
||||
}
|
||||
|
||||
const GUIDE_LEFT_JOINTS: PackedStringArray = [
|
||||
"LeftShoulder", "LeftElbow", "LeftWrist", "LeftKnee", "LeftAnkle"
|
||||
]
|
||||
const GUIDE_RIGHT_JOINTS: PackedStringArray = [
|
||||
"RightShoulder", "RightElbow", "RightWrist", "RightKnee", "RightAnkle"
|
||||
]
|
||||
# any joint not in LEFT/RIGHT is central (Hips, Neck, Head)
|
||||
|
||||
const GUIDE_BONES: Array = [
|
||||
["Hips", "Neck"], # spine (central)
|
||||
["LeftShoulder", "LeftElbow"], # left upper arm
|
||||
["LeftElbow", "LeftWrist"], # left forearm
|
||||
["RightShoulder", "RightElbow"], # right upper arm
|
||||
["RightElbow", "RightWrist"], # right forearm
|
||||
["Hips", "LeftKnee"], # left thigh
|
||||
["LeftKnee", "LeftAnkle"], # left shin
|
||||
["Hips", "RightKnee"], # right thigh
|
||||
["RightKnee", "RightAnkle"], # right shin
|
||||
]
|
||||
|
||||
enum Interaction { NONE, TRANSLATE, ROTATE, SCALE }
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -95,6 +145,9 @@ var _context_menu: PopupMenu
|
||||
# Phase 6: selection gizmos rendered on top
|
||||
var _selected_gizmo_bounds: Rect2 = Rect2()
|
||||
|
||||
# Phase 7: pose silhouette guide (default ON per user decision)
|
||||
var _show_guide: bool = true
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Public API
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -212,6 +265,12 @@ func set_snap_enabled(enabled: bool) -> void:
|
||||
_snap_enabled = enabled
|
||||
|
||||
|
||||
# Phase 7
|
||||
func set_show_guide(enabled: bool) -> void:
|
||||
_show_guide = enabled
|
||||
preview_area.queue_redraw()
|
||||
|
||||
|
||||
func reset_view() -> void:
|
||||
_zoom = 1.0
|
||||
_pan_offset = Vector2.ZERO
|
||||
@@ -323,6 +382,9 @@ func _on_preview_draw() -> void:
|
||||
if bounds.has_area():
|
||||
_selected_gizmo_bounds = bounds
|
||||
|
||||
# Phase 7: ghost the silhouette guide IN FRONT of parts (below selection affordances)
|
||||
_draw_silhouette_guide()
|
||||
|
||||
# Highlight dragged part
|
||||
if not _dragging_part.is_empty() and _interaction == Interaction.TRANSLATE:
|
||||
var bounds: Variant = _part_bounds.get(_dragging_part)
|
||||
@@ -373,6 +435,58 @@ func _draw_grid() -> void:
|
||||
y += gs
|
||||
|
||||
|
||||
func _draw_silhouette_guide() -> void:
|
||||
if not _show_guide:
|
||||
return
|
||||
|
||||
var lw: float = 1.5 / _zoom # match _draw_polyline_preview stroke
|
||||
var jr: float = GUIDE_JOINT_RADIUS / _zoom # constant 6px screen size
|
||||
|
||||
# 1. Limb / spine segments (semi-transparent)
|
||||
for bone: Array in GUIDE_BONES:
|
||||
var a: String = bone[0] as String
|
||||
var b: String = bone[1] as String
|
||||
if not (GUIDE_JOINTS.has(a) and GUIDE_JOINTS.has(b)):
|
||||
continue
|
||||
var pa: Vector2 = _guide_to_preview(GUIDE_JOINTS[a])
|
||||
var pb: Vector2 = _guide_to_preview(GUIDE_JOINTS[b])
|
||||
preview_area.draw_line(pa, pb, _guide_color(a), lw)
|
||||
|
||||
# 2. Head outline circle (central, semi-transparent)
|
||||
var head_center: Vector2 = _guide_to_preview(GUIDE_JOINTS["Head"])
|
||||
preview_area.draw_arc(
|
||||
head_center,
|
||||
GUIDE_HEAD_RADIUS * GUIDE_SCALE,
|
||||
0.0, TAU, 48,
|
||||
GUIDE_COLOR_CENTRAL, lw
|
||||
)
|
||||
|
||||
# 3. Joint anchors (constant screen size)
|
||||
for joint: String in GUIDE_JOINTS:
|
||||
var p: Vector2 = _guide_to_preview(GUIDE_JOINTS[joint])
|
||||
preview_area.draw_circle(p, jr, _guide_joint_color(joint))
|
||||
|
||||
|
||||
func _guide_to_preview(master_pos: Vector2) -> Vector2:
|
||||
return (master_pos - GUIDE_FIGURE_CENTER) * GUIDE_SCALE + preview_area.size * 0.5
|
||||
|
||||
|
||||
func _guide_color(joint_name: String) -> Color:
|
||||
if GUIDE_LEFT_JOINTS.has(joint_name):
|
||||
return GUIDE_COLOR_LEFT
|
||||
if GUIDE_RIGHT_JOINTS.has(joint_name):
|
||||
return GUIDE_COLOR_RIGHT
|
||||
return GUIDE_COLOR_CENTRAL
|
||||
|
||||
|
||||
func _guide_joint_color(joint_name: String) -> Color:
|
||||
if GUIDE_LEFT_JOINTS.has(joint_name):
|
||||
return GUIDE_JOINT_COLOR_LEFT
|
||||
if GUIDE_RIGHT_JOINTS.has(joint_name):
|
||||
return GUIDE_JOINT_COLOR_RIGHT
|
||||
return GUIDE_JOINT_COLOR_CENTRAL
|
||||
|
||||
|
||||
func _draw_polyline_preview(pts: PackedVector2Array, color: Color, closed: bool) -> void:
|
||||
for i: int in range(pts.size() - 1):
|
||||
preview_area.draw_line(pts[i], pts[i + 1], color, 1.5)
|
||||
|
||||
Reference in New Issue
Block a user