Advertisement
Staggart

Spline Junction

Apr 5th, 2024 (edited)
836
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 6.13 KB | None | 0 0
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using Unity.Mathematics;
  5. using UnityEngine;
  6. using UnityEngine.Splines;
  7. #if UNITY_EDITOR
  8. using UnityEditor;
  9. #endif
  10.  
  11. namespace sc.modeling.splines.runtime.auxiliary
  12. {
  13.     //This component can exposed connections, to which the start/end of a spline can be attached.
  14.     //Useful to link two splines together, or to create intersections
  15.     public class SplineJunction : MonoBehaviour
  16.     {
  17.         public Vector3 offset;
  18.        
  19.         [Serializable]
  20.         public class Connection
  21.         {
  22.             public SplineContainer splineContainer;
  23.             public enum Target
  24.             {
  25.                 Start,
  26.                 End
  27.             }
  28.             public Target connect;
  29.            
  30.             [Space]
  31.            
  32.             public Vector3 position;
  33.             public Vector3 rotation;
  34.            
  35.             [Space]
  36.            
  37.             [Min(0.01f)]
  38.             [Tooltip("Control how strongly the spline gets aligned to the connection. This is essentially the knot tangent.")]
  39.             public float stiffness = 5f;
  40.         }
  41.        
  42.         public List<Connection> connections = new List<Connection>();
  43.  
  44.         private void Reset()
  45.         {
  46.             Connection a = new Connection();
  47.             a.position.z = -1f;
  48.             a.rotation.y = 180f;
  49.             a.stiffness = 5f;
  50.             a.connect = Connection.Target.Start;
  51.            
  52.             Connection b = new Connection();
  53.             b.position.z = 1f;
  54.             b.rotation.y = 0f;
  55.             b.stiffness = 5f;
  56.             b.connect = Connection.Target.End;
  57.  
  58.             connections.Add(a);
  59.             connections.Add(b);
  60.         }
  61.        
  62.         public void Reconnect()
  63.         {
  64.             foreach (Connection connection in connections)
  65.             {
  66.                 if(connection.splineContainer == null) continue;
  67.  
  68.                 Vector3 worldPos = this.transform.TransformPoint(connection.position + offset);
  69.                 Vector3 localPos = connection.splineContainer.transform.InverseTransformPoint(worldPos);
  70.  
  71.                 int knotIndex = connection.connect == Connection.Target.Start ? 0 : connection.splineContainer.Splines[0].Knots.Count()-1;
  72.                 BezierKnot knot = connection.splineContainer.Splines[0].Knots.ElementAt(knotIndex);
  73.                
  74.                 knot.Position = localPos;
  75.                 knot.Rotation = (this.transform.rotation) * Quaternion.Euler(connection.rotation);
  76.  
  77.                 BezierTangent tangentType;
  78.                 if (connection.connect == Connection.Target.Start)
  79.                 {
  80.                     tangentType = BezierTangent.Out;
  81.                     knot.TangentOut = new float3(0f, 0f, connection.stiffness);
  82.                 }
  83.                 else
  84.                 {
  85.                     tangentType = BezierTangent.In;
  86.                     knot.TangentIn = new float3(0f, 0f, connection.stiffness);
  87.                 }
  88.  
  89.                 connection.splineContainer.Splines[0].SetKnot(knotIndex, knot, tangentType);
  90.                 connection.splineContainer.Splines[0].SetTangentMode(knotIndex, TangentMode.Continuous);
  91.             }    
  92.         }
  93.  
  94.         private void OnDrawGizmos()
  95.         {
  96.             DrawGizmos(false);
  97.         }
  98.  
  99.         private void OnDrawGizmosSelected()
  100.         {
  101.             DrawGizmos(true);
  102.         }
  103.  
  104.         private void DrawGizmos(bool selected)
  105.         {
  106.             #if UNITY_EDITOR
  107.             Gizmos.matrix = this.transform.localToWorldMatrix;
  108.             float handleSize = 0.2f;
  109.            
  110.             handleSize *= HandleUtility.GetHandleSize(this.transform.position);
  111.             Handles.matrix = Gizmos.matrix;
  112.            
  113.             if (selected)
  114.             {
  115.                 if (transform.hasChanged)
  116.                 {
  117.                     transform.hasChanged = false;
  118.                
  119.                     Reconnect();
  120.                 }
  121.             }
  122.            
  123.             foreach (Connection connection in connections)
  124.             {
  125.                 if (!selected)
  126.                 {
  127.                     //Make the junction selectable
  128.                     Gizmos.color = Color.cyan;
  129.                     //Gizmos.color = Color.clear;
  130.                     Gizmos.DrawCube(connection.position, Vector3.one * handleSize);
  131.                 }
  132.                 else
  133.                 {
  134.                     Gizmos.color = connection.splineContainer == null ? Color.red : Color.green;
  135.  
  136.                     Gizmos.DrawWireCube(connection.position + offset, Vector3.one * handleSize);
  137.  
  138.                     Vector3 normal = (Quaternion.Euler(connection.rotation) * Vector3.forward).normalized;
  139.  
  140.                     Handles.color = Gizmos.color;
  141.                     Handles.DrawAAPolyLine(Texture2D.whiteTexture, 3f, new []{ connection.position, connection.position + normal});
  142.                 }
  143.             }
  144.             #endif
  145.         }
  146.     }
  147.    
  148.     #if UNITY_EDITOR
  149.     [CustomEditor(typeof(SplineJunction))]
  150.     [CanEditMultipleObjects]
  151.     public class SplineJunctionInspector : Editor
  152.     {
  153.         [MenuItem("GameObject/Spline/Junction", false, 1000)]
  154.         private static void AddObjectMenu()
  155.         {
  156.             GameObject gameObject = new GameObject("Spline Junction", new []{typeof(SplineJunction)});
  157.            
  158.             if (Selection.activeGameObject) gameObject.transform.parent = Selection.activeGameObject.transform;
  159.            
  160.             Selection.activeGameObject = gameObject;
  161.  
  162.             EditorApplication.ExecuteMenuItem("GameObject/Move To View");
  163.            
  164.             if(Application.isPlaying == false) UnityEditor.SceneManagement.EditorSceneManager.MarkSceneDirty(UnityEngine.SceneManagement.SceneManager.GetActiveScene());
  165.         }
  166.        
  167.         public override void OnInspectorGUI()
  168.         {
  169.             EditorGUI.BeginChangeCheck();
  170.  
  171.             base.OnInspectorGUI();
  172.  
  173.             if (EditorGUI.EndChangeCheck())
  174.             {
  175.                 foreach (var m_target in targets)
  176.                     ((SplineJunction)m_target).Reconnect();
  177.             }
  178.         }
  179.     }
  180.     #endif
  181. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement