文档章节

Unity曲线编辑器和bezier曲线插值

梦想游戏人
 梦想游戏人
发布于 2017/08/17 10:34
字数 1309
阅读 199
收藏 0

Unity曲线编辑器和bezier曲线插值 在上一篇的基础上扩展,

还有一个类似功能的插件SWS

曲线编辑,可用于不规则路线,N个2阶bezier 替代高阶,达到曲线插值 的额性能和速度平衡

为了曲线公衡平滑可以用N个3阶的特性调节细节

 

 

BezierMgrEditor.cs


using UnityEngine;
using UnityEditor;
using System;
using System.Collections;
using System.Collections.Generic;

[CustomEditor(typeof(BezierMgr))]
public class BezierMgrEditor : Editor
{
    private SerializedObject m_Object;
    private SerializedProperty m_ShowWayPointInGame;
    private SerializedProperty m_IsTest;
    private SerializedProperty m_Id;


    //called whenever this inspector window is loaded 
    public void OnEnable()
    {
        //we create a reference to our script object by passing in the target
        m_Object = new SerializedObject(target);
        m_ShowWayPointInGame = m_Object.FindProperty("showWayPoint");
        m_IsTest = m_Object.FindProperty("isWayPointTest");
        m_Id = m_Object.FindProperty("id");

    }

    //called whenever the inspector gui gets rendered
    public override void OnInspectorGUI()
    {
        //this pulls the relative variables from unity runtime and stores them in the object
        m_Object.Update();

        this.RenameAll();

        GUILayout.BeginHorizontal();
        GUILayout.Label("--------------游戏设置--------------");
        GUILayout.EndHorizontal();
        this.m_Id.intValue = EditorGUILayout.IntField("该路点id:", m_Id.intValue, GUILayout.Width(300.0f));

        this.m_ShowWayPointInGame.boolValue = EditorGUILayout.Toggle("游戏中显示路点", m_ShowWayPointInGame.boolValue, GUILayout.Width(300.0f));

        this.m_IsTest.boolValue = EditorGUILayout.Toggle("开启路点测试", m_IsTest.boolValue, GUILayout.Width(300.0f));

        //waypoint index header
        GUILayout.Label("Bezier Points: ", EditorStyles.boldLabel);
        GUILayout.BeginHorizontal();

        if (GUILayout.Button("add"))
        {
            AddPoint();
        }
        if (GUILayout.Button("remove"))
        {
            RemovePoint();
        }
        if (GUILayout.Button("remove all"))
        {
            this.RemoveAllPoints();
        }

        GUILayout.EndHorizontal();

        GUILayout.BeginHorizontal();
        GUILayout.Label("---------------------------------");
        GUILayout.EndHorizontal();

        if (points.Count % 3 != 0)
        {
            GUILayout.BeginHorizontal();
            GUILayout.Label("Error:当前路点不为3的整数倍");
            GUILayout.EndHorizontal();
        }

        GUILayout.BeginHorizontal();
        GUILayout.Label("----------信---息----------");
        GUILayout.EndHorizontal();

        GUILayout.BeginHorizontal();
        GUILayout.Label("当前二阶Bezier曲线数量:" + points.Count / 3);
        GUILayout.EndHorizontal();


        for (int i = 0; i < 3; i++)
        {
            GUILayout.BeginHorizontal();
            //indicate each array slot with index number in front of it
            //create an object field for every waypoint
            // EditorGUILayout.ObjectField(waypoints[i], typeof(Transform), true);

            GUILayout.EndHorizontal();
        }

        //we push our modified variables back to our serialized object
        m_Object.ApplyModifiedProperties();
    }

    ArrayList points = new ArrayList();
    public void AddPoint()
    {
        this.RenameAll();
        int count = 3 - points.Count % 3;

        for (int j = 0; j < count; j++)
        {
            GameObject p = GameObject.Instantiate<GameObject>(GameObject.Find("__BezierTemplatePoint"));

            if (points.Count > 0)
            {
                p.transform.position = (points[points.Count - 1] as GameObject).transform.position + Vector3.left * 10.0f;
            }
            points.Add(p);
            p.name = "BezierPoint " + (points.Count);
            p.transform.SetParent((m_Object.targetObject as BezierMgr).gameObject.transform);
            //   p.transform.SetSiblingIndex(1);
            this.RenameAll();
        }
    }
    void SyncAll()
    {
        this.RenameAll();
    }
    private void RenameAll()
    {
        //先删除不在记录中的点
        var objj = new SerializedObject(target);
        var parent = (objj.targetObject as BezierMgr).gameObject;
        var pp = parent.GetComponentsInChildren<Transform>();

        ArrayList real = new ArrayList();
        for (int i = 1; i < pp.Length; i++)
        {
            Transform tr = pp[i] as Transform;
            real.Add(tr.gameObject);
        }
        // rename all
        int idx = 0;
        bool swap = (real.Count) != points.Count && points.Count != 0; //只有不足3的倍数时 才交换,因为可能会删除某个点来作为

        points.Clear();
        foreach (GameObject obj in real)
        {
            points.Add(obj);
            string point_name_tag = "";

            const string Name_Tag_Head = "_Head";
            const string Name_Tag_Mid = "_Mid";
            const string Name_Tag_End = "_End";

            if (idx % 3 == 0)
            {
                point_name_tag = Name_Tag_Head;
            }
            else if (idx % 3 == 1)
            {
                point_name_tag = Name_Tag_Mid;
            }
            else
            {
                point_name_tag = Name_Tag_End;
            }
            string newname = "BezierPoint Rename " + idx;
            Transform oldObj = parent.transform.Find(newname + Name_Tag_Head);
            if (oldObj == null)
            {
                oldObj = parent.transform.Find(newname + Name_Tag_Mid);
            }
            if (oldObj == null)
            {
                oldObj = parent.transform.Find(newname + Name_Tag_End);
            }
            if (oldObj != null && swap)
            {//replace new position to old position avoid miss info
                obj.transform.position = oldObj.position;
            }
            obj.name = newname + point_name_tag;
            ++idx;
        }
    }
    bool HasObject(GameObject obj)
    {
        foreach (GameObject ob in points)
        {
            if (ob == obj) return true;
        }
        return false;
    }
    public void RemovePoint()
    {
        this.RenameAll();
        if (points.Count <= 0) return;
        int offset = 1;
        if (points.Count % 3 == 0) offset = 3;
        for (int i = 0; i < offset; i++)
        {
            GameObject p = points[points.Count - 1] as GameObject;
            GameObject.DestroyImmediate(p);
            points.Remove(p);
        }

        this.RenameAll();
    }
    public void RemoveAllPoints()
    {
        var parent = (this.m_Object.targetObject as BezierMgr).gameObject;
        var pp = parent.GetComponentsInChildren<Transform>();

        ArrayList real = new ArrayList();
        for (int i = 1; i < pp.Length; i++)
        {
            Transform tr = pp[i] as Transform;
            GameObject.DestroyImmediate(tr.gameObject);
        }
        points.Clear();
    }

}

 

 

BezierMgr.cs

/*
* Author:  caoshanshan
* Email:   me@dreamyouxi.com

 */
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

// 2次 贝塞尔 曲线管理器,用于拼接多个低阶 组合成平滑路径,
public class BezierMgr : MonoBehaviour
{
    [Header("生成可显示路点否")]
    [SerializeField]
    public bool showWayPoint = true;

    [Header("显示路点的精度")]
    [SerializeField]
    public float tolerance = 0.001f;

    [Header("显示路点的缩放")]
    [SerializeField]
    public float scale = 0.1f;
    [Header("开启路点测试后,汽车前进速度不会变化,只是测试路径平滑度使用")]
    [SerializeField]
    public bool isWayPointTest = true;

    public int id = 0;//改路点id 一个赛道允许多个路点,用id表示
    [HideInInspector]
    public static BezierMgr ins;
    public BezierMgr()
    {
        ins = this;
    }

    private int CURRENT_INDEX = 0;
    public Bezier3 GetNextBezier()
    {
        if (bezier_queue.Count <= 0)
        {
            this.Awake();
        }
        if (CURRENT_INDEX >= bezier_queue.Count)
        {
            CURRENT_INDEX = 0; // for loop
        }
        int index = CURRENT_INDEX;
        CURRENT_INDEX++;
        var b = bezier_queue[index] as Bezier3;
        return b;
    }

