]> Untitled Git - william-skin.git/blob - TrackingBone3D.gd
Squashed commit of the following:
[william-skin.git] / TrackingBone3D.gd
1 @tool
2
3 class_name TrackingBone3D
4 extends SkeletonModifier3D
5
6 enum Axis {
7         X_plus, Y_plus, Z_plus, X_minus, Y_minus, Z_minus
8 }
9
10 @export_enum(" ") var bone: String
11 @export var aim_axis := Axis.Z_plus
12 @export var target: Vector3 = Vector3(0, 0, 0)
13
14 var _skeleton: Skeleton3D
15 var _bone_idx: int
16
17
18 func _validate_property(property: Dictionary) -> void:
19         if property.name == "bone":
20                 var skeleton: Skeleton3D = get_skeleton()
21                 if skeleton:
22                         property.hint = PROPERTY_HINT_ENUM
23                         property.hint_string = skeleton.get_concatenated_bone_names()
24
25
26 func _ready() -> void:
27         # for tweening bone poses
28         _skeleton = get_skeleton()
29         if not _skeleton:
30                 push_error("Expected a skeleton!")
31         _bone_idx = _skeleton.find_bone(bone)
32         
33
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)
37         
38         _skeleton.set_bone_global_pose(
39                 _bone_idx,
40                 Transform3D(
41                         (_skeleton.global_transform.affine_inverse() * looked_at).basis.orthonormalized(), 
42                         _skeleton.get_bone_global_pose(_bone_idx).origin
43                         )
44                 )
45
46
47 func _w_look_at(from: Transform3D) -> Transform3D:
48         var w: Vector3
49         
50         if aim_axis == Axis.Y_plus:
51                 w = from.basis.x
52         elif aim_axis == Axis.X_plus:
53                 w = from.basis.z
54         elif aim_axis == Axis.Z_plus:
55                 w = from.basis.y
56         elif aim_axis == Axis.Y_minus:
57                 w = w.inverse()
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()
62         
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)
69         return from