/Source/ThirdParty/ik/src/solver_2bone.c

https://gitlab.com/Teo-Mirror/AtomicGameEngine · C · 138 lines · 92 code · 16 blank · 30 comment · 5 complexity · 43e635c707623de0b8b50eefecb9856a MD5 · raw file

  1. #include "ik/effector.h"
  2. #include "ik/node.h"
  3. #include "ik/log.h"
  4. #include "ik/solver_2bone.h"
  5. #include <assert.h>
  6. #include <math.h>
  7. #include <stddef.h>
  8. /* ------------------------------------------------------------------------- */
  9. int
  10. solver_2bone_construct(ik_solver_t* solver)
  11. {
  12. two_bone_t* two_bone = (two_bone_t*)solver;
  13. /* set up derived functions */
  14. two_bone->destruct = solver_2bone_destruct;
  15. two_bone->post_chain_build = solver_2bone_post_chain_build;
  16. two_bone->solve = solver_2bone_solve;
  17. return 0;
  18. }
  19. /* ------------------------------------------------------------------------- */
  20. void
  21. solver_2bone_destruct(ik_solver_t* solver)
  22. {
  23. }
  24. /* ------------------------------------------------------------------------- */
  25. int
  26. solver_2bone_post_chain_build(ik_solver_t* solver)
  27. {
  28. /*
  29. * We need to assert that there really are only chains of length 1 and no
  30. * sub chains.
  31. */
  32. ORDERED_VECTOR_FOR_EACH(&solver->chain_tree.islands, chain_island_t, island)
  33. if (ordered_vector_count(&island->root_chain.nodes) != 3) /* 3 nodes = 2 bones */
  34. {
  35. ik_log_message("ERROR: Your tree has chains that are longer or shorter than 2 bones. Are you sure you selected the correct solver algorithm?");
  36. return -1;
  37. }
  38. if (ordered_vector_count(&island->root_chain.children) > 0)
  39. {
  40. ik_log_message("ERROR: Your tree has child chains. This solver does not support arbitrary trees. You will need to switch to another algorithm (e.g. FABRIK)");
  41. return -1;
  42. }
  43. ORDERED_VECTOR_END_EACH
  44. return 0;
  45. }
  46. /* ------------------------------------------------------------------------- */
  47. int
  48. solver_2bone_solve(ik_solver_t* solver)
  49. {
  50. ORDERED_VECTOR_FOR_EACH(&solver->chain_tree.islands, chain_island_t, island)
  51. ik_node_t* node_tip;
  52. ik_node_t* node_mid;
  53. ik_node_t* node_base;
  54. vec3_t to_target;
  55. ik_real a, b, c, aa, bb, cc;
  56. assert(ordered_vector_count(&island->root_chain.nodes) > 2);
  57. node_tip = *(ik_node_t**)ordered_vector_get_element(&island->root_chain.nodes, 0);
  58. node_mid = *(ik_node_t**)ordered_vector_get_element(&island->root_chain.nodes, 1);
  59. node_base = *(ik_node_t**)ordered_vector_get_element(&island->root_chain.nodes, 2);
  60. assert(node_tip->effector != NULL);
  61. to_target = node_tip->effector->target_position;
  62. vec3_sub_vec3(to_target.f, node_base->position.f);
  63. /*
  64. * Form a triangle from the two segment lengths so we can calculate the
  65. * angles. Here's some visual help.
  66. *
  67. * target *--.__ a
  68. * \ --.___ (unknown position, needs solving)
  69. * \ _-
  70. * c \ _-
  71. * \- b
  72. * base
  73. *
  74. */
  75. a = node_tip->segment_length;
  76. b = node_mid->segment_length;
  77. aa = a*a;
  78. bb = b*b;
  79. cc = vec3_length_squared(to_target.f);
  80. c = sqrt(cc);
  81. /* check if in reach */
  82. if (c < a + b)
  83. {
  84. /* Cosine law to get base angle (alpha) */
  85. quat_t alpha_rotation;
  86. ik_real alpha = acos((bb + cc - aa) / (2.0 * node_mid->segment_length * sqrt(cc)));
  87. ik_real cos_a = cos(alpha * 0.5);
  88. ik_real sin_a = sin(alpha * 0.5);
  89. /* Cross product of both segment vectors defines axis of rotation */
  90. alpha_rotation.vw.v = node_tip->position;
  91. vec3_sub_vec3(alpha_rotation.f, node_mid->position.f); /* top segment */
  92. vec3_sub_vec3(node_mid->position.f, node_base->position.f); /* bottom segment */
  93. vec3_cross(alpha_rotation.f, node_mid->position.f);
  94. /*
  95. * Set up quaternion describing the rotation of alpha. Need to
  96. * normalise vec3 component of quaternion so rotation is correct.
  97. */
  98. vec3_normalise(alpha_rotation.f);
  99. vec3_mul_scalar(alpha_rotation.f, sin_a);
  100. alpha_rotation.q.w = cos_a;
  101. /* Rotate side c and scale to length of side b to get the unknown position */
  102. node_mid->position = to_target;
  103. vec3_normalise(node_mid->position.f);
  104. vec3_mul_scalar(node_mid->position.f, node_mid->segment_length);
  105. quat_rotate_vec(node_mid->position.f, alpha_rotation.f);
  106. vec3_add_vec3(node_mid->position.f, node_base->position.f);
  107. node_tip->position = node_tip->effector->target_position;
  108. }
  109. else
  110. {
  111. /* Just point both segments at target */
  112. vec3_normalise(to_target.f);
  113. node_mid->position = to_target;
  114. node_tip->position = to_target;
  115. vec3_mul_scalar(node_mid->position.f, node_mid->segment_length);
  116. vec3_mul_scalar(node_tip->position.f, node_tip->segment_length);
  117. vec3_add_vec3(node_mid->position.f, node_base->position.f);
  118. vec3_add_vec3(node_tip->position.f, node_mid->position.f);
  119. }
  120. ORDERED_VECTOR_END_EACH
  121. return 0;
  122. }