Unity 之 贝塞尔曲线介绍和实际使用-阿里云开发者社区

开发者社区> 陈言必行> 正文

Unity 之 贝塞尔曲线介绍和实际使用

简介: Unity 中对贝塞尔曲线的实战应用,制作可视化操作曲线工具,文末附工具源码链接~
+关注继续查看

一,什么是贝塞尔曲线

百度百科诠释:

   贝塞尔曲线(Bézier curve),又称贝兹曲线或贝济埃曲线,是应用于二维图形应用程序的数学曲线。一般的矢量图形软件通过它来精确画出曲线,贝兹曲线由线段与节点组成,节点是可拖动的支点,线段像可伸缩的皮筋,我们在绘图工具上看到的钢笔工具就是来做这种矢量曲线的。贝塞尔曲线是计算机图形学中相当重要的参数曲线,在一些比较成熟的位图软件中也有贝塞尔曲线工具,如PhotoShop等。在Flash4中还没有完整的曲线工具,而在Flash5里面已经提供出贝塞尔曲线工具。

说太多概念也没什么用,直接看公式吧:

1.线性公式:

给定点P0、P1,线性贝兹曲线只是一条两点之间的直线。这条线由下式给出:
1
一阶曲线就是根据t来的线性插值,还不明白,来看张图你应该就明白了;
1.1.1
(网图)


2.二次方公式:

二次方贝塞尔曲线的路径由给定点P0、P1、P2的函数B(t)公式推导:由(P0,P1),(P1,P2)分别求线性公式所得的结果P0‘ 和 P1‘再带入线性公式,整理所得即为二次公式:

P0,P1所求:
1.1.1
P1,P2所求:
1.2.2
P0,P1,P2二次方公式:
1.2.3
简化所得:
1.2.4


3.三次方公式

P0、P1、P2、P3四个点在平面或在三维空间中定义了三次方贝兹曲线。曲线起始于P0走向P1,并从P2的方向来到P3。一般不会经过P1或P2;这两个点只是在那里提供方向。P0和P1之间的间距,决定了曲线在转而趋进P3之前,走向P2方向的“长度有多长”。

其公式为:
1.3.1
【推导方式(二次方公式同理):(P0,P1,P2),(P1,P2,P3)分别求二次方公式,所得结果在带入线性公式,简化后即为上式】


4.一般参数公式

N阶贝塞尔曲线可如下推断。给定点P0、P1、…、Pn,其公式为:
1.4.1

贝塞尔曲线
(百度百科图)


二,在UNITY中的运用

1.公式转换为代码:

public class BezierCurveTest
{    
    /// <summary>
    /// 线性公式
    /// </summary>
    Vector3 Bezier(Vector3 p0, Vector3 p1, float t)
    {
        return (1 - t) * p0 + t * p1;
    }

    /// <summary>
    /// 二次方公式
    /// </summary>
    Vector3 Bezier(Vector3 p0, Vector3 p1, Vector3 p2, float t)
    {
        Vector3 p0p1 = (1 - t) * p0 + t * p1;
        Vector3 p1p2 = (1 - t) * p1 + t * p2;

        Vector3 result = (1 - t) * p0p1 + t * p1p2;

        return result;
    }

    /// <summary>
    /// 三次方公式
    /// </summary>
    Vector3 Bezier(Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, float t)
    {
        Vector3 result;

        Vector3 p0p1 = (1 - t) * p0 + t * p1;
        Vector3 p1p2 = (1 - t) * p1 + t * p2;
        Vector3 p2p3 = (1 - t) * p2 + t * p3;

        Vector3 p0p1p2 = (1 - t) * p0p1 + t * p1p2;
        Vector3 p1p2p3 = (1 - t) * p1p2 + t * p2p3;

        result = (1 - t) * p0p1p2 + t * p1p2p3;
        return result;
    }
}

2.举个例子

看了半天公式也转换成代码了,那么它到底用的呢?
看个例子:在Unity中绘制一条曲线

2.2.1
搭建场景如下图:
2.2.2
创建一个空物体作为父物体并挂载下面脚本,然后创建四个cube作为曲线控制点,即可在Scene视图下看到上图效果

using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

public class BezierCurveTest : MonoBehaviour
{
    // 点的半径
    public float radius = 1;
    // 曲线取点的密度
    public int densityCurve = 1000;
    /// <summary>
    /// 绘制曲线控制点 -- 此脚本的子物体
    /// </summary>
    public List<GameObject> ControlPointList = new List<GameObject>();
    /// <summary>
    /// 当前绘制曲线的所有点
    /// </summary>
    public List<Vector3> CurvePointList = new List<Vector3>();

    /// <summary>
    /// 编辑状态下子自动绘制曲线
    /// </summary>
    private void OnDrawGizmos()
    {
        // 绘制前重新添加控制点
        ControlPointList.Clear();
        foreach (Transform item in transform)
        {
            ControlPointList.Add(item.gameObject);
        }

        // Select 取每个点的position作为新的元素
        List<Vector3> controlPointPos = ControlPointList.Select(point => point.transform.position).ToList();
        // 经过三阶运算返回的需要绘制的点
        var points = GetDrawingPoints(controlPointPos, densityCurve);

        Vector3 startPos = points[0];
        CurvePointList.Clear();
        CurvePointList.Add(startPos);
        for (int i = 1; i < points.Count; i++)
        {
            if (Vector3.Distance(startPos, points[i]) >= radius)
            {
                startPos = points[i];
                CurvePointList.Add(startPos);
            }
        }

        //绘制曲线
        Gizmos.color = Color.blue;
        foreach (var item in CurvePointList)
        {
            Gizmos.DrawSphere(item, radius * 0.5f);
        }

        //绘制曲线控制点连线
        Gizmos.color = Color.red;
        for (int i = 0; i < controlPointPos.Count - 1; i++)
        {
            Gizmos.DrawLine(controlPointPos[i], controlPointPos[i + 1]);
        }

    }

    /// <summary>
    /// 获取绘制点
    /// </summary>
    /// <param name="controlPoints"></param>
    /// <param name="segmentsPerCurve"></param>
    /// <returns></returns>
    public List<Vector3> GetDrawingPoints(List<Vector3> controlPoints, int segmentsPerCurve)
    {
        List<Vector3> points = new List<Vector3>();
        // 下一段的起始点和上段终点是一个,所以是 i+=3
        for (int i = 0; i < controlPoints.Count - 3; i += 3)
        {
        
            var p0 = controlPoints[i];
            var p1 = controlPoints[i + 1];
            var p2 = controlPoints[i + 2];
            var p3 = controlPoints[i + 3];
            
            for (int j = 0; j <= segmentsPerCurve; j++)
            {
                var t = j / (float)segmentsPerCurve;
                points.Add(CalculateBezierPoint(t, p0, p1, p2, p3));
            }
        }
        return points;
    }

    // 三阶公式
    Vector3 CalculateBezierPoint(float t, Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3)
    {
        Vector3 result;

        Vector3 p0p1 = (1 - t) * p0 + t * p1;
        Vector3 p1p2 = (1 - t) * p1 + t * p2;
        Vector3 p2p3 = (1 - t) * p2 + t * p3;

        Vector3 p0p1p2 = (1 - t) * p0p1 + t * p1p2;
        Vector3 p1p2p3 = (1 - t) * p1p2 + t * p2p3;

        result = (1 - t) * p0p1p2 + t * p1p2p3;
        return result;
    }

}

PS:后续可以根据需求调整点的半径(radius )和曲线取点的密度(densityCurve )进行调整。


三,在实际项目中应用

根据上述示例,很容易想到在指定按照指定路径移动的情况下可以使用(比如:祖玛,保卫萝卜,塔防类)

下面这个Demo制作了一个可视化操作生成曲线点的工具;

实现原理:和二项中一致,我添加了一键保存配置文件扩展,它可以帮助你快速的实现关卡路径的制作,将所得的坐标点保存到本地文件,用的时候在拿出来用就可以了;

场景搭建:
3.1.1
实现效果如下:
3.1.2

Demo链接

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
Python编程:使用unittest模块进行单元测试
Python编程:使用unittest模块进行单元测试
19 0
redis介绍,redis安装,redis持久化,redis数据类型
Redis是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。从2010年3月15日起,Redis的开发工作由VMware主持。
1496 0
Unity 之 贝塞尔曲线介绍和实际使用
Unity 中对贝塞尔曲线的实战应用,制作可视化操作曲线工具,文末附工具源码链接~
51 0
[unity3d]easytouch的使用
对于移动平台上的RPG类的游戏,我们常用虚拟摇杆来控制人物角色的行走和一些行为,相信我们对它并不陌生,之前尝试了EasyTouch2.5,发现并没有最新版的3.1好用,2.5版本的对于自适应没有做的很好,而最新版的已经解决了这一问题。
924 0
第三方框架/服务/类库介绍链接汇总
1.一个很不错的引导页面构建框架 https://github.com/mamaral/Onboard 2.当前比较实用的几个ios第三方框架 http://www.
1129 0
[喵咪Redis]Redis安装与介绍
哈喽大家好啊,这次要来和大家一起来了解学习Redis的一系列技术,最终目的是搭建一个高可用redis集群自动负载灾备,那我们先从最基础的Redis的一些基本介绍以及安装来说起!
139 0
使用c#访问Access数据库时,提示找不到可安装的 ISAM
使用c#访问Access数据库时,提示找不到可安装的 ISAM,如下图: 代码如下: connectionString = "Provider=Microsoft.Jet.
1137 0
JSP第三篇【JavaBean的介绍、JSP的行为--JavaBean】
什么是javaBean JavaBean就是一个普通的java类,也称之为简单java对象--POJO(Plain Ordinary Java Object),是Java程序设计中一种设计模式,是一种基于 Java 平台的软件组件思想 JavaBean遵循着特定的写法,通常有以下的规则: 有...
974 0
微信开放平台 公众号第三方平台开发 教程一 平台介绍
原文:微信开放平台 公众号第三方平台开发 教程一 平台介绍 教程导航: 微信开放平台 公众号第三方平台开发 教程一 平台介绍 微信开放平台 公众号第三方平台开发 教程二 创建公众号第三方平台 微信开放平台 公众号第三方平台开发 教程三 一键登录授权给第三方平台  微信开放平台 公众号第三方平...
1866 0
+关注
陈言必行
一个从事Unity游戏开发攻城狮。文章皆为从零到一的入门级教程,也有很多工作中遇到的问题解析。
61
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
《2021云上架构与运维峰会演讲合集》
立即下载
《零基础CSS入门教程》
立即下载
《零基础HTML入门教程》
立即下载