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: Node3D = null
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:
38 var pose: Transform3D = _skeleton.global_transform * _skeleton.get_bone_global_pose(_bone_idx)
39 var looked_at: Transform3D = _w_look_at(pose)
41 _skeleton.set_bone_global_pose(
44 (_skeleton.global_transform.affine_inverse() * looked_at).basis.orthonormalized(),
45 _skeleton.get_bone_global_pose(_bone_idx).origin
50 func _w_look_at(from: Transform3D) -> Transform3D:
53 if aim_axis == Axis.Y_plus:
55 elif aim_axis == Axis.X_plus:
57 elif aim_axis == Axis.Z_plus:
59 elif aim_axis == Axis.Y_minus:
61 elif aim_axis == Axis.X_minus:
62 w = from.basis.y.inverse()
63 elif aim_axis == Axis.Z_minus:
64 w = from.basis.y.inverse()
66 var t_v: Vector3 = target.global_position - from.origin
67 var v_y: Vector3 = t_v.normalized()
68 var v_z: Vector3 = w.cross(v_y)
69 v_z = v_z.normalized()
70 var v_x: Vector3 = v_y.cross(v_z)
71 from.basis = Basis(v_x, v_y, v_z)