IKSolverFullBody.cs 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  1. using UnityEngine;
  2. using System.Collections;
  3. namespace RootMotion.FinalIK {
  4. /// <summary>
  5. /// Generic FBIK solver. In each solver update, %IKSolverFullBody first reads the character's pose, then solves the %IK and writes the solved pose back to the character via IKMapping.
  6. /// </summary>
  7. [System.Serializable]
  8. public class IKSolverFullBody : IKSolver {
  9. #region Main Interface
  10. /// <summary>
  11. /// Number of solver iterations.
  12. /// </summary>
  13. [Range(0, 10)]
  14. public int iterations = 4;
  15. /// <summary>
  16. /// The root node chain.
  17. /// </summary>
  18. public FBIKChain[] chain = new FBIKChain[0];
  19. /// <summary>
  20. /// The effectors.
  21. /// </summary>
  22. public IKEffector[] effectors = new IKEffector[0];
  23. /// <summary>
  24. /// Mapping spine bones to the solver.
  25. /// </summary>
  26. public IKMappingSpine spineMapping = new IKMappingSpine();
  27. /// <summary>
  28. /// Mapping individual bones to the solver
  29. /// </summary>
  30. public IKMappingBone[] boneMappings = new IKMappingBone[0];
  31. /// <summary>
  32. /// Mapping 3 segment limbs to the solver
  33. /// </summary>
  34. public IKMappingLimb[] limbMappings = new IKMappingLimb[0];
  35. /// <summary>
  36. /// If false, will not solve a FABRIK pass and the arms/legs will not be able to pull the body.
  37. /// </summary>
  38. public bool FABRIKPass = true;
  39. /// <summary>
  40. /// Gets the effector of the specified Transform.
  41. /// </summary>
  42. public IKEffector GetEffector(Transform t) {
  43. for (int i = 0; i < effectors.Length; i++) if (effectors[i].bone == t) return effectors[i];
  44. return null;
  45. }
  46. /// <summary>
  47. /// Gets the chain that contains the specified Transform.
  48. /// </summary>
  49. public FBIKChain GetChain(Transform transform) {
  50. int index = GetChainIndex(transform);
  51. if (index == -1) return null;
  52. return chain[index];
  53. }
  54. /// <summary>
  55. /// Gets the index of the chain (in the IKSolverFullBody.chain array) that contains the specified Transform.
  56. /// </summary>
  57. public int GetChainIndex(Transform transform) {
  58. for (int i = 0; i < chain.Length; i++) {
  59. for (int n = 0; n < chain[i].nodes.Length; n++) if (chain[i].nodes[n].transform == transform) return i;
  60. }
  61. return -1;
  62. }
  63. public IKSolver.Node GetNode(int chainIndex, int nodeIndex) {
  64. return chain[chainIndex].nodes[nodeIndex];
  65. }
  66. public void GetChainAndNodeIndexes(Transform transform, out int chainIndex, out int nodeIndex) {
  67. chainIndex = GetChainIndex(transform);
  68. if (chainIndex == -1) nodeIndex = -1;
  69. else nodeIndex = chain[chainIndex].GetNodeIndex(transform);
  70. }
  71. public override IKSolver.Point[] GetPoints() {
  72. int nodes = 0;
  73. for (int i = 0; i < chain.Length; i++) nodes += chain[i].nodes.Length;
  74. IKSolver.Point[] pointArray = new IKSolver.Point[nodes];
  75. int added = 0;
  76. for (int i = 0; i < chain.Length; i++) {
  77. for (int n = 0; n < chain[i].nodes.Length; n++) {
  78. pointArray[added] = chain[i].nodes[n] as IKSolver.Node;
  79. added++;
  80. }
  81. }
  82. return pointArray;
  83. }
  84. public override IKSolver.Point GetPoint(Transform transform) {
  85. for (int i = 0; i < chain.Length; i++) {
  86. for (int n = 0; n < chain[i].nodes.Length; n++) if (chain[i].nodes[n].transform == transform) return chain[i].nodes[n] as IKSolver.Point;
  87. }
  88. return null;
  89. }
  90. public override bool IsValid(ref string message) {
  91. if (chain == null) {
  92. message = "FBIK chain is null, can't initiate solver.";
  93. return false;
  94. }
  95. if (chain.Length == 0) {
  96. message = "FBIK chain length is 0, can't initiate solver.";
  97. return false;
  98. }
  99. for (int i = 0; i < chain.Length; i++) {
  100. if (!chain[i].IsValid(ref message)) return false;
  101. }
  102. foreach (IKEffector e in effectors) if (!e.IsValid(this, ref message)) return false;
  103. if (!spineMapping.IsValid(this, ref message)) return false;
  104. foreach (IKMappingLimb l in limbMappings) if (!l.IsValid(this, ref message)) return false;
  105. foreach (IKMappingBone b in boneMappings) if (!b.IsValid(this, ref message)) return false;
  106. return true;
  107. }
  108. /// <summary>
  109. /// Called before reading the pose
  110. /// </summary>
  111. public UpdateDelegate OnPreRead;
  112. /// <summary>
  113. /// Called before solving.
  114. /// </summary>
  115. public UpdateDelegate OnPreSolve;
  116. /// <summary>
  117. /// Called before each iteration
  118. /// </summary>
  119. public IterationDelegate OnPreIteration;
  120. /// <summary>
  121. /// Called after each iteration
  122. /// </summary>
  123. public IterationDelegate OnPostIteration;
  124. /// <summary>
  125. /// Called before applying bend constraints.
  126. /// </summary>
  127. public UpdateDelegate OnPreBend;
  128. /// <summary>
  129. /// Called after updating the solver
  130. /// </summary>
  131. public UpdateDelegate OnPostSolve;
  132. /// <summary>
  133. /// Called when storing default local state (the state that FixTransforms will reset the hierarchy to).
  134. /// </summary>
  135. public UpdateDelegate OnStoreDefaultLocalState;
  136. /// <summary>
  137. /// Called when the bones used by the solver will reset to the default local state.
  138. /// </summary>
  139. public UpdateDelegate OnFixTransforms;
  140. #endregion Main Interface
  141. public override void StoreDefaultLocalState() {
  142. spineMapping.StoreDefaultLocalState();
  143. for (int i = 0; i < limbMappings.Length; i++) limbMappings[i].StoreDefaultLocalState();
  144. for (int i = 0; i < boneMappings.Length; i++) boneMappings[i].StoreDefaultLocalState();
  145. if (OnStoreDefaultLocalState != null) OnStoreDefaultLocalState();
  146. }
  147. public override void FixTransforms() {
  148. if (!initiated) return;
  149. if (IKPositionWeight <= 0f) return;
  150. spineMapping.FixTransforms();
  151. for (int i = 0; i < limbMappings.Length; i++) limbMappings[i].FixTransforms();
  152. for (int i = 0; i < boneMappings.Length; i++) boneMappings[i].FixTransforms();
  153. if (OnFixTransforms != null) OnFixTransforms();
  154. }
  155. protected override void OnInitiate() {
  156. // Initiate chain
  157. for (int i = 0; i < chain.Length; i++) {
  158. chain[i].Initiate(this);
  159. }
  160. // Initiate effectors
  161. foreach (IKEffector e in effectors) e.Initiate(this);
  162. // Initiate IK mapping
  163. spineMapping.Initiate(this);
  164. foreach (IKMappingBone boneMapping in boneMappings) boneMapping.Initiate(this);
  165. foreach (IKMappingLimb limbMapping in limbMappings) limbMapping.Initiate(this);
  166. }
  167. protected override void OnUpdate() {
  168. if (IKPositionWeight <= 0) {
  169. // clear effector positionOffsets so they would not accumulate
  170. for (int i = 0; i < effectors.Length; i++) effectors[i].positionOffset = Vector3.zero;
  171. return;
  172. }
  173. if (chain.Length == 0) return;
  174. IKPositionWeight = Mathf.Clamp(IKPositionWeight, 0f, 1f);
  175. if (OnPreRead != null) OnPreRead();
  176. // Phase 1: Read the pose of the biped
  177. ReadPose();
  178. if (OnPreSolve != null) OnPreSolve();
  179. // Phase 2: Solve IK
  180. Solve();
  181. if (OnPostSolve != null) OnPostSolve();
  182. // Phase 3: Map biped to it's solved state
  183. WritePose();
  184. // Reset effector position offsets to Vector3.zero
  185. for (int i = 0; i < effectors.Length; i++) effectors[i].OnPostWrite();
  186. }
  187. protected virtual void ReadPose() {
  188. // Making sure the limbs are not inverted
  189. for (int i = 0; i < chain.Length; i++) {
  190. if (chain[i].bendConstraint.initiated) chain[i].bendConstraint.LimitBend(IKPositionWeight, GetEffector(chain[i].nodes[2].transform).positionWeight);
  191. }
  192. // Presolve effectors, apply effector offset to the nodes
  193. for (int i = 0; i < effectors.Length; i++) effectors[i].ResetOffset(this);
  194. for (int i = 0; i < effectors.Length; i++) effectors[i].OnPreSolve(this);
  195. // Set solver positions to match the current bone positions of the biped
  196. for (int i = 0; i < chain.Length; i++) {
  197. chain[i].ReadPose(this, iterations > 0);
  198. }
  199. // IKMapping
  200. if (iterations > 0) {
  201. spineMapping.ReadPose();
  202. for (int i = 0; i < boneMappings.Length; i++) boneMappings[i].ReadPose();
  203. }
  204. for (int i = 0; i < limbMappings.Length; i++) limbMappings[i].ReadPose();
  205. }
  206. protected virtual void Solve() {
  207. // Iterate solver
  208. if(iterations > 0) {
  209. for (int i = 0; i < (FABRIKPass? iterations: 1); i++) {
  210. if (OnPreIteration != null) OnPreIteration(i);
  211. // Apply end-effectors
  212. for (int e = 0; e < effectors.Length; e++) if (effectors[e].isEndEffector) effectors[e].Update(this);
  213. if (FABRIKPass) {
  214. // Reaching
  215. chain[0].Push(this);
  216. // Reaching
  217. if (FABRIKPass) chain[0].Reach(this);
  218. // Apply non end-effectors
  219. for (int e = 0; e < effectors.Length; e++) if (!effectors[e].isEndEffector) effectors[e].Update(this);
  220. }
  221. // Trigonometric pass to release push tension from the solver
  222. chain[0].SolveTrigonometric(this);
  223. if (FABRIKPass) {
  224. // Solving FABRIK forward
  225. chain[0].Stage1(this);
  226. // Apply non end-effectors again
  227. for (int e = 0; e < effectors.Length; e++) if (!effectors[e].isEndEffector) effectors[e].Update(this);
  228. // Solving FABRIK backwards
  229. chain[0].Stage2(this, chain[0].nodes[0].solverPosition);
  230. }
  231. if (OnPostIteration != null) OnPostIteration(i);
  232. }
  233. }
  234. // Before applying bend constraints (last chance to modify the bend direction)
  235. if (OnPreBend != null) OnPreBend();
  236. // Final end-effector pass
  237. for (int i = 0; i < effectors.Length; i++) if (effectors[i].isEndEffector) effectors[i].Update(this);
  238. ApplyBendConstraints();
  239. }
  240. protected virtual void ApplyBendConstraints() {
  241. // Solve bend constraints
  242. chain[0].SolveTrigonometric(this, true);
  243. }
  244. protected virtual void WritePose() {
  245. if (IKPositionWeight <= 0f) return;
  246. // Apply IK mapping
  247. if (iterations > 0) {
  248. spineMapping.WritePose(this);
  249. for (int i = 0; i < boneMappings.Length; i++) boneMappings[i].WritePose(IKPositionWeight);
  250. }
  251. for (int i = 0; i < limbMappings.Length; i++) limbMappings[i].WritePose(this, iterations > 0);
  252. }
  253. }
  254. }