]> Untitled Git - william-skin.git/blobdiff - TrackingBone3D_head.gd
Squashed commit of the following:
[william-skin.git] / TrackingBone3D_head.gd
index 04e69383635509774e90a5db7416a86b13c84d18..c1d39138e9b1a93230184d9f28a7dc2c872cc6d4 100644 (file)
@@ -5,7 +5,13 @@ extends SkeletonModifier3D
 
 @export_enum(" ") var bone: String
 @export var target: Vector3 = Vector3(0, 0, 0)
+@export var influence_lerp_seconds: float = 0.5
+@export var rotation_lerp_weight: float = 0.5
 
+var _skeleton: Skeleton3D
+var _bone_idx: int
+
+var old_current_pose: Transform3D = Transform3D.IDENTITY
 
 func _validate_property(property: Dictionary) -> void:
        if property.name == "bone":
@@ -15,23 +21,55 @@ func _validate_property(property: Dictionary) -> void:
                        property.hint_string = skeleton.get_concatenated_bone_names()
 
 
+func _ready() -> void:
+       # for tweening influence
+       influence = 0
+       
+       # for tweening bone poses
+       _skeleton = get_skeleton()
+       if not _skeleton:
+               push_error("Expected a skeleton!")
+       _bone_idx = _skeleton.find_bone(bone)
+       
+       # for smooth rotations
+       old_current_pose = _skeleton.global_transform * _skeleton.get_bone_global_pose(_bone_idx)
+
+
+func tween_influence(goal_weight: float) -> void:
+       create_tween().tween_method(
+               _interpolate_influence, influence, goal_weight, influence_lerp_seconds
+               ).set_trans(Tween.TRANS_EXPO)
+
+
+func _interpolate_influence(weight: float) -> void:
+       influence = weight
+
+
+
 func _process_modification() -> void:
-       var skeleton: Skeleton3D = get_skeleton()
-       if !skeleton:
-               return # Never happen, but for the safety.
-       var bone_idx: int = skeleton.find_bone(bone)
-       var _parent_idx: int = skeleton.get_bone_parent(bone_idx)
-       var pose: Transform3D = skeleton.global_transform * skeleton.get_bone_global_pose(bone_idx)
+       var current_pose: Transform3D = _skeleton.global_transform * _skeleton.get_bone_global_pose(_bone_idx)
+       current_pose.basis = old_current_pose.basis
+       var target_pose: Transform3D  = current_pose.looking_at(target, Vector3.UP)
+       
+       # TODO: replace this specific code with general purpose modifier
+       var axis: Vector3 = target_pose.basis.y
+       target_pose = target_pose.rotated(axis, PI)
+       
+       # https://docs.godotengine.org/en/latest/tutorials/3d/using_transforms.html#interpolating-with-quaternions
+       if rotation_lerp_weight > 0:
+               var from := Quaternion(current_pose.basis.orthonormalized())
+               var to := Quaternion(target_pose.basis.orthonormalized())
+               var rot_target := from.slerp(to, rotation_lerp_weight)
+               target_pose.basis = Basis(rot_target)
        
-       #var looked_at: Transform3D = _w_look_at(pose, target)
-       var looked_at: Transform3D = pose.looking_at(target, Vector3.UP)
-       var axis: Vector3 = looked_at.basis.y
-       looked_at = looked_at.rotated(axis, PI)
+       # remember this!
+       old_current_pose = target_pose
        
-       skeleton.set_bone_global_pose(
-               bone_idx,
+       # yield until target pose has changed, then apply it?
+       _skeleton.set_bone_global_pose(
+               _bone_idx,
                Transform3D(
-                       (skeleton.global_transform.affine_inverse() * looked_at).basis.orthonormalized(), 
-                       skeleton.get_bone_global_pose(bone_idx).origin
+                       (_skeleton.global_transform.affine_inverse() * target_pose).basis.orthonormalized(), 
+                       _skeleton.get_bone_global_pose(_bone_idx).origin
                        )
                )