X-Git-Url: http://git.purplebirdman.com/william-skin.git/blobdiff_plain/c84055968443414e67caa33c3a823094ed29365b..HEAD:/TrackingBone3D_head.gd diff --git a/TrackingBone3D_head.gd b/TrackingBone3D_head.gd index 04e6938..6d522b3 100644 --- a/TrackingBone3D_head.gd +++ b/TrackingBone3D_head.gd @@ -4,8 +4,14 @@ class_name TrackingBone3D_head extends SkeletonModifier3D @export_enum(" ") var bone: String -@export var target: Vector3 = Vector3(0, 0, 0) +@export var target: Node3D = null +@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,58 @@ 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) + if target == null: + return + + 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.global_position, 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 ) )