TerrainOffset.cs 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455
  1. using UnityEngine;
  2. using System.Collections;
  3. using RootMotion.FinalIK;
  4. namespace RootMotion.Demos {
  5. /// <summary>
  6. /// Raycasting to the ground to redirect upper-body animation based on ground topography.
  7. /// </summary>
  8. public class TerrainOffset : MonoBehaviour {
  9. public AimIK aimIK; // Reference to the AimIK component
  10. public Vector3 raycastOffset = new Vector3(0f, 2f, 1.5f); // Offset from the character, in local space, to raycast from
  11. public LayerMask raycastLayers; // The layers we want to raycast at
  12. public float min = -2f, max = 2f; // Min and max for the offset
  13. public float lerpSpeed = 10f; // The speed of lerping the IKPosition to make things nice and smooth
  14. private RaycastHit hit;
  15. private Vector3 offset;
  16. void LateUpdate() {
  17. // Find the raycastOffset in world space
  18. Vector3 worldOffset = transform.rotation * raycastOffset;
  19. // Find how much higher is the ground at worldOffset relative to the character position.
  20. Vector3 realOffset = GetGroundHeightOffset(transform.position + worldOffset);
  21. // Smoothly lerp the offset value so it would not jump on sudden raycast changes
  22. offset = Vector3.Lerp(offset, realOffset, Time.deltaTime * lerpSpeed);
  23. // The default offset point at the character's height
  24. Vector3 zeroOffsetPosition = transform.position + new Vector3(worldOffset.x, 0f, worldOffset.z);
  25. // Make the Aim Transform look at the default offset point (So when we are on planar ground there will be nothing for Aim IK to do)
  26. aimIK.solver.transform.LookAt(zeroOffsetPosition);
  27. // Make Aim IK bend the spine by the offset.
  28. aimIK.solver.IKPosition = zeroOffsetPosition + offset;
  29. }
  30. private Vector3 GetGroundHeightOffset(Vector3 worldPosition) {
  31. // Visualize the raycast
  32. Debug.DrawRay(worldPosition, Vector3.down * raycastOffset.y * 2f, Color.green);
  33. // Raycast to find how much higher is the ground at worldPosition relative to the character.
  34. if (Physics.Raycast(worldPosition, Vector3.down, out hit, raycastOffset.y * 2f)) {
  35. return Mathf.Clamp(hit.point.y - transform.position.y, min, max) * Vector3.up;
  36. }
  37. // Raycast found nothing so return zero
  38. return Vector3.zero;
  39. }
  40. }
  41. }