3 class_name TrackingBone3D
4 extends SkeletonModifier3D
7 X_plus, Y_plus, Z_plus, X_minus, Y_minus, Z_minus
10 @export_enum(" ") var bone: String
11 @export var aim_axis := Axis.Z_plus
12 @export var target: Vector3 = Vector3(0, 0, 0)
14 var _skeleton: Skeleton3D
18 func _validate_property(property: Dictionary) -> void:
19 if property.name == "bone":
20 var skeleton: Skeleton3D = get_skeleton()
22 property.hint = PROPERTY_HINT_ENUM
23 property.hint_string = skeleton.get_concatenated_bone_names()
26 func _ready() -> void:
27 # for tweening bone poses
28 _skeleton = get_skeleton()
30 push_error("Expected a skeleton!")
31 _bone_idx = _skeleton.find_bone(bone)
34 func _process_modification() -> void:
35 var pose: Transform3D = _skeleton.global_transform * _skeleton.get_bone_global_pose(_bone_idx)
36 var looked_at: Transform3D = _w_look_at(pose)
38 _skeleton.set_bone_global_pose(
41 (_skeleton.global_transform.affine_inverse() * looked_at).basis.orthonormalized(),
42 _skeleton.get_bone_global_pose(_bone_idx).origin
47 func _w_look_at(from: Transform3D) -> Transform3D:
50 if aim_axis == Axis.Y_plus:
52 elif aim_axis == Axis.X_plus:
54 elif aim_axis == Axis.Z_plus:
56 elif aim_axis == Axis.Y_minus:
58 elif aim_axis == Axis.X_minus:
59 w = from.basis.y.inverse()
60 elif aim_axis == Axis.Z_minus:
61 w = from.basis.y.inverse()
63 var t_v: Vector3 = target - from.origin
64 var v_y: Vector3 = t_v.normalized()
65 var v_z: Vector3 = w.cross(v_y)
66 v_z = v_z.normalized()
67 var v_x: Vector3 = v_y.cross(v_z)
68 from.basis = Basis(v_x, v_y, v_z)