Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //Taken from http://catlikecoding.com/unity/tutorials/curves-and-splines/
- /*************
- * Bezier.cs *
- *************/
- using UnityEngine;
- using System.Collections;
- public static class Bezier {
- public static Vector3 GetPoint(Vector3 p0, Vector3 p1, Vector3 p2, float t) {
- t = Mathf.Clamp01(t);
- float oneMinusT = 1f - t;
- return (oneMinusT * oneMinusT * p0) + (2f * oneMinusT * t * p1) + (t * t * p2);
- }
- public static Vector3 GetFirstDerivative(Vector3 p0, Vector3 p1, Vector3 p2, float t) {
- return 2f * (1f - t) * (p1 - p0) + 2f * t * (p2 - p1);
- }
- public static Vector3 GetPoint(Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, float t) {
- t = Mathf.Clamp01(t);
- float oneMinusT = 1f - t;
- return oneMinusT * oneMinusT * oneMinusT * p0 +
- 3f * oneMinusT * oneMinusT * t * p1 +
- 3f * oneMinusT * t * t * p2 +
- t * t * t * p3;
- }
- public static Vector3 GetFirstDerivative(Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, float t) {
- t = Mathf.Clamp01(t);
- float oneMinusT = 1f - t;
- return 3f * oneMinusT * oneMinusT * (p1 - p0) +
- 6f * oneMinusT * t * (p2 - p1) +
- 3f * t * t * (p3 - p2);
- }
- }
- /*****************
- *BezierSpline.cs *
- *****************/
- using UnityEngine;
- using System.Collections;
- using System;
- public class BezierSpline : MonoBehaviour {
- public enum BezierControlPointMode {
- Free,
- Aligned,
- Mirrored
- }
- [SerializeField]
- private BezierControlPointMode[] modes;
- [SerializeField]
- private Vector3[] points;
- [SerializeField]
- private bool loop;
- public int CurveCount {
- get {
- return (points.Length - 1) / 3;
- }
- }
- public int NumPoints {
- get {
- return points.Length;
- }
- }
- public int ControlPointCount {
- get {
- return points.Length;
- }
- }
- public void Reset() {
- points = new Vector3[] {
- new Vector3(1f, 0f, 0f),
- new Vector3(2f, 0f, 0f),
- new Vector3(3f, 0f, 0f),
- new Vector3(4f, 0f, 0f)
- };
- modes = new BezierControlPointMode[] {
- BezierControlPointMode.Free,
- BezierControlPointMode.Free
- };
- }
- public Vector3 GetControlPoint(int index) {
- return points[index];
- }
- public void SetControlPoint(int index, Vector3 point) {
- if (index % 3 == 0) {
- Vector3 delta = point - points[index];
- if (loop) {
- if (index == 0) {
- points[1] += delta;
- points[points.Length - 2] += delta;
- points[points.Length - 1] = point;
- }
- else if (index == points.Length - 1) {
- points[0] = point;
- points[1] += delta;
- points[index - 1] += delta;
- }
- else {
- if (index > 0) {
- points[index - 1] += delta;
- }
- if (index + 1 < points.Length) {
- points[index + 1] += delta;
- }
- }
- }
- }
- points[index] = point;
- EnforceMode(index);
- }
- public Vector3 GetPoint(float t) {
- int i;
- if (t >= 1f) {
- t = 1f;
- i = points.Length - 4;
- }
- else {
- t = Mathf.Clamp01(t) * CurveCount;
- i = (int)t;
- t -= i;
- i *= 3;
- }
- return transform.TransformPoint(Bezier.GetPoint(points[i], points[i+1], points[i+2], points[i+3], t));
- }
- public Vector3 GetVelocity(float t) {
- int i;
- if (t >= 1f) {
- t = 1f;
- i = points.Length - 4;
- }
- else {
- t = Mathf.Clamp01(t) * CurveCount;
- i = (int)t;
- t -= i;
- i *= 3;
- }
- return transform.TransformPoint(Bezier.GetFirstDerivative(points[i], points[i+1], points[i+2], points[i+3], t)) - transform.position;
- }
- public Vector3 GetDirection(float t) {
- return GetVelocity(t).normalized;
- }
- public void AddCurve() {
- Vector3 point = points[points.Length - 1];
- Array.Resize(ref points, points.Length + 3);
- for (int i = 3; i > 0; --i) {
- point.x += 1f;
- points[points.Length - i] = point;
- }
- Array.Resize(ref modes, modes.Length + 1);
- modes[modes.Length - 1] = modes[modes.Length - 2];
- EnforceMode(points.Length - 4);
- if (loop) {
- points[points.Length - 1] = points[0];
- modes[modes.Length - 1] = modes[0];
- EnforceMode(0);
- }
- }
- public void RemoveCurve() {
- Array.Resize(ref points, points.Length - 3);
- Array.Resize(ref modes, modes.Length - 1);
- }
- public BezierControlPointMode GetControlPointMode(int index) {
- return modes[(index + 1) / 3];
- }
- public void SetControlPointMode(int index, BezierControlPointMode mode) {
- int modeIndex = (index + 1) / 3;
- modes[modeIndex] = mode;
- if (loop) {
- if (modeIndex == 0) {
- modes[modes.Length - 1] = mode;
- }
- else if (modeIndex == modes.Length - 1) {
- modes[0] = mode;
- }
- }
- EnforceMode(index);
- }
- private void EnforceMode(int index) {
- int modeIndex = (index + 1) / 3;
- BezierControlPointMode mode = modes[modeIndex];
- if (mode == BezierControlPointMode.Free || !loop && (modeIndex == 0 || modeIndex == modes.Length - 1)) {
- return;
- }
- int middleIndex = modeIndex * 3;
- int fixedIndex, enforcedIndex;
- if (index <= middleIndex) {
- fixedIndex = middleIndex - 1;
- if (fixedIndex < 0) {
- fixedIndex = points.Length - 2;
- }
- enforcedIndex = middleIndex + 1;
- if (enforcedIndex >= points.Length) {
- enforcedIndex = 1;
- }
- }
- else {
- fixedIndex = middleIndex + 1;
- if (fixedIndex >= points.Length) {
- fixedIndex = 1;
- }
- enforcedIndex = middleIndex - 1;
- if (enforcedIndex < 0) {
- enforcedIndex = points.Length - 2;
- }
- }
- Vector3 middle = points[middleIndex];
- Vector3 enforcedTangent = middle - points[fixedIndex];
- if (mode == BezierControlPointMode.Aligned) {
- enforcedTangent = enforcedTangent.normalized * Vector3.Distance(middle, points[enforcedIndex]);
- }
- points[enforcedIndex] = middle + enforcedTangent;
- }
- public bool Loop {
- get {
- return loop;
- }
- set {
- loop = value;
- if (value == true) {
- modes[modes.Length - 1] = modes[0];
- SetControlPoint(0, points[0]);
- }
- }
- }
- }
- /***************************
- * BezierSplineInspector.cs *
- ***************************/
- using UnityEngine;
- using UnityEditor;
- using System.Collections;
- [CustomEditor(typeof(BezierSpline))]
- public class BezierSplineInspector : Editor {
- private static Color[] modeColors = {
- Color.white,
- Color.yellow,
- Color.cyan
- };
- private BezierSpline spline;
- private Transform handleTransform;
- private Quaternion handleRotation;
- private const int lineSteps = 10;
- private const float directionScale = 0.5f;
- private const int stepsPerCurve = 10;
- private const float handleSize = 0.04f;
- private const float pickSize = 0.06f;
- private int selectedIndex = -1;
- public override void OnInspectorGUI() {
- spline = target as BezierSpline;
- EditorGUI.BeginChangeCheck();
- bool loop = EditorGUILayout.Toggle("Loop", spline.Loop);
- if (EditorGUI.EndChangeCheck()) {
- Undo.RecordObject(spline, "Toggle Loop");
- EditorUtility.SetDirty(spline);
- spline.Loop = loop;
- }
- if (selectedIndex >= 0 && selectedIndex < spline.ControlPointCount) {
- DrawSelectedPointInspector();
- }
- if (GUILayout.Button("Add Curve")) {
- Undo.RecordObject(spline, "Add Curve");
- spline.AddCurve();
- EditorUtility.SetDirty(spline);
- }
- if (GUILayout.Button("Remove Curve")) {
- if (spline.CurveCount > 1) {
- Undo.RecordObject(spline, "Remove Curve");
- spline.RemoveCurve();
- EditorUtility.SetDirty(spline);
- }
- }
- }
- private void DrawSelectedPointInspector() {
- GUILayout.Label("Selected Point");
- EditorGUI.BeginChangeCheck();
- Vector3 point = EditorGUILayout.Vector3Field("Position", spline.GetControlPoint(selectedIndex));
- if (EditorGUI.EndChangeCheck()) {
- Undo.RecordObject(spline, "Move Point");
- EditorUtility.SetDirty(spline);
- spline.SetControlPoint(selectedIndex, point);
- }
- EditorGUI.BeginChangeCheck();
- BezierSpline.BezierControlPointMode mode = (BezierSpline.BezierControlPointMode)EditorGUILayout.EnumPopup("Mode", spline.GetControlPointMode(selectedIndex));
- if (EditorGUI.EndChangeCheck()) {
- Undo.RecordObject(spline, "Change Point Mode");
- spline.SetControlPointMode(selectedIndex, mode);
- EditorUtility.SetDirty(spline);
- }
- }
- private void OnSceneGUI() {
- spline = target as BezierSpline;
- handleTransform = spline.transform;
- handleRotation = Tools.pivotRotation == PivotRotation.Local ? handleTransform.rotation : Quaternion.identity;
- Vector3 p0 = ShowPoint(0);
- for (int i = 1; i < spline.ControlPointCount; i += 3) {
- Vector3 p1 = ShowPoint(i);
- Vector3 p2 = ShowPoint(i + 1);
- Vector3 p3 = ShowPoint(i + 2);
- Handles.color = Color.grey;
- Handles.DrawLine(p0, p1);
- Handles.DrawLine(p2, p3);
- Handles.DrawBezier(p0, p3, p1, p2, Color.white, null, 2f);
- p0 = p3;
- }
- ShowDirections();
- }
- private Vector3 ShowPoint(int index) {
- Vector3 point = handleTransform.TransformPoint(spline.GetControlPoint(index));
- float size = HandleUtility.GetHandleSize(point);
- if (index == 0) {
- size *= 2f;
- }
- Handles.color = modeColors[(int)spline.GetControlPointMode(index)];
- if (Handles.Button(point, handleRotation, size * handleSize, size * pickSize, Handles.DotCap)) {
- selectedIndex = index;
- Repaint();
- }
- if (selectedIndex == index) {
- EditorGUI.BeginChangeCheck();
- point = Handles.DoPositionHandle(point, handleRotation);
- if (EditorGUI.EndChangeCheck()) {
- Undo.RecordObject(spline, "Move Point");
- EditorUtility.SetDirty(spline);
- spline.SetControlPoint(index, handleTransform.InverseTransformPoint(point));
- }
- }
- return point;
- }
- private void ShowDirections() {
- Handles.color = Color.green;
- Vector3 point = spline.GetPoint(0f);
- Handles.DrawLine(point, point + spline.GetDirection(0f) * directionScale);
- int steps = stepsPerCurve * spline.CurveCount;
- for (int i = 1; i <= steps; ++i) {
- point = spline.GetPoint(i / (float)steps);
- Handles.DrawLine(point, point + spline.GetDirection(i / (float)steps) * directionScale);
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment