Unity 3d曲线编辑器

这篇博客详细介绍了在Unity 3D中如何绘制曲线,包括画线、Bezier曲线和Spine B样条曲线的实现。内容涵盖线的数据类型、Bezier曲线的数学原理以及Spine B样条曲线的连续构建,同时提供了编辑器支持。

参考:https://blog.youkuaiyun.com/jxw167/article/details/77717012
https://blog.youkuaiyun.com/jxw167/article/details/77732605
https://blog.youkuaiyun.com/jxw167/article/details/77836509
https://blog.youkuaiyun.com/jxw167/article/details/77848742
https://blog.youkuaiyun.com/jxw167/article/details/77862110

画线

线的数据类型

using UnityEngine;

public class Line : MonoBehaviour {
    public Vector3 p0, p1;
}

线在编辑器中显示:由于Handles是世界空间,所以,要把point从局部空间转换到世界空间;改变位置后,再从世界空间转换到局部空间,修改point的值;记录改变、提醒保存;可以revert。
该类放在editor目录下

using UnityEditor;
using UnityEngine;

[CustomEditor(typeof(Line))]
public class LineInspector : Editor
{
    //unity自带的回调函数
    private void OnSceneGUI()
    {
        Line line = target as Line;

        Transform handleTransform = line.transform;
        Quaternion handleRotation = Tools.pivotRotation == PivotRotation.Local ?
            handleTransform.rotation : Quaternion.identity;

        //将p0从局部空间转换到世界空间
        Vector3 p0 = handleTransform.TransformPoint(line.p0); 
        Vector3 p1 = handleTransform.TransformPoint(line.p1);

        Handles.color = Color.yellow;
        Handles.DrawLine(p0, p1);

        EditorGUI.BeginChangeCheck();
        p0 = Handles.DoPositionHandle(p0, handleRotation);
        //当点改变时,才进行点的移动
        if (EditorGUI.EndChangeCheck())
        {
            //记录历史记录,我们就可以执行撤销操作了
            Undo.RecordObject(line, "Move Line");
            //再重新转换回局部空间
            line.p0 = handleTransform.InverseTransformPoint(p0);
            //unity知道线改了,会提醒保存
            EditorUtility.SetDirty(line);
        }

        EditorGUI.BeginChangeCheck();
        p1 = Handles.DoPositionHandle(p1, handleRotation);
        if (EditorGUI.EndChangeCheck())
        {
            Undo.RecordObject(line, "Move Line");
            line.p1 = handleTransform.InverseTransformPoint(p1);
            EditorUtility.SetDirty(line);
        }
    }
}

Bezier曲线

Bezier曲线来自于线性插值,线性曲线可以写为B(t) = (1 - t) P0 + t P1。二次曲线B(t) = (1 - t) ((1 - t) P0 + t P1) + t ((1 - t) P1 + t P2)更深一步。 这只是线性曲线,P0和P1被两条新的线性曲线取代。它也可以被重写为更紧凑的形式B(t) = (1 - t)2 P0 + 2 (1 - t) t P1 + t2 P2。所以我们也可以直接使用二次公式而不是三次调用Vector3.Lerp。
另外,我们的二次Beziér曲线的一阶导数是B’(t) = 2 (1 - t) (P1 - P0) + 2 t (P2 - P1)。
二阶或三阶Bezier曲线公式

using UnityEngine;

public static class Bezier
{
    public static Vector3 GetSquarePoint(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;
    }

    //B(t) = (1 - t)3 P0 + 3 (1 - t)2 t P1 + 3 (1 - t) t2 P2 + t3 P3
    public static Vector3 GetCubicPoint(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;
    }

    //B'(t) = 2 (1 - t) (P1 - P0) + 2 t (P2 - P1)。
    public static Vector3 GetSquareFirstDerivative(Vector3 p0, Vector3 p1, Vector3 p2, float t)
    {
        return 2f * (1f - t) * (p1 - p0) +
            2f * t * (p2 - p1);
    }

    public static Vector3 GetCubicFirstDerivative(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);
    }

    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 GetPoint(Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, float t)
    {
        t = Mathf.Clamp01(t);
        float oneMinusT = 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿拉平平的小屋

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值