    // n阶段 bezier points
    public static List<Vector3> GetBezierPoints(List<Vector3> pathToCurve, int interpolations)
    {
        List<Vector3> tempPoints;
        List<Vector3> curvedPoints;
        int pointsLength = 0;
        int curvedLength = 0;

        if (interpolations < 1)
            interpolations = 1;

        pointsLength = pathToCurve.Count;
        curvedLength = (pointsLength * Mathf.RoundToInt(interpolations)) - 1;
        curvedPoints = new List<Vector3>(curvedLength);

        float t = 0.0f;
        for (int pointInTimeOnCurve = 0; pointInTimeOnCurve < curvedLength + 1; pointInTimeOnCurve++)
        {
            t = Mathf.InverseLerp(0, curvedLength, pointInTimeOnCurve);
            tempPoints = new List<Vector3>(pathToCurve);
            for (int j = pointsLength - 1; j > 0; j--)
            {
                for (int i = 0; i < j; i++)
                {
                    tempPoints[i] = (1 - t) * tempPoints[i] + t * tempPoints[i + 1];
                }
            }
            curvedPoints.Add(tempPoints[0]);
        }

        return curvedPoints;
    }
    public void Init()
    {
        bezier_queue.Clear();
        foreach (GameObject obj in show_queue)
        {
            GameObject.DestroyImmediate(obj);
        }
        show_queue.Clear();
        CURRENT_INDEX = 0;
    }
    ArrayList show_queue = new ArrayList();
    ArrayList bezier_queue = new ArrayList();
    void Awake()
    {
        this.Init();
        this.bezier_queue = this.GetBezierQueue();
    }

    bool hasShow = false;
    ArrayList GetBezierQueue(bool editorMode = false)
    {
        var points = this.GetComponentsInChildren<Transform>();
        ArrayList ret = new ArrayList();
        ArrayList bezier_points = new ArrayList();
        int i = 0;
        foreach (Transform point in points)
        {
            if (i != 0 && editorMode == false)
            {
                //  point.gameObject.SetActive(false);
            }
            bezier_points.Add(point.position);
            i++;
        }
        i--;
        bezier_points.RemoveAt(0);
        if (i % 3 != 0 && editorMode == false)
        {
            Debug.LogError("error of number of way point   " + bezier_points.Count);
        }
        for (int ii = 0; ii < bezier_points.Count; ii += 3)
        {
            //根据路点 生成 2阶bezier 集合
            Vector3 point = (Vector3)bezier_points[ii];
            var bezier = new Bezier3();
            bezier.id = ii / 3;
            if (editorMode)
            {
                try
                {
                    bezier.p0 = (Vector3)bezier_points[ii];
                    bezier.p1 = (Vector3)bezier_points[ii + 1];
                    bezier.p2 = (Vector3)bezier_points[ii + 2];
                    ret.Add(bezier);
                }
                catch (System.Exception e)
                {

                }
            }
            else
            {
                bezier.p0 = (Vector3)bezier_points[ii];
                bezier.p1 = (Vector3)bezier_points[ii + 1];
                bezier.p2 = (Vector3)bezier_points[ii + 2];
                ret.Add(bezier);
            }
        }

        if (editorMode == false && showWayPoint && hasShow == false)
        {
            this.bezier_queue = ret;
            GameObject cube = GameObject.Find("__WayPointShowCube");
            GameObject p = GameObject.Find("__DrawShowPoints");
            if (Application.isPlaying)
            {
                hasShow = true;
                foreach (Bezier3 be in bezier_queue)
                {
                    Vector3 p0 = be.p0;
                    Vector3 p1 = be.p1;
                    Vector3 p2 = be.p2;
                    for (float time = 0f; time < 1.0f; time += tolerance)
                    {
                        float t = time;
                        Vector3 pos = be.GetPoint(t);
                        var obj = GameObject.Instantiate<GameObject>(cube, p.transform);
                        obj.transform.position = pos;
                        obj.name = "clone";
                        obj.transform.localScale = new Vector3(scale, scale, scale);

                        show_queue.Add(obj);
                    }
                }
            }
        }
        return ret;
    }
    void Start()
    {

    }

    void Update()
    {

    }

    void OnDrawGizmos()
    {
        ArrayList bezier_queue = this.GetBezierQueue(true); ;
        ArrayList pointss = new ArrayList();
        foreach (Bezier3 be in bezier_queue)
        {
            for (float time = 0f; time < 1.0f; time += 0.001f)
            {
                float t = time;
                Vector3 pos = be.GetPoint(t);
                pointss.Add(pos);
            }
        }
        for (int ii = 0; ii < pointss.Count - 3; ii += 2)
        {
            Gizmos.DrawLine((Vector3)(pointss[ii]), (Vector3)(pointss[ii + 1]));
        }
    }

}

 

