Guest User

godot arm ik

a guest
Sep 19th, 2020
783
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.65 KB | None | 0 0
  1. extends Spatial
  2.  
  3. onready var hand_r = $HandR
  4. onready var hand_l = $HandL
  5.  
  6. #used for reload animations, this is the point the left hand goes to to grab an ammo clip
  7. export(NodePath) var reload_clip_point_path
  8. onready var reload_clip_point = get_node(reload_clip_point_path)
  9. onready var reload_clip_interim_point = reload_clip_point.get_node("ReloadClipPointInterim")
  10. var grab_clip_weight = 0.0 # if weight is 1.0 hand is at reload point, if 0.0 at regular point
  11.  
  12. export(NodePath) var reload_magnet_path
  13. onready var reload_magnet = get_node(reload_magnet_path)
  14.  
  15. export(NodePath) var magnet_l_path
  16. export(NodePath) var magnet_r_path
  17.  
  18. var magnet_l : Spatial
  19. var magnet_r : Spatial
  20.  
  21. var ref_hand_r : Spatial = null
  22. var ref_hand_l : Spatial = null
  23.  
  24. export(NodePath) var skeleton_path
  25. onready var skeleton = get_node(skeleton_path)
  26.  
  27. var upper_arm_l_ind = 0
  28. var lower_arm_l_ind = 0
  29. var hand_l_ind = 0
  30. var upper_arm_r_ind = 0
  31. var lower_arm_r_ind = 0
  32. var hand_r_ind = 0
  33.  
  34. var arm_upper_length_l = 0.0
  35. var arm_lower_length_l = 0.0
  36. var arm_upper_length_r = 0.0
  37. var arm_lower_length_r = 0.0
  38.  
  39. func _ready():
  40. magnet_l = get_node(magnet_l_path)
  41. magnet_r = get_node(magnet_r_path)
  42.  
  43. upper_arm_l_ind = skeleton.find_bone("arm_upperl")
  44. lower_arm_l_ind = skeleton.find_bone("arm_lowerl")
  45. hand_l_ind = skeleton.find_bone("handl")
  46. upper_arm_r_ind = skeleton.find_bone("arm_upperr")
  47. lower_arm_r_ind = skeleton.find_bone("arm_lowerr")
  48. hand_r_ind = skeleton.find_bone("handr")
  49.  
  50. var shoulder_pos_l = skeleton.get_bone_global_pose(upper_arm_l_ind).origin
  51. var elbow_pos_l = skeleton.get_bone_global_pose(lower_arm_l_ind).origin
  52. var hand_pos_l = skeleton.get_bone_global_pose(hand_l_ind).origin
  53. var shoulder_pos_r = skeleton.get_bone_global_pose(upper_arm_r_ind).origin
  54. var elbow_pos_r = skeleton.get_bone_global_pose(lower_arm_r_ind).origin
  55. var hand_pos_r = skeleton.get_bone_global_pose(hand_r_ind).origin
  56.  
  57. arm_upper_length_l = shoulder_pos_l.distance_to(elbow_pos_l)
  58. arm_lower_length_l = hand_pos_l.distance_to(elbow_pos_l)
  59. arm_upper_length_r = shoulder_pos_r.distance_to(elbow_pos_r)
  60. arm_lower_length_r = hand_pos_r.distance_to(elbow_pos_r)
  61.  
  62. func update_hand_ref(_hand_r, _hand_l):
  63. ref_hand_r = _hand_r
  64. ref_hand_l = _hand_l
  65.  
  66. func _process(_delta):
  67. update_hand_transforms()
  68.  
  69. func update_hand_transforms():
  70. if !is_instance_valid(ref_hand_l) or !is_instance_valid(ref_hand_r):
  71. return
  72. hand_r.global_transform = ref_hand_r.global_transform
  73. if grab_clip_weight < 0.001:
  74. hand_l.global_transform = ref_hand_l.global_transform
  75. else:
  76. var ref_hand_pos = ref_hand_l.global_transform.origin
  77. var reload_point_pos = reload_clip_point.global_transform.origin
  78. var interim_reload_point_pos = reload_clip_interim_point.global_transform.origin
  79. if grab_clip_weight < 0.5:
  80. var weight = grab_clip_weight / 0.5
  81. hand_l.global_transform.origin = ref_hand_pos.linear_interpolate(interim_reload_point_pos, weight)
  82. else:
  83. var weight = (grab_clip_weight - 0.5) / 0.5
  84. hand_l.global_transform.origin = interim_reload_point_pos.linear_interpolate(reload_point_pos, weight)
  85. var lower_arm_transform = skeleton.get_bone_global_pose(lower_arm_l_ind)
  86. var t_x = skeleton.to_global(lower_arm_transform.basis.x)
  87. var t_y = skeleton.to_global(lower_arm_transform.basis.y)
  88. var t_z = skeleton.to_global(lower_arm_transform.basis.z)
  89. t_x = t_x - skeleton.global_transform.origin
  90. t_y = t_y - skeleton.global_transform.origin
  91. t_z = t_z - skeleton.global_transform.origin
  92. var goal_basis = Basis(t_x, -t_z, t_y)
  93. var start_basis = ref_hand_l.global_transform.basis
  94. var weight = clamp(grab_clip_weight, 0.0, 0.2) / 0.2
  95. #hand_l.global_transform.basis = start_basis.slerp(goal_basis, weight) # this is error prone for some reason
  96. hand_l.global_transform.basis = goal_basis
  97. update_arm_transforms()
  98.  
  99. func update_arm_transforms():
  100. var weight = clamp(grab_clip_weight, 0.0, 0.5) / 0.5
  101. var magnet_l_pos = magnet_l.global_transform.origin.linear_interpolate(reload_magnet.global_transform.origin, grab_clip_weight)
  102. update_arm_transform(upper_arm_l_ind, lower_arm_l_ind, hand_l_ind, arm_upper_length_l, arm_lower_length_l, hand_l, magnet_l_pos)
  103. #update_arm_transform(upper_arm_l_ind, lower_arm_l_ind, hand_l_ind, arm_upper_length_l, arm_lower_length_l, hand_l, magnet_l.global_transform.origin)
  104. update_arm_transform(upper_arm_r_ind, lower_arm_r_ind, hand_r_ind, arm_upper_length_r, arm_lower_length_r, hand_r, magnet_r.global_transform.origin, false)
  105.  
  106. func update_arm_transform(upper_arm_ind, lower_arm_ind, hand_ind, upper_arm_len, lower_arm_len, goal_hand, magnet_position, is_left=true):
  107. # bunch of math for doing IK on the arms
  108. var shoulder_pos = skeleton.get_bone_global_pose(upper_arm_ind).origin
  109. var goal_hand_pos = skeleton.to_local(goal_hand.global_transform.origin)
  110. var dis_from_shoulder_to_goal_pos = shoulder_pos.distance_to(goal_hand_pos)
  111. var angles = SSS_calc(upper_arm_len, lower_arm_len, dis_from_shoulder_to_goal_pos)
  112. var y = shoulder_pos.direction_to(goal_hand_pos)
  113. var tmp_z = shoulder_pos.direction_to(skeleton.to_local(magnet_position))
  114. var x = -y.cross(tmp_z).normalized()
  115. var z = x.cross(y).normalized()
  116.  
  117.  
  118. var angle = angles.B
  119. if angle != 0 and is_left:
  120. angle = PI - angle
  121. if !is_left:
  122. x = -x
  123. z = -z
  124. angle = -(PI - angle)
  125.  
  126. y = y.rotated(x, angle)
  127. z = z.rotated(x, angle)
  128.  
  129. var upper_arm_y = y
  130.  
  131. #arm will point along y of basis, bicep faces towards z, x is towards inside
  132. var new_upper_arm_transform = Transform()
  133. new_upper_arm_transform.basis = Basis(z, y, -x)
  134. new_upper_arm_transform.origin = shoulder_pos
  135. new_upper_arm_transform.scaled(skeleton.scale)
  136. skeleton.set_bone_global_pose_override(upper_arm_ind, new_upper_arm_transform, 1, true)
  137.  
  138. var new_lower_arm_transform = Transform()
  139. #var elbow_pos = skeleton.get_bone_global_pose(lower_arm_ind).origin
  140.  
  141. if is_left:
  142. angle = PI - angles.C
  143. else:
  144. var tmp = y
  145. y = z
  146. z = -tmp
  147. angle = -3*PI/2 + angles.C
  148.  
  149. y = -y.rotated(x, angle).normalized()
  150. z = -z.rotated(x, angle)
  151.  
  152. if is_left:
  153. var t = clamp(cur_y_angle/90, 0.0, 1.0)
  154. z = z.rotated(y, -t * deg2rad(30))
  155. x = x.rotated(y, -t * deg2rad(30))
  156.  
  157. new_lower_arm_transform.basis = Basis(z, y, -x)
  158. new_lower_arm_transform.origin = shoulder_pos + upper_arm_y * upper_arm_len
  159. skeleton.set_bone_global_pose_override(lower_arm_ind, new_lower_arm_transform, 1, true)
  160.  
  161. var new_hand_transform = Transform()
  162. var hand_global_pos = goal_hand.global_transform.origin
  163. new_hand_transform.origin = goal_hand_pos
  164. var t_x = skeleton.to_local(hand_global_pos + goal_hand.global_transform.basis.x)
  165. var t_y = skeleton.to_local(hand_global_pos + goal_hand.global_transform.basis.y)
  166. var t_z = skeleton.to_local(hand_global_pos + goal_hand.global_transform.basis.z)
  167. t_x = t_x - goal_hand_pos
  168. t_y = t_y - goal_hand_pos
  169. t_z = t_z - goal_hand_pos
  170. if is_left:
  171. new_hand_transform.basis = Basis(t_x, t_z, -t_y)
  172. else:
  173. new_hand_transform.basis = Basis(t_x, -t_z, t_y)
  174. skeleton.set_bone_global_pose_override(hand_ind, new_hand_transform, 1, true)
  175. #$DebugPoint.transform.origin = new_hand_transform.origin
  176.  
  177.  
  178. func SSS_calc(side_a, side_b, side_c):
  179. if side_c >= side_a + side_b:
  180. return {"A": 0, "B": 0, "C": 0}
  181. var angle_a = law_of_cos(side_b, side_c, side_a)
  182. var angle_b = law_of_cos(side_c, side_a, side_b) + PI
  183. var angle_c = PI - angle_a - angle_b
  184.  
  185. return {"A": angle_a, "B": angle_b, "C": angle_c}
  186.  
  187. func law_of_cos(a, b, c):
  188. if 2 * a * b == 0:
  189. return 0
  190. return acos( (a * a + b * b - c * c) / ( 2 * a * b) )
  191.  
  192. var cur_y_angle = 0.0
  193. func update_turn_info(y_angle: float):
  194. cur_y_angle = y_angle
  195.  
  196. func set_grab_clip_weight(weight: float):
  197. grab_clip_weight = weight
  198.  
  199.  
Advertisement
Add Comment
Please, Sign In to add comment