Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using System;
- using System.Collections.Generic;
- using Unity.Mathematics;
- using UnityEngine;
- using UnityEngine.Splines;
- #if UNITY_EDITOR
- using UnityEditor;
- #endif
- namespace sc.modeling.splines.runtime.auxiliary
- {
- public class SplineLooping : MonoBehaviour
- {
- public SplineContainer splineContainer;
- [Min(1f)]
- public float knotDistance = 2f;
- public enum Direction
- {
- Right,
- Left
- }
- [Space]
- public Direction direction;
- public TextAlignment xAlignment = TextAlignment.Center;
- public TextAlignment zAlignment = TextAlignment.Center;
- [Header("Shape")]
- [Min(5f)]
- public float radius = 10f;
- [Min(0f)]
- public float width = 15f;
- [Range(1, 3)]
- public int loops = 1;
- [Header("Runway")]
- [Min(1f)]
- public float runwayLength = 15f;
- [Min(0f)]
- public float runwayHeight = 0f;
- [Header("Curvature")]
- [Range(0f,1f)]
- public float flattening = 1f;
- private void Reset()
- {
- splineContainer = GetComponent<SplineContainer>();
- if(!splineContainer) splineContainer = gameObject.AddComponent<SplineContainer>();
- }
- [Serializable]
- private class Point
- {
- public Point(float3 position, float3 forward, float3 up, float3 right)
- {
- this.position = position;
- this.forward = forward;
- this.up = up;
- this.right = right;
- }
- public float3 position;
- public float3 forward;
- public float3 up;
- public float3 right;
- }
- private Point[] points = Array.Empty<Point>();
- public void Rebuild()
- {
- if (!splineContainer) return;
- int pointCount = (int)(math.ceil((radius + width) / knotDistance) * loops);
- pointCount = Mathf.Max(8, pointCount);
- if (pointCount <= 1) return;
- for (int s = 0; s < splineContainer.Splines.Count; s++)
- {
- splineContainer.RemoveSpline(splineContainer.Splines[s]);
- }
- Spline spline = new Spline();
- float curAngle = -90f;
- float angleLength = 360 * loops;
- float angleIncrement = (angleLength / (float)pointCount);
- points = new Point[pointCount+1];
- float3 prevPosition = new float3(0f);
- for (int i = 0; i <= pointCount; i++)
- {
- float t = (float)i / (pointCount);
- t = math.clamp(t, 0.00001f, 0.999999f);
- float r = Mathf.Deg2Rad * curAngle;
- float3 dir = new float3(
- math.sin(t * 2f - 1f) * 0.5f,
- math.sin(r),
- math.cos(r));
- if (direction == Direction.Left) dir.x = -dir.x;
- //Negate x-component so that the direction stays level
- float3 up = -math.normalize(new float3(dir.x * (1f-flattening), dir.y, dir.z));
- float3 center = new float3(0f, dir.y, 0f);
- float3 right = math.normalize(dir - center);
- right = math.lerp(right, math.right(), flattening);
- float3 position = new Vector3(
- dir.x * width,
- dir.y * radius,
- dir.z * radius
- );
- //Uncenter
- position.y += radius;
- if (xAlignment == TextAlignment.Left) position.x += (width * 0.5f);
- if (xAlignment == TextAlignment.Right) position.x -= (width * 0.5f);
- //First
- if (i == 0)
- {
- position.z = -runwayLength;
- right = Vector3.right;
- up = Vector3.up;
- //Unknown, so place it before the first point
- prevPosition = position + (-math.forward() * 2f);
- }
- //Last
- else if (i == pointCount)
- {
- position.z += runwayLength;
- right = Vector3.right;
- up = Vector3.up;
- }
- else
- {
- position.y += runwayHeight;
- }
- if (zAlignment == TextAlignment.Left) position.z += (runwayLength);
- if (zAlignment == TextAlignment.Right) position.z -= (runwayLength);
- float3 forward = math.normalize(position - prevPosition);
- prevPosition = position;
- BezierKnot knot = new BezierKnot
- {
- Position = position,
- Rotation = Quaternion.LookRotation(-forward, up),
- };
- spline.Add(knot, TangentMode.AutoSmooth);
- points[i] = new Point(position, forward, up, right);
- curAngle += angleIncrement;
- }
- //Adding a spline automatically rebuilds the mesh
- splineContainer.AddSpline(spline);
- }
- private void OnDrawGizmosSelected()
- {
- if (!splineContainer) return;
- Gizmos.matrix = splineContainer.transform.localToWorldMatrix;
- foreach (Point p in points)
- {
- Gizmos.color = Color.blue;
- Gizmos.DrawLine(p.position, p.position + p.forward);
- Gizmos.color = Color.green;
- Gizmos.DrawLine(p.position, p.position + p.up);
- Gizmos.color = Color.red;
- Gizmos.DrawLine(p.position, p.position + p.right);
- }
- }
- }
- #if UNITY_EDITOR
- [CustomEditor(typeof(SplineLooping))]
- [CanEditMultipleObjects]
- public class SplineLoopingEditor : Editor
- {
- public override void OnInspectorGUI()
- {
- EditorGUI.BeginChangeCheck();
- base.OnInspectorGUI();
- if (EditorGUI.EndChangeCheck())
- {
- foreach (var m_target in targets)
- ((SplineLooping)m_target).Rebuild();
- }
- }
- }
- #endif
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement