Feat/14 movement overhaul #20
@@ -461,17 +461,14 @@ func _warn_missing(anim_name: String) -> void:
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
if not skeleton:
|
||||
print("SkinnedPlayerModel: _process - no skeleton!")
|
||||
return
|
||||
|
||||
# Get movement state from parent PlayerMovementController
|
||||
var parent = get_parent()
|
||||
if not parent:
|
||||
print("SkinnedPlayerModel: _process - no parent!")
|
||||
return
|
||||
var sm = parent.get_node_or_null("MovementStateMachine")
|
||||
if not sm:
|
||||
print("SkinnedPlayerModel: _process - no MovementStateMachine!")
|
||||
return
|
||||
|
||||
var state = sm.current_state
|
||||
@@ -539,7 +536,6 @@ func _process(delta: float) -> void:
|
||||
_anim_time = min(_anim_time, length)
|
||||
# Apply procedural animation to skeleton
|
||||
_apply_procedural_animation(data, _anim_time)
|
||||
print("SkinnedPlayerModel: applied '%s' t=%.2f" % [_current_anim_name, _anim_time])
|
||||
else:
|
||||
# For non-procedural anims (Death, Crouch from GLB), use AP
|
||||
if animation_player:
|
||||
@@ -558,7 +554,7 @@ func _process(delta: float) -> void:
|
||||
|
||||
func _apply_procedural_animation(data: Dictionary, time: float) -> void:
|
||||
## Applies procedural animation data to the skeleton at the given time.
|
||||
## Rotates bones around their anatomical swing axis (world X for locomotion).
|
||||
## Sets local pose = rest_local * offset_quat for correct skinning.
|
||||
if not skeleton:
|
||||
return
|
||||
var tracks = data["tracks"]
|
||||
@@ -590,28 +586,18 @@ func _apply_procedural_animation(data: Dictionary, time: float) -> void:
|
||||
|
||||
if prev_kf.has("rot") and next_kf.has("rot"):
|
||||
var rot: Vector3 = lerp(prev_kf["rot"], next_kf["rot"], t)
|
||||
# Get rest global pose
|
||||
var rest_global = skeleton.get_bone_global_pose(bone_idx)
|
||||
# Apply rotation around the bone's swing axis
|
||||
# rot.x = forward/back swing (rotation around world X)
|
||||
# rot.y = twist (rotation around bone's forward axis)
|
||||
# rot.z = lateral (rotation around world Z)
|
||||
var new_basis = rest_global.basis
|
||||
if abs(rot.x) > 0.001:
|
||||
# Forward/back swing: rotate around world X axis
|
||||
var swing = Basis(Vector3(1, 0, 0), rot.x)
|
||||
new_basis = swing * new_basis
|
||||
if abs(rot.y) > 0.001:
|
||||
# Twist: rotate around the bone's Y axis (in world space)
|
||||
var bone_y = new_basis.y
|
||||
var twist = Basis(bone_y, rot.y)
|
||||
new_basis = twist * new_basis
|
||||
if abs(rot.z) > 0.001:
|
||||
# Lateral: rotate around world Z
|
||||
var lateral = Basis(Vector3(0, 0, 1), rot.z)
|
||||
new_basis = lateral * new_basis
|
||||
var new_global = Transform3D(new_basis, rest_global.origin)
|
||||
skeleton.set_bone_global_pose_override(bone_idx, new_global, 1.0, true)
|
||||
# Compute offset quaternion from euler angles
|
||||
var offset_quat = Quaternion.from_euler(rot)
|
||||
# Get rest pose local rotation for this bone
|
||||
var rest_quat: Quaternion = _bone_rest_local_rot.get(bone_idx, Quaternion.IDENTITY)
|
||||
# local_pose = rest_local * offset (so final = rest * offset)
|
||||
var new_local_quat = rest_quat * offset_quat
|
||||
skeleton.set_bone_pose_rotation(bone_idx, new_local_quat)
|
||||
# Keep rest pose local position
|
||||
var rest_pos: Vector3 = _bone_rest_local_pos.get(bone_idx, Vector3.ZERO)
|
||||
skeleton.set_bone_pose_position(bone_idx, rest_pos)
|
||||
elif prev_kf.has("pos") and next_kf.has("pos"):
|
||||
var pos: Vector3 = lerp(prev_kf["pos"], next_kf["pos"], t)
|
||||
skeleton.set_bone_pose_position(bone_idx, pos)
|
||||
# Position is additive on top of rest pose position
|
||||
var rest_pos: Vector3 = _bone_rest_local_pos.get(bone_idx, Vector3.ZERO)
|
||||
skeleton.set_bone_pose_position(bone_idx, rest_pos + pos)
|
||||
|
||||
Reference in New Issue
Block a user