Показать сообщение отдельно
Старый 13.03.2012, 00:17   #15
WISHMASTER35
Бывалый
 
Аватар для WISHMASTER35
 
Регистрация: 21.12.2008
Адрес: UA
Сообщений: 878
Написано 105 полезных сообщений
(для 357 пользователей)
Ответ: Расширение редактора Unity

Написал свой вариант редактирования замкнутых кривых.
т.к. в виде массива 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 много безье создает.
Миниатюры
Нажмите на изображение для увеличения
Название: Безымянный.png
Просмотров: 1847
Размер:	132.4 Кб
ID:	16345  
(Offline)
 
Ответить с цитированием