文档章节

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

梦想游戏人
 梦想游戏人
发布于 2017/08/17 10:34
字数 1309
阅读 146
收藏 0
点赞 0
评论 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
}

 

© 著作权归作者所有

共有 人打赏支持
梦想游戏人
粉丝 34
博文 402
码字总数 115594
作品 0
成都
Unity2018新功能抢鲜 | 粒子系统改进

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

zhenghongzhi6 ⋅ 04/17 ⋅ 0

利用unity和steamVR完成场景漫游(四) 利用VRTK实现激光指针

简单激光指针(VRTK_ SimplePointer) 简单指针(Simple Pointer)脚本从控制器尾部发出一个有色光束来模拟激光束。这在场景中指向对象很有用,它能判断所指向的对象以及对象距控制器发出光束...

carotadream ⋅ 04/22 ⋅ 0

TWaver3D直线、曲线、曲面的绘制

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

MonoLog ⋅ 2017/08/09 ⋅ 0

Unity3D 游戏引擎之游戏对象的访问绘制线与绘制面详解(十七)

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

彭博 ⋅ 2012/03/09 ⋅ 0

如何把UGUI当做一个插件使用(删除Unity中的UGUI,导入UGUI源码进入项目)

最近闲着没事,一直也都知道UGUI是开源的,所以就想着把UGUI的源代码放到Unity里面,看一看能不能用,经过一番调试,终于弄好了,有兴趣的同学可以看一下,欢迎交流沟通。 欲练神功,必先自宫...

qq826364410 ⋅ 05/09 ⋅ 0

3D 引擎 Unity 2018.1 正式发布,增添 330 余项改进

流行的游戏开发引擎 Unity 近期获得了重大更新,带来了一系列很酷且惊人的新功能。新版 Unity 2018.1 于 2018 年 5 月 2 日发布,旨在让游戏开发者的生活变得更加轻松,并帮助他们快速制作出...

局长 ⋅ 05/07 ⋅ 6

Unity-UnityScript转换C#工具(js转c#)

如何使用 首先,从https://github.com/Unity-Technologies/unityscript2csharp/releases下载工具。 运行转换工具之前: 备份您的项目 请记住,如果您的UnityScripts将#pragma严格应用于它们,...

qq_21153225 ⋅ 05/09 ⋅ 0

Bezier曲线原理及实现代码(c++)

Bezier曲线原理及实现代码(c++) 2009-06-30 18:50:09| 分类: 数据结构与算法|字号 订阅 一、原理: 贝塞尔曲线于1962年,由法国工程师皮埃尔·贝塞尔(Pierre Bézier)所广泛发表,他运用...

云栖希望。 ⋅ 2017/12/04 ⋅ 0

Unity Memory 内存 官方文档笔记

本文档主要是对Unity官方教程的个人理解与总结(其实以翻译记录为主:>) 仅作为个人学习使用,不得作为商业用途,欢迎转载,并请注明出处。 文章中涉及到的操作都是基于 Unity2017.3版本 参...

cangod ⋅ 04/18 ⋅ 0

Unity网页数据交互基本原理

1. u3d是一个3D游戏引擎由于和编辑器集成在一起 所以也可以理解为一个制作/开发平台 2. u3d使用javascript C#作为核心脚本语言 来驱动整个游戏引擎 3. 平台可以发布为Exe执行文件或者打包为供...

qq_30279553 ⋅ 04/22 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

Spring Cloud构建微服务架构—创建“服务注册中心”

创建一个基础的Spring Boot工程,命名为eureka-server,并在pom.xml中引入需要的依赖内容: <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-par......

itcloud ⋅ 5分钟前 ⋅ 0

拖动

<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>event</title> <style> #box { width: 100px; height: 100px; background-color: aquamarine; position: absolute; } </style......

fyliujj ⋅ 8分钟前 ⋅ 0

es6 polyfill array

polyfill之javascript函数的兼容写法——Array篇 1. Array.isArray(obj) if (!Array.isArray) { Array.isArray = function(arg) { return Object.prototype.toString.call(arg) === '[objec......

球球 ⋅ 10分钟前 ⋅ 0

kibana启动异常

检查一下:kibana.yml 每一对key:value中,冒号之后应有空格。

增删改查1 ⋅ 12分钟前 ⋅ 0

js修改img的src属性刷新图片时的图片缓存问题

问题:上传一张图片,通过js更新src属性刷新图片使其即时显示时, 当img的src当前的url与上次地址无变化时(只更改图片,名称不变,不同图片名称相同)图片不变化(仍显示原来的图片) 但通过...

HaierBrother ⋅ 12分钟前 ⋅ 0

Mysql

1.Jdbc Url 设置allowMultiQueries为true和false mysql的批量更新是要我们主动去设置的, 就是在数据库的连接url上设置一下,加上* &allowMultiQueries=true *即可。 参数名称 参数说明 缺省...

瑟青豆 ⋅ 15分钟前 ⋅ 0

mysql导出导入表结构与数据

当我们需要进行数据迁移时,mysql自带的mysqldump会是最好的方式。 1.导出某张表的结构和数据 首先,我们应当使用服务器,打开终端,连接到所需要导出的表所在的服务器上。执行命令: mysqld...

hengbao5 ⋅ 15分钟前 ⋅ 0

世界杯也走向“比拼”大数据的时代

《日本经济新闻》6月19日报道称,俄罗斯足球世界杯已于6月14日揭开战幕。作为第21次举办的足球世界杯,如何活用大数据有可能成为决定各支球队胜负的重要因素。从对阵球队的分析到战术建议,还...

加米谷大数据 ⋅ 16分钟前 ⋅ 0

金额转为千分制,金额转中文大写

金额转关为大写 js /** 数字金额大写转换(可以处理整数,小数,负数) */ function digitUppercase(n){ if(!n) reutrn "" let fraction = ['角', '分']; let digit = ['零', '壹', '贰', '叁', ...

YXMBetter ⋅ 18分钟前 ⋅ 0

开发利器JRebel部署SpringBoot项目

不要以为年纪轻轻就跌倒了人生谷底,未来还有更大的下降空间等着你。 idea下载和安装JRebel 激活JRebel 访问https://my.jrebel.com/ 使用facebook或twitter登录 勾选 Build project automati...

郑龙飞 ⋅ 24分钟前 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部