SplineSmoother.cs 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.Collections.ObjectModel;
  5. using UnityEngine;
  6. using UnityEngine.Events;
  7. namespace SplineMesh {
  8. [DisallowMultipleComponent]
  9. [ExecuteInEditMode]
  10. [RequireComponent(typeof(Spline))]
  11. public class SplineSmoother : MonoBehaviour {
  12. private Spline spline;
  13. private Spline Spline {
  14. get {
  15. if (spline == null) spline = GetComponent<Spline>();
  16. return spline;
  17. }
  18. }
  19. [Range(0, 1f)] public float curvature = 0.3f;
  20. private void OnValidate() {
  21. SmoothAll();
  22. }
  23. private void OnEnable() {
  24. Spline.NodeListChanged += Spline_NodeListChanged;
  25. foreach(var node in Spline.nodes) {
  26. node.Changed += OnNodeChanged;
  27. }
  28. SmoothAll();
  29. }
  30. private void OnDisable() {
  31. Spline.NodeListChanged -= Spline_NodeListChanged;
  32. foreach (var node in Spline.nodes) {
  33. node.Changed -= OnNodeChanged;
  34. }
  35. }
  36. private void Spline_NodeListChanged(object sender, ListChangedEventArgs<SplineNode> args) {
  37. if(args.newItems != null) {
  38. foreach (var node in args.newItems) {
  39. node.Changed += OnNodeChanged;
  40. }
  41. }
  42. if(args.removedItems != null) {
  43. foreach (var node in args.removedItems) {
  44. node.Changed -= OnNodeChanged;
  45. }
  46. }
  47. }
  48. private void OnNodeChanged(object sender, EventArgs e) {
  49. var node = (SplineNode)sender;
  50. SmoothNode(node);
  51. var index = Spline.nodes.IndexOf(node);
  52. if(index > 0) {
  53. SmoothNode(Spline.nodes[index - 1]);
  54. }
  55. if(index < Spline.nodes.Count - 1) {
  56. SmoothNode(Spline.nodes[index + 1]);
  57. }
  58. }
  59. private void SmoothNode(SplineNode node) {
  60. var index = Spline.nodes.IndexOf(node);
  61. var pos = node.Position;
  62. // For the direction, we need to compute a smooth vector.
  63. // Orientation is obtained by substracting the vectors to the previous and next way points,
  64. // which give an acceptable tangent in most situations.
  65. // Then we apply a part of the average magnitude of these two vectors, according to the smoothness we want.
  66. var dir = Vector3.zero;
  67. float averageMagnitude = 0;
  68. if (index != 0) {
  69. var previousPos = Spline.nodes[index - 1].Position;
  70. var toPrevious = pos - previousPos;
  71. averageMagnitude += toPrevious.magnitude;
  72. dir += toPrevious.normalized;
  73. }
  74. if (index != Spline.nodes.Count - 1) {
  75. var nextPos = Spline.nodes[index + 1].Position;
  76. var toNext = pos - nextPos;
  77. averageMagnitude += toNext.magnitude;
  78. dir -= toNext.normalized;
  79. }
  80. averageMagnitude *= 0.5f;
  81. // This constant should vary between 0 and 0.5, and allows to add more or less smoothness.
  82. dir = dir.normalized * averageMagnitude * curvature;
  83. // In SplineMesh, the node direction is not relative to the node position.
  84. var controlPoint = dir + pos;
  85. // We only set one direction at each spline node because SplineMesh only support mirrored direction between curves.
  86. node.Direction = controlPoint;
  87. }
  88. private void SmoothAll() {
  89. foreach(var node in Spline.nodes) {
  90. SmoothNode(node);
  91. }
  92. }
  93. }
  94. }