PenetrationAvoidance.cs 3.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. using UnityEngine;
  2. using System.Collections;
  3. using RootMotion.FinalIK;
  4. namespace RootMotion.FinalIK {
  5. /// <summary>
  6. /// Prevents body parts from penetrating scene geometry by offsetting effectors away from the colliders.
  7. /// </summary>
  8. public class PenetrationAvoidance : OffsetModifier {
  9. /// <summary>
  10. /// Definition of avoidance and raycasting info.
  11. /// </summary>
  12. [System.Serializable]
  13. public class Avoider {
  14. /// <summary>
  15. /// Linking this to an effector
  16. /// </summary>
  17. [System.Serializable]
  18. public class EffectorLink {
  19. [Tooltip("Effector to apply the offset to.")] public FullBodyBipedEffector effector;
  20. [Tooltip("Multiplier of the offset value, can be negative.")] public float weight;
  21. }
  22. [Tooltip("Bones to start the raycast from. Multiple raycasts can be used by assigning more than 1 bone.")] public Transform[] raycastFrom;
  23. [Tooltip("The Transform to raycast towards. Usually the body part that you want to keep from penetrating.")] public Transform raycastTo;
  24. [Tooltip("If 0, will use simple raycasting, if > 0, will use sphere casting (better, but slower).")] [Range(0f, 1f)] public float raycastRadius;
  25. [Tooltip("Linking this to FBBIK effectors.")] public EffectorLink[] effectors;
  26. [Tooltip("The time of smooth interpolation of the offset value to avoid penetration.")] public float smoothTimeIn = 0.1f;
  27. [Tooltip("The time of smooth interpolation of the offset value blending out of penetration avoidance.")] public float smoothTimeOut = 0.3f;
  28. [Tooltip("Layers to keep penetrating from.")] public LayerMask layers;
  29. private Vector3 offset;
  30. private Vector3 offsetTarget;
  31. private Vector3 offsetV;
  32. public void Solve(IKSolverFullBodyBiped solver, float weight) {
  33. // Get the offset to interpolate to
  34. offsetTarget = GetOffsetTarget(solver);
  35. // Interpolating the offset value
  36. float smoothDampTime = offsetTarget.sqrMagnitude > offset.sqrMagnitude? smoothTimeIn: smoothTimeOut;
  37. offset = Vector3.SmoothDamp(offset, offsetTarget, ref offsetV, smoothDampTime);
  38. // Apply offset to the FBBIK effectors
  39. foreach (EffectorLink link in effectors) {
  40. solver.GetEffector(link.effector).positionOffset += offset * weight * link.weight;
  41. }
  42. }
  43. // Multiple raycasting to accumulate the offset
  44. private Vector3 GetOffsetTarget(IKSolverFullBodyBiped solver) {
  45. Vector3 t = Vector3.zero;
  46. foreach (Transform from in raycastFrom) {
  47. t += Raycast(from.position, raycastTo.position + t);
  48. }
  49. return t;
  50. }
  51. // Raycast, return the offset that would not penetrate any colliders
  52. private Vector3 Raycast(Vector3 from, Vector3 to) {
  53. Vector3 direction = to - from;
  54. float distance = direction.magnitude;
  55. RaycastHit hit;
  56. if (raycastRadius <= 0f) {
  57. Physics.Raycast(from, direction, out hit, distance, layers);
  58. } else {
  59. Physics.SphereCast(from, raycastRadius, direction, out hit, distance, layers);
  60. }
  61. if (hit.collider == null) return Vector3.zero;
  62. return Vector3.Project(-direction.normalized * (distance - hit.distance), hit.normal);
  63. }
  64. }
  65. [Tooltip("Definitions of penetration avoidances.")] public Avoider[] avoiders;
  66. // Called by IKSolverFullBody before updating
  67. protected override void OnModifyOffset() {
  68. foreach (Avoider avoider in avoiders) avoider.Solve(ik.solver, weight);
  69. }
  70. }
  71. }