Bezier3.cs

/*
* Author:  caoshanshan
* Email:   me@dreamyouxi.com

 */
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

//2次贝塞尔曲线
//为了计算性能和精度 暂不用高阶生成,用多个2阶 实时计算 拼接出完整赛道
// 额外的工作是 每个2阶的粘合处平稳过渡 
public class Bezier3
{
    public Vector3 GetPoint(float t)
    {
 
        Vector3 pos = (1 - t) * (1 - t) * p0 + 2 * t * (1 - t) * p1 + t * t * p2;
        return pos;
    }
    public Bezier3()
    {

    }
    public Vector3 p0 = Vector3.zero;
    public Vector3 p1 = Vector3.zero;
    public Vector3 p2 = Vector3.zero;

    public int id = 0;//id
}

 

© 著作权归作者所有

共有 人打赏支持
梦想游戏人
粉丝 35
博文 435
码字总数 123998
作品 0
成都
私信 提问
Unity3D 游戏引擎之游戏对象的访问绘制线与绘制面详解(十七)

Unity3D 游戏引擎之游戏对象的访问绘制线与绘制面详解 雨松MOMO原创文章如转载,请注明:转载自雨松MOMO的博客原文地址:http://blog.csdn.net/xys289187120/article/details/7002369 一眨眼学...

彭博
2012/03/09
278
0
Unity2018新功能抢鲜 | 粒子系统改进

本文首发于“洪流学堂”微信公众号。 洪流学堂,让你学Unity快人几步 Unity2018.1中对粒子系统进行了重大改进,包括功能、性能很多方面,快来看看吧! GPU网格实例化 粒子系统现在支持GPU实例...

zhenghongzhi6
04/17
0
0
【Unity3D基础概念】给初学者看的Unity概览(一):GameObject,Compoent,Time,Input,Physics

点击进入我的新博客 作者:王选易,出处:http://www.cnblogs.com/neverdie/ 欢迎转载,也请保留这段声明。如果你喜欢这篇文章,请点推荐。谢谢! Unity3D重要模块的类图 最近刚刚完成了一个...

王选易
2014/05/29
0
0
写 Shader 转场的几点思考

前言 转场效果在视频编辑工具中最为常见,在两段视频或图像之间增加一个「过渡」的效果,可以让整个过程更佳柔滑自然。常见的转场如渐变过渡、旋转、擦除等(下图为 iMovie 自带转场): 而且...

_Hahn_
09/30
0
0
TWaver3D直线、曲线、曲面的绘制

插播一则广告(长期有效) MONO哥需要在武汉招JavaScript工程师若干 要求:对前端技术(JavasScript、HTML、CSS),对可视化技术(Canvas、WebGL)有浓厚的兴趣 基础不好的可培养,基础好的可共谋...

MonoLog
2017/08/09
0
0

没有更多内容

加载失败,请刷新页面

加载更多

selenium 结合 docker 构建分布式测试环境

随着自动化测试越学越深,深深觉得有太多的东西需要总结。 1.记录下学习中遇到的坑,当做学习笔记。 2.有前人路过看到文章中比较落后的做法,请务必一定要指教。(因为是初学者视角,很多东西...

呐呐丶嘿
3分钟前
0
0
PostgreSQL 安装启动使用一条龙教程——Ubuntu 16.04

今天想尝试下 PostgreSQL,分享一下在 Ubuntu 16.04 下安装启动使用 PostgreSQL 一条龙方法。 添加第三方 apt 仓库: sudo add-apt-repository "deb http://apt.postgresql.org/pub/repos/a...

宇润
5分钟前
0
0
对于json文件的读写操作

对json文件的读操作 返回的一个列表,里面是多个字典 def read_json(self,jsonname): with open(r"./{}.json".format(jsonname),"r") as json_f: text_list = json......

鹏灬
7分钟前
0
0
Date-Time API简介

  Date-Time API简介      在Java8之前的版本中,我们处理时间类型常常使用的是java.util包下的Date类。但使用Date类却有诸多的弊端,如: java.util.Date 是非线程安全的,所有的日期...

SEOwhywhy
8分钟前
1
0
实体类生成对应的建表语句

通过实体类生成对应的建表语句 用java代码根据实体类自动生成对应的建表语句或生成某个包下的所有类的建表语句 根据实体类反射生成SQL java 根据实体对象生成 增删改的SQL语句 ModelToSQL...

miaojiangmin
11分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部