博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Unity曲线编辑器和bezier曲线插值
阅读量:6419 次
发布时间:2019-06-23

本文共 11690 字,大约阅读时间需要 38 分钟。

hot3.png

 在上一篇的基础上扩展,

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

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

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

103318_SJeb_1391394.png

 

103333_WZCx_1391394.png

 

103342_UMTb_1391394.png

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.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
(); 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
(); 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
GetBezierPoints(List
pathToCurve, int interpolations) { List
tempPoints; List
curvedPoints; int pointsLength = 0; int curvedLength = 0; if (interpolations < 1) interpolations = 1; pointsLength = pathToCurve.Count; curvedLength = (pointsLength * Mathf.RoundToInt(interpolations)) - 1; curvedPoints = new List
(curvedLength); float t = 0.0f; for (int pointInTimeOnCurve = 0; pointInTimeOnCurve < curvedLength + 1; pointInTimeOnCurve++) { t = Mathf.InverseLerp(0, curvedLength, pointInTimeOnCurve); tempPoints = new List
(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
(); 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
(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}

 

转载于:https://my.oschina.net/kkkkkkkkkkkkk/blog/1511638

你可能感兴趣的文章
VC中使用XMLRPC提供接口(XMLPRC++)
查看>>
实战:EFS加密文件夹的过程
查看>>
CrazyWing:Python自动化运维开发实战 十三、Python文件I/O
查看>>
引导过程和服务控制
查看>>
Linux下网络相关属性配置
查看>>
分布式文件系统--MogileFS
查看>>
XP远程桌面连接Windows Server 2008 r2(网络级别身份验证NLA)
查看>>
4、【华为HCIE-Storage】--RAID性能指标及划分
查看>>
GDB常用命令
查看>>
U3D架构系列之- FSM有限状态机设计六(总结篇)
查看>>
关于php面向对象的一个坑爹的地方
查看>>
storm的搭建(单机版)
查看>>
Oracle 10g的卸载
查看>>
griedview setOnItemLongClickListener 无效
查看>>
pyqt在控件上创建图片
查看>>
邮件服务器被***根源及解决方案
查看>>
Linux IO实时监控iostat命令详解
查看>>
企业软件仓库部署及应用案例(基于CentOS 6的YUM源)
查看>>
探寻路径
查看>>
微访谈活动-企业微博2.0与数据微博营销(转)
查看>>