skeleton_modification_3d_fabrik.cpp 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628
  1. /*************************************************************************/
  2. /* skeleton_modification_3d_fabrik.cpp */
  3. /*************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* https://godotengine.org */
  7. /*************************************************************************/
  8. /* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
  9. /* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
  10. /* */
  11. /* Permission is hereby granted, free of charge, to any person obtaining */
  12. /* a copy of this software and associated documentation files (the */
  13. /* "Software"), to deal in the Software without restriction, including */
  14. /* without limitation the rights to use, copy, modify, merge, publish, */
  15. /* distribute, sublicense, and/or sell copies of the Software, and to */
  16. /* permit persons to whom the Software is furnished to do so, subject to */
  17. /* the following conditions: */
  18. /* */
  19. /* The above copyright notice and this permission notice shall be */
  20. /* included in all copies or substantial portions of the Software. */
  21. /* */
  22. /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
  23. /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
  24. /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
  25. /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
  26. /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
  27. /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
  28. /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
  29. /*************************************************************************/
  30. #include "scene/resources/skeleton_modification_3d_fabrik.h"
  31. #include "scene/3d/skeleton_3d.h"
  32. #include "scene/resources/skeleton_modification_3d.h"
  33. bool SkeletonModification3DFABRIK::_set(const StringName &p_path, const Variant &p_value) {
  34. String path = p_path;
  35. if (path.begins_with("joint_data/")) {
  36. int fabrik_data_size = fabrik_data_chain.size();
  37. int which = path.get_slicec('/', 1).to_int();
  38. String what = path.get_slicec('/', 2);
  39. ERR_FAIL_INDEX_V(which, fabrik_data_size, false);
  40. if (what == "bone_name") {
  41. set_fabrik_joint_bone_name(which, p_value);
  42. } else if (what == "bone_index") {
  43. set_fabrik_joint_bone_index(which, p_value);
  44. } else if (what == "length") {
  45. set_fabrik_joint_length(which, p_value);
  46. } else if (what == "magnet_position") {
  47. set_fabrik_joint_magnet(which, p_value);
  48. } else if (what == "auto_calculate_length") {
  49. set_fabrik_joint_auto_calculate_length(which, p_value);
  50. } else if (what == "use_tip_node") {
  51. set_fabrik_joint_use_tip_node(which, p_value);
  52. } else if (what == "tip_node") {
  53. set_fabrik_joint_tip_node(which, p_value);
  54. } else if (what == "use_target_basis") {
  55. set_fabrik_joint_use_target_basis(which, p_value);
  56. } else if (what == "roll") {
  57. set_fabrik_joint_roll(which, Math::deg_to_rad(real_t(p_value)));
  58. }
  59. return true;
  60. }
  61. return true;
  62. }
  63. bool SkeletonModification3DFABRIK::_get(const StringName &p_path, Variant &r_ret) const {
  64. String path = p_path;
  65. if (path.begins_with("joint_data/")) {
  66. const int fabrik_data_size = fabrik_data_chain.size();
  67. int which = path.get_slicec('/', 1).to_int();
  68. String what = path.get_slicec('/', 2);
  69. ERR_FAIL_INDEX_V(which, fabrik_data_size, false);
  70. if (what == "bone_name") {
  71. r_ret = get_fabrik_joint_bone_name(which);
  72. } else if (what == "bone_index") {
  73. r_ret = get_fabrik_joint_bone_index(which);
  74. } else if (what == "length") {
  75. r_ret = get_fabrik_joint_length(which);
  76. } else if (what == "magnet_position") {
  77. r_ret = get_fabrik_joint_magnet(which);
  78. } else if (what == "auto_calculate_length") {
  79. r_ret = get_fabrik_joint_auto_calculate_length(which);
  80. } else if (what == "use_tip_node") {
  81. r_ret = get_fabrik_joint_use_tip_node(which);
  82. } else if (what == "tip_node") {
  83. r_ret = get_fabrik_joint_tip_node(which);
  84. } else if (what == "use_target_basis") {
  85. r_ret = get_fabrik_joint_use_target_basis(which);
  86. } else if (what == "roll") {
  87. r_ret = Math::rad_to_deg(get_fabrik_joint_roll(which));
  88. }
  89. return true;
  90. }
  91. return true;
  92. }
  93. void SkeletonModification3DFABRIK::_get_property_list(List<PropertyInfo> *p_list) const {
  94. for (uint32_t i = 0; i < fabrik_data_chain.size(); i++) {
  95. String base_string = "joint_data/" + itos(i) + "/";
  96. p_list->push_back(PropertyInfo(Variant::STRING_NAME, base_string + "bone_name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
  97. p_list->push_back(PropertyInfo(Variant::INT, base_string + "bone_index", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
  98. p_list->push_back(PropertyInfo(Variant::FLOAT, base_string + "roll", PROPERTY_HINT_RANGE, "-360,360,0.01", PROPERTY_USAGE_DEFAULT));
  99. p_list->push_back(PropertyInfo(Variant::BOOL, base_string + "auto_calculate_length", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
  100. if (!fabrik_data_chain[i].auto_calculate_length) {
  101. p_list->push_back(PropertyInfo(Variant::FLOAT, base_string + "length", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
  102. } else {
  103. p_list->push_back(PropertyInfo(Variant::BOOL, base_string + "use_tip_node", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
  104. if (fabrik_data_chain[i].use_tip_node) {
  105. p_list->push_back(PropertyInfo(Variant::NODE_PATH, base_string + "tip_node", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Node3D", PROPERTY_USAGE_DEFAULT));
  106. }
  107. }
  108. // Cannot apply magnet to the origin of the chain, as it will not do anything.
  109. if (i > 0) {
  110. p_list->push_back(PropertyInfo(Variant::VECTOR3, base_string + "magnet_position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
  111. }
  112. // Only give the override basis option on the last bone in the chain, so only include it for the last bone.
  113. if (i == fabrik_data_chain.size() - 1) {
  114. p_list->push_back(PropertyInfo(Variant::BOOL, base_string + "use_target_basis", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
  115. }
  116. }
  117. }
  118. void SkeletonModification3DFABRIK::_execute(real_t p_delta) {
  119. ERR_FAIL_COND_MSG(!stack || !is_setup || stack->skeleton == nullptr,
  120. "Modification is not setup and therefore cannot execute!");
  121. if (!enabled) {
  122. return;
  123. }
  124. if (target_node_cache.is_null()) {
  125. _print_execution_error(true, "Target cache is out of date. Attempting to update...");
  126. update_target_cache();
  127. return;
  128. }
  129. if (_print_execution_error(fabrik_data_chain.size() <= 1, "FABRIK requires at least two joints to operate. Cannot execute modification!")) {
  130. return;
  131. }
  132. Node3D *node_target = Object::cast_to<Node3D>(ObjectDB::get_instance(target_node_cache));
  133. if (_print_execution_error(!node_target || !node_target->is_inside_tree(), "Target node is not in the scene tree. Cannot execute modification!")) {
  134. return;
  135. }
  136. // Make sure the transform cache is the correct size
  137. if (fabrik_transforms.size() != fabrik_data_chain.size()) {
  138. fabrik_transforms.resize(fabrik_data_chain.size());
  139. }
  140. // Verify that all joints have a valid bone ID, and that all bone lengths are zero or more
  141. // Also, while we are here, apply magnet positions.
  142. for (uint32_t i = 0; i < fabrik_data_chain.size(); i++) {
  143. if (_print_execution_error(fabrik_data_chain[i].bone_idx < 0, "FABRIK Joint " + itos(i) + " has an invalid bone ID. Cannot execute!")) {
  144. return;
  145. }
  146. if (fabrik_data_chain[i].length < 0 && fabrik_data_chain[i].auto_calculate_length) {
  147. fabrik_joint_auto_calculate_length(i);
  148. }
  149. if (_print_execution_error(fabrik_data_chain[i].length < 0, "FABRIK Joint " + itos(i) + " has an invalid joint length. Cannot execute!")) {
  150. return;
  151. }
  152. fabrik_transforms[i] = stack->skeleton->get_bone_global_pose(fabrik_data_chain[i].bone_idx);
  153. // Apply magnet positions:
  154. if (stack->skeleton->get_bone_parent(fabrik_data_chain[i].bone_idx) >= 0) {
  155. int parent_bone_idx = stack->skeleton->get_bone_parent(fabrik_data_chain[i].bone_idx);
  156. Transform3D conversion_transform = (stack->skeleton->get_bone_global_pose(parent_bone_idx));
  157. fabrik_transforms[i].origin += conversion_transform.basis.xform_inv(fabrik_data_chain[i].magnet_position);
  158. } else {
  159. fabrik_transforms[i].origin += fabrik_data_chain[i].magnet_position;
  160. }
  161. }
  162. Transform3D origin_global_pose_trans = stack->skeleton->get_bone_global_pose_no_override(fabrik_data_chain[0].bone_idx);
  163. target_global_pose = stack->skeleton->world_transform_to_global_pose(node_target->get_global_transform());
  164. origin_global_pose = origin_global_pose_trans;
  165. final_joint_idx = fabrik_data_chain.size() - 1;
  166. real_t target_distance = fabrik_transforms[final_joint_idx].origin.distance_to(target_global_pose.origin);
  167. chain_iterations = 0;
  168. while (target_distance > chain_tolerance) {
  169. chain_backwards();
  170. chain_forwards();
  171. // update the target distance
  172. target_distance = fabrik_transforms[final_joint_idx].origin.distance_to(target_global_pose.origin);
  173. // update chain iterations
  174. chain_iterations += 1;
  175. if (chain_iterations >= chain_max_iterations) {
  176. break;
  177. }
  178. }
  179. chain_apply();
  180. execution_error_found = false;
  181. }
  182. void SkeletonModification3DFABRIK::chain_backwards() {
  183. int final_bone_idx = fabrik_data_chain[final_joint_idx].bone_idx;
  184. Transform3D final_joint_trans = fabrik_transforms[final_joint_idx];
  185. // Get the direction the final bone is facing in.
  186. stack->skeleton->update_bone_rest_forward_vector(final_bone_idx);
  187. Transform3D final_bone_direction_trans = final_joint_trans.looking_at(target_global_pose.origin, Vector3(0, 1, 0));
  188. final_bone_direction_trans.basis = stack->skeleton->global_pose_z_forward_to_bone_forward(final_bone_idx, final_bone_direction_trans.basis);
  189. Vector3 direction = final_bone_direction_trans.basis.xform(stack->skeleton->get_bone_axis_forward_vector(final_bone_idx)).normalized();
  190. // If set to override, then use the target's Basis rather than the bone's
  191. if (fabrik_data_chain[final_joint_idx].use_target_basis) {
  192. direction = target_global_pose.basis.xform(stack->skeleton->get_bone_axis_forward_vector(final_bone_idx)).normalized();
  193. }
  194. // set the position of the final joint to the target position
  195. final_joint_trans.origin = target_global_pose.origin - (direction * fabrik_data_chain[final_joint_idx].length);
  196. fabrik_transforms[final_joint_idx] = final_joint_trans;
  197. // for all other joints, move them towards the target
  198. int i = final_joint_idx;
  199. while (i >= 1) {
  200. Transform3D next_bone_trans = fabrik_transforms[i];
  201. i -= 1;
  202. Transform3D current_trans = fabrik_transforms[i];
  203. real_t length = fabrik_data_chain[i].length / (current_trans.origin.distance_to(next_bone_trans.origin));
  204. current_trans.origin = next_bone_trans.origin.lerp(current_trans.origin, length);
  205. // Save the result
  206. fabrik_transforms[i] = current_trans;
  207. }
  208. }
  209. void SkeletonModification3DFABRIK::chain_forwards() {
  210. // Set root at the initial position.
  211. Transform3D root_transform = fabrik_transforms[0];
  212. root_transform.origin = origin_global_pose.origin;
  213. fabrik_transforms[0] = origin_global_pose;
  214. for (uint32_t i = 0; i < fabrik_data_chain.size() - 1; i++) {
  215. Transform3D current_trans = fabrik_transforms[i];
  216. Transform3D next_bone_trans = fabrik_transforms[i + 1];
  217. real_t length = fabrik_data_chain[i].length / (next_bone_trans.origin.distance_to(current_trans.origin));
  218. next_bone_trans.origin = current_trans.origin.lerp(next_bone_trans.origin, length);
  219. // Save the result
  220. fabrik_transforms[i + 1] = next_bone_trans;
  221. }
  222. }
  223. void SkeletonModification3DFABRIK::chain_apply() {
  224. for (uint32_t i = 0; i < fabrik_data_chain.size(); i++) {
  225. int current_bone_idx = fabrik_data_chain[i].bone_idx;
  226. Transform3D current_trans = fabrik_transforms[i];
  227. // If this is the last bone in the chain...
  228. if (i == fabrik_data_chain.size() - 1) {
  229. if (fabrik_data_chain[i].use_target_basis == false) { // Point to target...
  230. // Get the forward direction that the basis is facing in right now.
  231. stack->skeleton->update_bone_rest_forward_vector(current_bone_idx);
  232. Vector3 forward_vector = stack->skeleton->get_bone_axis_forward_vector(current_bone_idx);
  233. // Rotate the bone towards the target:
  234. current_trans.basis.rotate_to_align(forward_vector, current_trans.origin.direction_to(target_global_pose.origin));
  235. current_trans.basis.rotate_local(forward_vector, fabrik_data_chain[i].roll);
  236. } else { // Use the target's Basis...
  237. current_trans.basis = target_global_pose.basis.orthonormalized().scaled(current_trans.basis.get_scale());
  238. }
  239. } else { // every other bone in the chain...
  240. Transform3D next_trans = fabrik_transforms[i + 1];
  241. // Get the forward direction that the basis is facing in right now.
  242. stack->skeleton->update_bone_rest_forward_vector(current_bone_idx);
  243. Vector3 forward_vector = stack->skeleton->get_bone_axis_forward_vector(current_bone_idx);
  244. // Rotate the bone towards the next bone in the chain:
  245. current_trans.basis.rotate_to_align(forward_vector, current_trans.origin.direction_to(next_trans.origin));
  246. current_trans.basis.rotate_local(forward_vector, fabrik_data_chain[i].roll);
  247. }
  248. stack->skeleton->set_bone_local_pose_override(current_bone_idx, stack->skeleton->global_pose_to_local_pose(current_bone_idx, current_trans), stack->strength, true);
  249. }
  250. // Update all the bones so the next modification has up-to-date data.
  251. stack->skeleton->force_update_all_bone_transforms();
  252. }
  253. void SkeletonModification3DFABRIK::_setup_modification(SkeletonModificationStack3D *p_stack) {
  254. stack = p_stack;
  255. if (stack != nullptr) {
  256. is_setup = true;
  257. execution_error_found = false;
  258. update_target_cache();
  259. for (uint32_t i = 0; i < fabrik_data_chain.size(); i++) {
  260. update_joint_tip_cache(i);
  261. }
  262. }
  263. }
  264. void SkeletonModification3DFABRIK::update_target_cache() {
  265. if (!is_setup || !stack) {
  266. _print_execution_error(true, "Cannot update target cache: modification is not properly setup!");
  267. return;
  268. }
  269. target_node_cache = ObjectID();
  270. if (stack->skeleton) {
  271. if (stack->skeleton->is_inside_tree() && target_node.is_empty() == false) {
  272. if (stack->skeleton->has_node(target_node)) {
  273. Node *node = stack->skeleton->get_node(target_node);
  274. ERR_FAIL_COND_MSG(!node || stack->skeleton == node,
  275. "Cannot update target cache: node is this modification's skeleton or cannot be found!");
  276. ERR_FAIL_COND_MSG(!node->is_inside_tree(),
  277. "Cannot update target cache: node is not in the scene tree!");
  278. target_node_cache = node->get_instance_id();
  279. execution_error_found = false;
  280. }
  281. }
  282. }
  283. }
  284. void SkeletonModification3DFABRIK::update_joint_tip_cache(int p_joint_idx) {
  285. const int bone_chain_size = fabrik_data_chain.size();
  286. ERR_FAIL_INDEX_MSG(p_joint_idx, bone_chain_size, "FABRIK joint not found");
  287. if (!is_setup || !stack) {
  288. _print_execution_error(true, "Cannot update tip cache: modification is not properly setup!");
  289. return;
  290. }
  291. fabrik_data_chain[p_joint_idx].tip_node_cache = ObjectID();
  292. if (stack->skeleton) {
  293. if (stack->skeleton->is_inside_tree() && fabrik_data_chain[p_joint_idx].tip_node.is_empty() == false) {
  294. if (stack->skeleton->has_node(fabrik_data_chain[p_joint_idx].tip_node)) {
  295. Node *node = stack->skeleton->get_node(fabrik_data_chain[p_joint_idx].tip_node);
  296. ERR_FAIL_COND_MSG(!node || stack->skeleton == node,
  297. "Cannot update tip cache for joint " + itos(p_joint_idx) + ": node is this modification's skeleton or cannot be found!");
  298. ERR_FAIL_COND_MSG(!node->is_inside_tree(),
  299. "Cannot update tip cache for joint " + itos(p_joint_idx) + ": node is not in scene tree!");
  300. fabrik_data_chain[p_joint_idx].tip_node_cache = node->get_instance_id();
  301. execution_error_found = false;
  302. }
  303. }
  304. }
  305. }
  306. void SkeletonModification3DFABRIK::set_target_node(const NodePath &p_target_node) {
  307. target_node = p_target_node;
  308. update_target_cache();
  309. }
  310. NodePath SkeletonModification3DFABRIK::get_target_node() const {
  311. return target_node;
  312. }
  313. int SkeletonModification3DFABRIK::get_fabrik_data_chain_length() {
  314. return fabrik_data_chain.size();
  315. }
  316. void SkeletonModification3DFABRIK::set_fabrik_data_chain_length(int p_length) {
  317. ERR_FAIL_COND(p_length < 0);
  318. fabrik_data_chain.resize(p_length);
  319. fabrik_transforms.resize(p_length);
  320. execution_error_found = false;
  321. notify_property_list_changed();
  322. }
  323. real_t SkeletonModification3DFABRIK::get_chain_tolerance() {
  324. return chain_tolerance;
  325. }
  326. void SkeletonModification3DFABRIK::set_chain_tolerance(real_t p_tolerance) {
  327. ERR_FAIL_COND_MSG(p_tolerance <= 0, "FABRIK chain tolerance must be more than zero!");
  328. chain_tolerance = p_tolerance;
  329. }
  330. int SkeletonModification3DFABRIK::get_chain_max_iterations() {
  331. return chain_max_iterations;
  332. }
  333. void SkeletonModification3DFABRIK::set_chain_max_iterations(int p_iterations) {
  334. ERR_FAIL_COND_MSG(p_iterations <= 0, "FABRIK chain iterations must be at least one. Set enabled to false to disable the FABRIK chain.");
  335. chain_max_iterations = p_iterations;
  336. }
  337. // FABRIK joint data functions
  338. String SkeletonModification3DFABRIK::get_fabrik_joint_bone_name(int p_joint_idx) const {
  339. const int bone_chain_size = fabrik_data_chain.size();
  340. ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, String());
  341. return fabrik_data_chain[p_joint_idx].bone_name;
  342. }
  343. void SkeletonModification3DFABRIK::set_fabrik_joint_bone_name(int p_joint_idx, String p_bone_name) {
  344. const int bone_chain_size = fabrik_data_chain.size();
  345. ERR_FAIL_INDEX(p_joint_idx, bone_chain_size);
  346. fabrik_data_chain[p_joint_idx].bone_name = p_bone_name;
  347. if (stack) {
  348. if (stack->skeleton) {
  349. fabrik_data_chain[p_joint_idx].bone_idx = stack->skeleton->find_bone(p_bone_name);
  350. }
  351. }
  352. execution_error_found = false;
  353. notify_property_list_changed();
  354. }
  355. int SkeletonModification3DFABRIK::get_fabrik_joint_bone_index(int p_joint_idx) const {
  356. const int bone_chain_size = fabrik_data_chain.size();
  357. ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, -1);
  358. return fabrik_data_chain[p_joint_idx].bone_idx;
  359. }
  360. void SkeletonModification3DFABRIK::set_fabrik_joint_bone_index(int p_joint_idx, int p_bone_idx) {
  361. const int bone_chain_size = fabrik_data_chain.size();
  362. ERR_FAIL_INDEX(p_joint_idx, bone_chain_size);
  363. ERR_FAIL_COND_MSG(p_bone_idx < 0, "Bone index is out of range: The index is too low!");
  364. fabrik_data_chain[p_joint_idx].bone_idx = p_bone_idx;
  365. if (stack) {
  366. if (stack->skeleton) {
  367. fabrik_data_chain[p_joint_idx].bone_name = stack->skeleton->get_bone_name(p_bone_idx);
  368. }
  369. }
  370. execution_error_found = false;
  371. notify_property_list_changed();
  372. }
  373. real_t SkeletonModification3DFABRIK::get_fabrik_joint_length(int p_joint_idx) const {
  374. const int bone_chain_size = fabrik_data_chain.size();
  375. ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, -1);
  376. return fabrik_data_chain[p_joint_idx].length;
  377. }
  378. void SkeletonModification3DFABRIK::set_fabrik_joint_length(int p_joint_idx, real_t p_bone_length) {
  379. const int bone_chain_size = fabrik_data_chain.size();
  380. ERR_FAIL_INDEX(p_joint_idx, bone_chain_size);
  381. ERR_FAIL_COND_MSG(p_bone_length < 0, "FABRIK joint length cannot be less than zero!");
  382. if (!is_setup) {
  383. fabrik_data_chain[p_joint_idx].length = p_bone_length;
  384. return;
  385. }
  386. if (fabrik_data_chain[p_joint_idx].auto_calculate_length) {
  387. WARN_PRINT("FABRIK Length not set: auto calculate length is enabled for this joint!");
  388. fabrik_joint_auto_calculate_length(p_joint_idx);
  389. } else {
  390. fabrik_data_chain[p_joint_idx].length = p_bone_length;
  391. }
  392. execution_error_found = false;
  393. }
  394. Vector3 SkeletonModification3DFABRIK::get_fabrik_joint_magnet(int p_joint_idx) const {
  395. const int bone_chain_size = fabrik_data_chain.size();
  396. ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, Vector3());
  397. return fabrik_data_chain[p_joint_idx].magnet_position;
  398. }
  399. void SkeletonModification3DFABRIK::set_fabrik_joint_magnet(int p_joint_idx, Vector3 p_magnet) {
  400. const int bone_chain_size = fabrik_data_chain.size();
  401. ERR_FAIL_INDEX(p_joint_idx, bone_chain_size);
  402. fabrik_data_chain[p_joint_idx].magnet_position = p_magnet;
  403. }
  404. bool SkeletonModification3DFABRIK::get_fabrik_joint_auto_calculate_length(int p_joint_idx) const {
  405. const int bone_chain_size = fabrik_data_chain.size();
  406. ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, false);
  407. return fabrik_data_chain[p_joint_idx].auto_calculate_length;
  408. }
  409. void SkeletonModification3DFABRIK::set_fabrik_joint_auto_calculate_length(int p_joint_idx, bool p_auto_calculate) {
  410. const int bone_chain_size = fabrik_data_chain.size();
  411. ERR_FAIL_INDEX(p_joint_idx, bone_chain_size);
  412. fabrik_data_chain[p_joint_idx].auto_calculate_length = p_auto_calculate;
  413. fabrik_joint_auto_calculate_length(p_joint_idx);
  414. notify_property_list_changed();
  415. }
  416. void SkeletonModification3DFABRIK::fabrik_joint_auto_calculate_length(int p_joint_idx) {
  417. const int bone_chain_size = fabrik_data_chain.size();
  418. ERR_FAIL_INDEX(p_joint_idx, bone_chain_size);
  419. if (!fabrik_data_chain[p_joint_idx].auto_calculate_length) {
  420. return;
  421. }
  422. if (!stack || !stack->skeleton || !is_setup) {
  423. _print_execution_error(true, "Cannot auto calculate joint length: modification is not properly setup!");
  424. return;
  425. }
  426. ERR_FAIL_INDEX_MSG(fabrik_data_chain[p_joint_idx].bone_idx, stack->skeleton->get_bone_count(),
  427. "Bone for joint " + itos(p_joint_idx) + " is not set or points to an unknown bone!");
  428. if (fabrik_data_chain[p_joint_idx].use_tip_node) { // Use the tip node to update joint length.
  429. update_joint_tip_cache(p_joint_idx);
  430. Node3D *tip_node = Object::cast_to<Node3D>(ObjectDB::get_instance(fabrik_data_chain[p_joint_idx].tip_node_cache));
  431. ERR_FAIL_COND_MSG(!tip_node, "Tip node for joint " + itos(p_joint_idx) + "is not a Node3D-based node. Cannot calculate length...");
  432. ERR_FAIL_COND_MSG(!tip_node->is_inside_tree(), "Tip node for joint " + itos(p_joint_idx) + "is not in the scene tree. Cannot calculate length...");
  433. Transform3D node_trans = tip_node->get_global_transform();
  434. node_trans = stack->skeleton->world_transform_to_global_pose(node_trans);
  435. //node_trans = stack->skeleton->global_pose_to_local_pose(fabrik_data_chain[p_joint_idx].bone_idx, node_trans);
  436. //fabrik_data_chain[p_joint_idx].length = node_trans.origin.length();
  437. fabrik_data_chain[p_joint_idx].length = stack->skeleton->get_bone_global_pose(fabrik_data_chain[p_joint_idx].bone_idx).origin.distance_to(node_trans.origin);
  438. } else { // Use child bone(s) to update joint length, if possible
  439. Vector<int> bone_children = stack->skeleton->get_bone_children(fabrik_data_chain[p_joint_idx].bone_idx);
  440. if (bone_children.size() <= 0) {
  441. ERR_FAIL_MSG("Cannot calculate length for joint " + itos(p_joint_idx) + "joint uses leaf bone. \nPlease manually set the bone length or use a tip node!");
  442. return;
  443. }
  444. Transform3D bone_trans = stack->skeleton->get_bone_global_pose(fabrik_data_chain[p_joint_idx].bone_idx);
  445. real_t final_length = 0;
  446. for (int i = 0; i < bone_children.size(); i++) {
  447. Transform3D child_transform = stack->skeleton->get_bone_global_pose(bone_children[i]);
  448. final_length += bone_trans.origin.distance_to(child_transform.origin);
  449. //final_length += stack->skeleton->global_pose_to_local_pose(fabrik_data_chain[p_joint_idx].bone_idx, child_transform).origin.length();
  450. }
  451. fabrik_data_chain[p_joint_idx].length = final_length / bone_children.size();
  452. }
  453. execution_error_found = false;
  454. notify_property_list_changed();
  455. }
  456. bool SkeletonModification3DFABRIK::get_fabrik_joint_use_tip_node(int p_joint_idx) const {
  457. const int bone_chain_size = fabrik_data_chain.size();
  458. ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, false);
  459. return fabrik_data_chain[p_joint_idx].use_tip_node;
  460. }
  461. void SkeletonModification3DFABRIK::set_fabrik_joint_use_tip_node(int p_joint_idx, bool p_use_tip_node) {
  462. const int bone_chain_size = fabrik_data_chain.size();
  463. ERR_FAIL_INDEX(p_joint_idx, bone_chain_size);
  464. fabrik_data_chain[p_joint_idx].use_tip_node = p_use_tip_node;
  465. notify_property_list_changed();
  466. }
  467. NodePath SkeletonModification3DFABRIK::get_fabrik_joint_tip_node(int p_joint_idx) const {
  468. const int bone_chain_size = fabrik_data_chain.size();
  469. ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, NodePath());
  470. return fabrik_data_chain[p_joint_idx].tip_node;
  471. }
  472. void SkeletonModification3DFABRIK::set_fabrik_joint_tip_node(int p_joint_idx, NodePath p_tip_node) {
  473. const int bone_chain_size = fabrik_data_chain.size();
  474. ERR_FAIL_INDEX(p_joint_idx, bone_chain_size);
  475. fabrik_data_chain[p_joint_idx].tip_node = p_tip_node;
  476. update_joint_tip_cache(p_joint_idx);
  477. }
  478. bool SkeletonModification3DFABRIK::get_fabrik_joint_use_target_basis(int p_joint_idx) const {
  479. const int bone_chain_size = fabrik_data_chain.size();
  480. ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, false);
  481. return fabrik_data_chain[p_joint_idx].use_target_basis;
  482. }
  483. void SkeletonModification3DFABRIK::set_fabrik_joint_use_target_basis(int p_joint_idx, bool p_use_target_basis) {
  484. const int bone_chain_size = fabrik_data_chain.size();
  485. ERR_FAIL_INDEX(p_joint_idx, bone_chain_size);
  486. fabrik_data_chain[p_joint_idx].use_target_basis = p_use_target_basis;
  487. }
  488. real_t SkeletonModification3DFABRIK::get_fabrik_joint_roll(int p_joint_idx) const {
  489. const int bone_chain_size = fabrik_data_chain.size();
  490. ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, 0.0);
  491. return fabrik_data_chain[p_joint_idx].roll;
  492. }
  493. void SkeletonModification3DFABRIK::set_fabrik_joint_roll(int p_joint_idx, real_t p_roll) {
  494. const int bone_chain_size = fabrik_data_chain.size();
  495. ERR_FAIL_INDEX(p_joint_idx, bone_chain_size);
  496. fabrik_data_chain[p_joint_idx].roll = p_roll;
  497. }
  498. void SkeletonModification3DFABRIK::_bind_methods() {
  499. ClassDB::bind_method(D_METHOD("set_target_node", "target_nodepath"), &SkeletonModification3DFABRIK::set_target_node);
  500. ClassDB::bind_method(D_METHOD("get_target_node"), &SkeletonModification3DFABRIK::get_target_node);
  501. ClassDB::bind_method(D_METHOD("set_fabrik_data_chain_length", "length"), &SkeletonModification3DFABRIK::set_fabrik_data_chain_length);
  502. ClassDB::bind_method(D_METHOD("get_fabrik_data_chain_length"), &SkeletonModification3DFABRIK::get_fabrik_data_chain_length);
  503. ClassDB::bind_method(D_METHOD("set_chain_tolerance", "tolerance"), &SkeletonModification3DFABRIK::set_chain_tolerance);
  504. ClassDB::bind_method(D_METHOD("get_chain_tolerance"), &SkeletonModification3DFABRIK::get_chain_tolerance);
  505. ClassDB::bind_method(D_METHOD("set_chain_max_iterations", "max_iterations"), &SkeletonModification3DFABRIK::set_chain_max_iterations);
  506. ClassDB::bind_method(D_METHOD("get_chain_max_iterations"), &SkeletonModification3DFABRIK::get_chain_max_iterations);
  507. // FABRIK joint data functions
  508. ClassDB::bind_method(D_METHOD("get_fabrik_joint_bone_name", "joint_idx"), &SkeletonModification3DFABRIK::get_fabrik_joint_bone_name);
  509. ClassDB::bind_method(D_METHOD("set_fabrik_joint_bone_name", "joint_idx", "bone_name"), &SkeletonModification3DFABRIK::set_fabrik_joint_bone_name);
  510. ClassDB::bind_method(D_METHOD("get_fabrik_joint_bone_index", "joint_idx"), &SkeletonModification3DFABRIK::get_fabrik_joint_bone_index);
  511. ClassDB::bind_method(D_METHOD("set_fabrik_joint_bone_index", "joint_idx", "bone_index"), &SkeletonModification3DFABRIK::set_fabrik_joint_bone_index);
  512. ClassDB::bind_method(D_METHOD("get_fabrik_joint_length", "joint_idx"), &SkeletonModification3DFABRIK::get_fabrik_joint_length);
  513. ClassDB::bind_method(D_METHOD("set_fabrik_joint_length", "joint_idx", "length"), &SkeletonModification3DFABRIK::set_fabrik_joint_length);
  514. ClassDB::bind_method(D_METHOD("get_fabrik_joint_magnet", "joint_idx"), &SkeletonModification3DFABRIK::get_fabrik_joint_magnet);
  515. ClassDB::bind_method(D_METHOD("set_fabrik_joint_magnet", "joint_idx", "magnet_position"), &SkeletonModification3DFABRIK::set_fabrik_joint_magnet);
  516. ClassDB::bind_method(D_METHOD("get_fabrik_joint_auto_calculate_length", "joint_idx"), &SkeletonModification3DFABRIK::get_fabrik_joint_auto_calculate_length);
  517. ClassDB::bind_method(D_METHOD("set_fabrik_joint_auto_calculate_length", "joint_idx", "auto_calculate_length"), &SkeletonModification3DFABRIK::set_fabrik_joint_auto_calculate_length);
  518. ClassDB::bind_method(D_METHOD("fabrik_joint_auto_calculate_length", "joint_idx"), &SkeletonModification3DFABRIK::fabrik_joint_auto_calculate_length);
  519. ClassDB::bind_method(D_METHOD("get_fabrik_joint_use_tip_node", "joint_idx"), &SkeletonModification3DFABRIK::get_fabrik_joint_use_tip_node);
  520. ClassDB::bind_method(D_METHOD("set_fabrik_joint_use_tip_node", "joint_idx", "use_tip_node"), &SkeletonModification3DFABRIK::set_fabrik_joint_use_tip_node);
  521. ClassDB::bind_method(D_METHOD("get_fabrik_joint_tip_node", "joint_idx"), &SkeletonModification3DFABRIK::get_fabrik_joint_tip_node);
  522. ClassDB::bind_method(D_METHOD("set_fabrik_joint_tip_node", "joint_idx", "tip_node"), &SkeletonModification3DFABRIK::set_fabrik_joint_tip_node);
  523. ClassDB::bind_method(D_METHOD("get_fabrik_joint_use_target_basis", "joint_idx"), &SkeletonModification3DFABRIK::get_fabrik_joint_use_target_basis);
  524. ClassDB::bind_method(D_METHOD("set_fabrik_joint_use_target_basis", "joint_idx", "use_target_basis"), &SkeletonModification3DFABRIK::set_fabrik_joint_use_target_basis);
  525. ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "target_nodepath", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Node3D"), "set_target_node", "get_target_node");
  526. ADD_PROPERTY(PropertyInfo(Variant::INT, "fabrik_data_chain_length", PROPERTY_HINT_RANGE, "0,100,1"), "set_fabrik_data_chain_length", "get_fabrik_data_chain_length");
  527. ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "chain_tolerance", PROPERTY_HINT_RANGE, "0,100,0.001"), "set_chain_tolerance", "get_chain_tolerance");
  528. ADD_PROPERTY(PropertyInfo(Variant::INT, "chain_max_iterations", PROPERTY_HINT_RANGE, "1,50,1"), "set_chain_max_iterations", "get_chain_max_iterations");
  529. }
  530. SkeletonModification3DFABRIK::SkeletonModification3DFABRIK() {
  531. stack = nullptr;
  532. is_setup = false;
  533. enabled = true;
  534. }
  535. SkeletonModification3DFABRIK::~SkeletonModification3DFABRIK() {
  536. }