过程动画用于螃蟹的装配动画和反向运动学。

huangapple go评论109阅读模式
英文:

Procedural animation for a crab with Rigging animation & Inverse kinematic

问题

我在Unity上工作,我必须完全更改我的脚本,以实现逆运动学的过程动画,实际上,为了向您解释,我有一只有8条腿的螃蟹,每条腿都有4个枢轴点,我想要的是当螃蟹移动时,腿也要移动,通过过程动画来实现。

我已经创建了一个脚本来完成所有这些,但是有时点会保持在原地,无法重置它,即使进行检查,无论在计算中、计算之外,甚至通过强制使用任务等方式。

所以我想知道这里是否有人可以帮助我修复这个错误,或者从一个良好的基础开始完全重新做一切。

这是我的完整脚本。

  1. // ReSharper disable once InvalidXmlDocComment
  2. /**
  3. * Original Script by: Sanchez Maxime (@Maxime66410)
  4. * @version 1.0.0
  5. * @autor Sanchez Maxime (@Maxime66410)
  6. *
  7. * Last modification: 09/06/2023
  8. * File description: This script is used to procedurally animate the crab
  9. */
  10. using System;
  11. using System.Collections.Generic;
  12. using System.Threading.Tasks;
  13. using UnityEngine;
  14. using UnityEngine.Serialization;
  15. // ReSharper disable once CheckNamespace
  16. public class CrabPatteCombine : MonoBehaviour
  17. {
  18. [FormerlySerializedAs("SingleLegs")] [Header("Legs GameObject"), Space(10)]
  19. public List<GameObject> singleLegs = new List<GameObject>(); // Paw GameObject
  20. [FormerlySerializedAs("SingleLegsIK")] public List<GameObject> singleLegsIK = new List<GameObject>(); // IK's GameObject
  21. [FormerlySerializedAs("SingleLegsTarget")] [Header("Vector3"), Space(10)]
  22. public List<Vector3> singleLegsTarget = new List<Vector3>(); // Leg position
  23. [FormerlySerializedAs("SingleLocalTarget")] public List<Vector3> singleLocalTarget = new List<Vector3>(); // Position of the IK
  24. // ...(省略了一部分脚本内容)...
  25. }

问题示例:
https://media.discordapp.net/attachments/1123226386677645373/1123226391358472243/bb4ec7b4f30a5931a16048c665ab1904.mp4

https://cdn.discordapp.com/attachments/1123226386677645373/1123226391840825425/abb57db906ed7d7ef2663f3e6fc1745d.mp4

这是我的问题:
如您所见,有时红色立方体会保持不动。
由于我在我的代码上遇到了一个小问题已经几周了,我想知道为什么有时我的“红色立方体”尽管在腿(立方体)和初始点之间进行了距离计算,但仍然永远停在原地,
尤其是即使使用了检查和强制方法来强制将腿(立方体)重新放置到初始位置,也不总是有效。

我已经尝试过与我的Unity专业编程老师一起解决这个问题,我在许多论坛上尝试过,甚至与chatgpt聊天,但没有帮助,找不到解决这个问题的方法。

https://cdn.discordapp.com/attachments/1123226386677645373/1123226466650427432/0e6118b5c8351e00b49602ec1d63e237.mp4

英文:

I work on unity, I have to completely change my script which allows to do procedural animation in reverse kinematic, in fact to explain to you I have a crab with 8 legs, each with 4 pivot points, and I want to do so that when the crab moves the legs also, via procedural animation.

I have already created a script to do all this, however sometimes the point remains in place, impossible to reset it, even with checks, whether in the calculation, out of the calculation, and even by forcing with Tasks etc..

So I would like to know if some here could help me fix this bug, or completely redo everything to start from a good base.

