Unity 之 贝塞尔曲线介绍和实际使用
发布日期:2021-06-29 19:10:08 浏览次数:3 分类:技术文章

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

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{
/// /// 线性公式 /// Vector3 Bezier(Vector3 p0, Vector3 p1, float t) {
return (1 - t) * p0 + t * p1; } /// /// 二次方公式 /// 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; } /// /// 三次方公式 /// 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; /// /// 绘制曲线控制点 -- 此脚本的子物体 /// public List
ControlPointList = new List
(); ///
/// 当前绘制曲线的所有点 /// public List
CurvePointList = new List
(); ///
/// 编辑状态下子自动绘制曲线 /// private void OnDrawGizmos() {
// 绘制前重新添加控制点 ControlPointList.Clear(); foreach (Transform item in transform) {
ControlPointList.Add(item.gameObject); } // Select 取每个点的position作为新的元素 List
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]); } } ///
/// 获取绘制点 /// ///
///
///
public List
GetDrawingPoints(List
controlPoints, int segmentsPerCurve) { List
points = new List
(); // 下一段的起始点和上段终点是一个,所以是 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

转载地址:https://czhenya.blog.csdn.net/article/details/111994712 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:程序人生 -- 致已经逝去2020
下一篇:C# 之 概率随机数

发表评论

最新留言

关注你微信了!
[***.104.42.241]2024年04月05日 22时48分35秒