Написал свой вариант редактирования замкнутых кривых.
т.к. в виде массива Vertex хранить кривую не очень удобно, то вернулся к классу Bezier)
using UnityEngine;
using System.Collections;
[System.Serializable]
public class Bezier {
public Vector3 p0;
public Vector3 p1;
public Vector3 p2;
public Vector3 p3;
public Bezier() {
}
public Bezier(Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3) {
this.p0 = p0;
this.p1 = p1;
this.p2 = p2;
this.p3 = p3;
}
public Vector3 Evaluate(float t) {
t = Mathf.Clamp01(t);
float t1 = 1 - t;
return t1 * t1 * t1 * p0 +
3 * t * t1 * t1 * p1 +
3 * t * t * t1 * p2 +
t * t * t * p3;
}
}
using UnityEngine;
using System.Collections;
public class BezierFigure : MonoBehaviour {
public Bezier[] curves = new Bezier[0];
void OnDrawGizmos() {
Gizmos.color = Color.green;
for(int i=0; i<curves.Length; i++) {
Bezier a = curves[i];
DrawBezier(a);
}
}
private void DrawBezier(Bezier bezier) {
for(int i=0; i<30; i++) {
float t1 = i/30.0f;
float t2 = (i+1)/30.0f;
Vector3 a = bezier.Evaluate(t1);
Vector3 b = bezier.Evaluate(t2);
a = transform.TransformPoint(a);
b = transform.TransformPoint(b);
Gizmos.DrawLine(a, b);
}
}
public Bezier[] GetCurves() {
return curves;
}
public void SetCurves(Bezier[] curves) {
this.curves = curves;
}
}
using UnityEditor;
using UnityEngine;
using System.Collections.Generic;
using System.Collections;
[CustomEditor(typeof(BezierFigure))]
public class BezierEditor : Editor {
public override void OnInspectorGUI() {
DrawDefaultInspector();
EditorGUIUtility.LookLikeControls();
BezierFigure figure = target as BezierFigure;
if( GUILayout.Button("Subdivide") ) {
Subdivide(figure);
Undo.RegisterUndo(target, "Bezier");
EditorUtility.SetDirty(figure);
}
}
private static void Subdivide(BezierFigure figure) {
List<Bezier> list = new List<Bezier>();
foreach( Bezier bezier in figure.GetCurves() ) {
Subdivide(list, bezier.p0, bezier.p1, bezier.p2, bezier.p3);
}
figure.SetCurves(list.ToArray());
}
private static void Subdivide(List<Bezier> list, Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3) {
Vector3 p00 = p0;
Vector3 p01 = (p0+p1)/2;
Vector3 p02 = (p0+2*p1+p2)/4;
Vector3 p03 = (p0+3*(p1+p2)+p3)/8;
Vector3 p10 = (p0+3*(p1+p2)+p3)/8;
Vector3 p11 = (p3+2*p2+p1)/4;
Vector3 p12 = (p2+p3)/2;
Vector3 p13 = p3;
Bezier b1 = new Bezier(p00, p01, p02, p03);
Bezier b2 = new Bezier(p10, p11, p12, p13);
list.Add(b1);
list.Add(b2);
}
public void OnSceneGUI() {
BezierFigure figure = target as BezierFigure;
bool changed = false;
Bezier[] curves = figure.GetCurves();
for( int i=0; i<curves.Length; i++ ) {
Bezier a = curves[i];
Bezier b = curves[(i+1)%curves.Length];
changed |= BezierMoveHandle(figure.transform, a, b);
}
if(changed) Undo.RegisterUndo(target, "Bezier");
if (GUI.changed) EditorUtility.SetDirty(target);
}
private static bool BezierMoveHandle(Transform transform, Bezier b1, Bezier b2) {
Vector3 pos = transform.TransformPoint(b1.p3);
Vector3 dir1 = transform.TransformPoint(b1.p2);
Vector3 dir2 = transform.TransformPoint(b2.p1);
bool changed = BezierMoveHandle(ref pos, ref dir1, ref dir2);
b2.p0 = b1.p3 = transform.InverseTransformPoint(pos);
b1.p2 = transform.InverseTransformPoint(dir1);
b2.p1 = transform.InverseTransformPoint(dir2);
return changed;
}
private static bool BezierMoveHandle(ref Vector3 pos, ref Vector3 dir1, ref Vector3 dir2) {
Handles.DrawLine(pos, dir1);
Handles.DrawLine(pos, dir2);
Vector3 oldPos = pos;
Vector3 oldDir1 = dir1;
Vector3 oldDir2 = dir2;
float size = HandleUtility.GetHandleSize(pos) * 0.2f;
pos = Handles.FreeMoveHandle(pos, Quaternion.identity, size, Vector3.zero, Handles.SphereCap);
dir1 = Handles.FreeMoveHandle(dir1, Quaternion.identity, size, Vector3.zero, Handles.SphereCap);
dir2 = Handles.FreeMoveHandle(dir2, Quaternion.identity, size, Vector3.zero, Handles.SphereCap);
dir1 += pos-oldPos;
dir2 += pos-oldPos;
if(oldDir1 != dir1) {
dir1 -= pos;
dir2 -= pos;
dir2 = -dir1.normalized * dir2.magnitude;
dir1 += pos;
dir2 += pos;
} else if(oldDir2 != dir2) {
dir1 -= pos;
dir2 -= pos;
dir1 = -dir2.normalized * dir1.magnitude;
dir1 += pos;
dir2 += pos;
}
return pos != oldPos ||
dir1 != oldDir1 ||
dir2 != oldDir2;
}
}
Вот только из-за сериализациикласса Bezier при попытки вручную изменить ее координаты выскакивает ошибка: Using a SerializedProperty after the object has been deleted is not possible.
UnityEditor.Editor:DrawDefaultInspector()
BezierEditor:OnInspectorGUI() (at Assets/BezierLevel/Editor/BezierEditor.cs:10)
UnityEditor.DockArea:OnGUI() не пойму что не так. И кстате, на структуру сериализация не действовала(
И с Undo не все ясно. Если быстро пару раз нажать Subdivide, то не все изменения запоминаются(
Еще просто не пойму как оно запоминает изменения только тогда, когда я перестаю перетягивать вершину. Хотя RegisterUndo вызываю все время когда перетягиваю вершину.
Еще хорошо бы добавить возможность удалять и добавлять бизье в кривой, а то Subdevide много безье создает.