Here is my full script.

  1. // ReSharper disable once InvalidXmlDocComment
  2. /**
  3. * Original Script by: Sanchez Maxime (@Maxime66410)
  4. * @version 1.0.0
  5. * @autor Sanchez Maxime (@Maxime66410)
  6. *
  7. * Last modification: 09/06/2023
  8. * File description: This script is used to procedurally animate the crab
  9. */
  10. using System;
  11. using System.Collections.Generic;
  12. using System.Threading.Tasks;
  13. using UnityEngine;
  14. using UnityEngine.Serialization;
  15. // ReSharper disable once CheckNamespace
  16. public class CrabPatteCombine : MonoBehaviour
  17. {
  18. [FormerlySerializedAs("SingleLegs")] [Header("Legs GameObject"), Space(10)]
  19. public List<GameObject> singleLegs = new List<GameObject>(); // Paw GameObject
  20. [FormerlySerializedAs("SingleLegsIK")] public List<GameObject> singleLegsIK = new List<GameObject>(); // IK's GameObject
  21. [FormerlySerializedAs("SingleLegsTarget")] [Header("Vector3"), Space(10)]
  22. public List<Vector3> singleLegsTarget = new List<Vector3>(); // Leg position
  23. [FormerlySerializedAs("SingleLocalTarget")] public List<Vector3> singleLocalTarget = new List<Vector3>(); // Position of the IK
  24. [Header("Legs / Step"), Space(10)]
  25. [FormerlySerializedAs("SpeedSyncLegs")] public float speedSyncLegs = 10f; // paw speed
  26. [FormerlySerializedAs("DistanceToPoint")] public float distanceToPoint = 0.075f; // Distance between paw and target
  27. [FormerlySerializedAs("StepHeight")] public float stepHeight = 0.5f; // step height
  28. [FormerlySerializedAs("StepHeightCurve")] public AnimationCurve stepHeightCurve; // Step height curve
  29. [FormerlySerializedAs("OffsetStep")] public Vector3 offsetStep = Vector3.zero; // Step height offset
  30. [FormerlySerializedAs("_distanceStep")] [SerializeField] private List<float> distanceStep = new List<float>(); // Distance between paw and target
  31. [FormerlySerializedAs("_distanceToLegFromIK")] [SerializeField] private List<float> distanceToLegFromIK = new List<float>(); // Distance between paw and target
  32. [FormerlySerializedAs("DistanceToStopSyncLeg")] public float distanceToStopSyncLeg = 0.01f; // Distance between paw and target to stop synchronization
  33. [FormerlySerializedAs("MaxDistanceToSyncLeg")] public float maxDistanceToSyncLeg = 1f; // Maximum distance between paw and target to synchronize the paw
  34. [FormerlySerializedAs("MaxDistanceToSyncLeg")] public float maxDistanceDebug = 0.2f; // Maximum distance between paw and target to synchronize the paw (Debug)
  35. [FormerlySerializedAs("RaycastDistance")] public float raycastDistance = 0.3f; // Raycast distance
  36. [FormerlySerializedAs("LayerMaskGround")] public LayerMask layerMaskGround; // LayerMask
  37. public void Awake()
  38. {
  39. // Automatic initialization of the lists
  40. for (int i = 0; i < singleLegs.Count; i++)
  41. {
  42. distanceStep.Add(0f);
  43. distanceToLegFromIK.Add(0f);
  44. singleLegsTarget.Add(Vector3.zero);
  45. singleLocalTarget.Add(Vector3.zero);
  46. }
  47. }
  48. public void Start()
  49. {
  50. GetSurfaceOnStart();
  51. #pragma warning disable CS4014
  52. CheckDistanceLeg();
  53. #pragma warning restore CS4014
  54. }
  55. // Get crab area at start Position and rotation
  56. public void GetSurfaceOnStart()
  57. {
  58. // If SingleLegs is not empty
  59. if (singleLegs.Count > 0)
  60. {
  61. for (int i = 0; i < singleLegs.Count; i++)
  62. {
  63. singleLocalTarget[i] = singleLegsIK[i].transform.position; // Get IK paw position
  64. // Get the surface of the starting crab Position and rotation
  65. RaycastHit hit;
  66. if (Physics.Raycast(transform.position, Vector3.down, out hit, 0.03f, layerMaskGround))
  67. {
  68. singleLegs[i].transform.position = hit.point;
  69. singleLegsTarget[i] = hit.point;
  70. Transform transform1 = transform;
  71. transform1.rotation = Quaternion.FromToRotation(transform1.up, hit.normal) * (transform).rotation;
  72. }
  73. }
  74. }
  75. }
  76. public void FixedUpdate()
  77. {
  78. CheckDistance();
  79. UpdatePosition();
  80. }
  81. // Check the distance between the leg and the target
  82. public void CheckDistance()
  83. {
  84. // If SingleLegs is not empty
  85. if(singleLegs.Count > 0)
  86. {
  87. // Check the distance between the leg and the target
  88. for (int i = 0; i < singleLegs.Count; i++)
  89. {
  90. RaycastHit hit;
  91. if (Physics.Raycast(singleLocalTarget[i], Vector3.down, out hit, raycastDistance, layerMaskGround))
  92. {
  93. distanceStep[i] = Vector3.Distance(singleLegs[i].transform.position, hit.point);
  94. distanceToLegFromIK[i] = Vector3.Distance(singleLegs[i].transform.localPosition, singleLegsIK[i].transform.localPosition);
  95. // If the remaining distance is really too much greater than the target distance, reset the leg position (Fix Bug)
  96. if (distanceToLegFromIK[i] > maxDistanceToSyncLeg)
  97. {
  98. singleLegs[i].transform.position = singleLegsIK[i].transform.position;
  99. singleLegsTarget[i] = singleLegsIK[i].transform.position;
  100. singleLocalTarget[i] = singleLegsIK[i].transform.position;
  101. }
  102. else
  103. {
  104. // If the distance is greater than DistanceToPoint, update the leg position
  105. if (Vector3.Distance(singleLegs[i].transform.position, hit.point) > distanceToPoint)
  106. {
  107. singleLegsTarget[i] = hit.point;
  108. }
  109. }
  110. }
  111. }
  112. }
  113. }
  114. // Update leg position
  115. public void UpdatePosition()
  116. {
  117. if (singleLegs.Count > 0)
  118. {
  119. for (int i = 0; i < singleLegs.Count; i++)
  120. {
  121. if (singleLegs[i].transform.position != singleLegsTarget[i])
  122. {
  123. // Calculate the remaining distance between the current leg position and the target
  124. float remainingDistance = Vector3.Distance(singleLegs[i].transform.position, singleLegsTarget[i]);
  125. // Calculate total step based on remaining distance
  126. float totalStep = distanceToPoint * stepHeightCurve.length;
  127. // If the remaining distance is less than the total step, adjust the height of the step
  128. if (remainingDistance < totalStep)
  129. {
  130. // Calculate step height using StepHeightCurve
  131. // ReSharper disable once LocalVariableHidesMember
  132. float stepHeight = stepHeightCurve.Evaluate(1f - (remainingDistance / totalStep)) * this.stepHeight;
  133. // Move paw to target with height adjustment
  134. singleLegs[i].transform.position = Vector3.Lerp(singleLegs[i].transform.position, singleLegsTarget[i], Time.deltaTime * speedSyncLegs) + (offsetStep * stepHeight);
  135. // Adjust paw height to simulate lifting motion
  136. singleLegs[i].transform.position += Vector3.up * stepHeight;
  137. // If the remaining distance is less than a small threshold value, reset the position of the paw
  138. if (remainingDistance < distanceToStopSyncLeg)
  139. {
  140. singleLegs[i].transform.position = singleLegsTarget[i];
  141. }
  142. // If the remaining distance is really too much greater than the distance to the target, reset the position of the paw
  143. if (remainingDistance > maxDistanceToSyncLeg)
  144. {
  145. singleLegs[i].transform.position = singleLegsIK[i].transform.position;
  146. }
  147. }
  148. else
  149. {
  150. // Move paw to target without height adjustment
  151. singleLegs[i].transform.position = Vector3.Lerp(singleLegs[i].transform.position, singleLegsTarget[i], Time.deltaTime * speedSyncLegs);
  152. FixDistanceLeg();
  153. }
  154. }
  155. else
  156. {
  157. // If the remaining distance is really too much greater than the distance to the target, reset the position of the paw
  158. float remainingDistance = Vector3.Distance(singleLegs[i].transform.position, singleLegsIK[i].transform.position);
  159. // If the remaining distance is really too much greater than the distance to the target, reset the position of the paw
  160. if (remainingDistance > maxDistanceToSyncLeg)
  161. {
  162. singleLegs[i].transform.position = Vector3.Lerp(singleLegs[i].transform.position, singleLegsIK[i].transform.position, Time.deltaTime * speedSyncLegs);
  163. }
  164. }
  165. // Get the ground surface below the leg and adjust the local target
  166. RaycastHit hit;
  167. if (Physics.Raycast(singleLegsIK[i].transform.position, Vector3.down, out hit, raycastDistance, layerMaskGround))
  168. {
  169. singleLocalTarget[i] = Vector3.Lerp(singleLocalTarget[i], new Vector3(singleLegsIK[i].transform.position.x, hit.point.y, singleLegsIK[i].transform.position.z), Time.deltaTime * speedSyncLegs);
  170. }
  171. FixDistanceLeg();
  172. }
  173. }
  174. // SingleLocalTarget = SingleLegsIK.transform.position; // OLD
  175. }
  176. // If the remaining distance is really too much greater than the target distance, reset the leg position (Fix Bug)
  177. public void FixDistanceLeg()
  178. {
  179. for (int i = 0; i < singleLegs.Count; i++)
  180. {
  181. if (distanceToLegFromIK[i] > maxDistanceToSyncLeg)
  182. {
  183. singleLegs[i].transform.position = singleLegsIK[i].transform.position;
  184. singleLegsTarget[i] = singleLegsIK[i].transform.position;
  185. singleLocalTarget[i] = singleLegsIK[i].transform.position;
  186. }
  187. }
  188. }
  189. // ReSharper disable once FunctionRecursiveOnAllPaths
  190. public async Task CheckDistanceLeg()
  191. {
  192. for (int i = 0; i < singleLegs.Count; i++)
  193. {
  194. // If the distance between the paw and the target is greater than the maximum distance, reset the position of the paw
  195. float distance = Vector3.Distance(singleLegs[i].transform.position, singleLegsIK[i].transform.position);
  196. //Debug.Log($"Distance to Leg + {singleLegsIK[i].name} = {distance}");
  197. if(distance > maxDistanceDebug)
  198. {
  199. singleLegs[i].transform.position = singleLegsIK[i].transform.position;
  200. singleLegsTarget[i] = singleLegsIK[i].transform.position;
  201. singleLocalTarget[i] = singleLegsIK[i].transform.position;
  202. }
  203. }
  204. await Task.Delay(TimeSpan.FromSeconds(1));
  205. await CheckDistanceLeg();
  206. }
  207. // Draw a line between the paw and the target
  208. public void OnDrawGizmos()
  209. {
  210. if (singleLocalTarget.Count > 0)
  211. {
  212. for (int i = 0; i < singleLegs.Count; i++)
  213. {
  214. if (singleLocalTarget[i] != Vector3.zero)
  215. {
  216. Gizmos.color = Color.magenta;
  217. Gizmos.DrawLine(singleLegs[i].transform.position, singleLocalTarget[i]);
  218. }
  219. if(singleLocalTarget[i] != Vector3.zero)
  220. {
  221. Gizmos.color = Color.red;
  222. Gizmos.DrawLine(singleLocalTarget[i], singleLocalTarget[i] + Vector3.down * raycastDistance);
  223. }
  224. }
  225. }
  226. }
  227. }

Example :
https://media.discordapp.net/attachments/1123226386677645373/1123226391358472243/bb4ec7b4f30a5931a16048c665ab1904.mp4

https://cdn.discordapp.com/attachments/1123226386677645373/1123226391840825425/abb57db906ed7d7ef2663f3e6fc1745d.mp4

Here is my problem :
As you can see, sometimes the red cube remains frozen.
Since I've been stuck on a small problem on my code for several weeks, I would like to know why sometimes my "red cubes" stay stuck indefinitely in the same place despite the distance calculation between the leg (cube) and the point initial,
more especially as even with checks and methods which makes it possible to force to replace the leg (cube) towards the initial position does not work all the time.

I've already tried to solve the problem with my Unity specialist programming teacher, I've tried many forums, and even chatgpt, but nothing helped and couldn't find the solution to this problem.

https://cdn.discordapp.com/attachments/1123226386677645373/1123226466650427432/0e6118b5c8351e00b49602ec1d63e237.mp4

答案1

得分: 0

在我的代码中发现了一个计算错误,我是在全局计算,但我应该在本地计算。

删除脚本中的任务,它是无用的,而且做法不正确。

  1. public void FixDistanceLeg()
  2. {
  3. for (int i = 0; i < singleLegs.Count; i++)
  4. {
  5. var distanceIKtoLegLocal = Vector3.Distance(singleLegs[i].transform.localPosition, singleLegsIK[i].transform.localPosition);
  6. if (distanceIKtoLegLocal > distanceToFixStep)
  7. {
  8. //singleLegs[i].transform.position = singleLegsIK[i].transform.position;
  9. singleLegs[i].transform.position = Vector3.Lerp(singleLegs[i].transform.position, singleLegsIK[i].transform.position, Time.deltaTime * speedSyncLegs);
  10. singleLegsTarget[i] = singleLegsIK[i].transform.position;
  11. singleLocalTarget[i] = singleLegsIK[i].transform.position;
  12. }
  13. }
  14. }
英文:

Found, there is a calculation error in my code, I am calculating in world when I have to calculate locally.

Delete the task present in the script, it will be useless and it is not done in the right way.

  1. public void FixDistanceLeg()
  2. {
  3. for (int i = 0; i < singleLegs.Count; i++)
  4. {
  5. var distanceIKtoLegLocal = Vector3.Distance(singleLegs[i].transform.localPosition, singleLegsIK[i].transform.localPosition);
  6. if (distanceIKtoLegLocal > distanceToFixStep)
  7. {
  8. //singleLegs[i].transform.position = singleLegsIK[i].transform.position;
  9. singleLegs[i].transform.position = Vector3.Lerp(singleLegs[i].transform.position, singleLegsIK[i].transform.position, Time.deltaTime * speedSyncLegs);
  10. singleLegsTarget[i] = singleLegsIK[i].transform.position;
  11. singleLocalTarget[i] = singleLegsIK[i].transform.position;
  12. }
  13. }
  14. }

huangapple
  • 本文由 发表于 2023年6月27日 20:56:23
  • 转载请务必保留本文链接:https://go.coder-hub.com/76565097.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定