Unity__如何在游戏中体现贝塞尔曲线

一、简介

贝塞尔曲线是最基本的曲线,一般用在计算机 图形学和 图像处理。贝塞尔曲线可以用来创建平滑的曲线的道路、 弯曲的路径就像 祖玛游戏、 弯曲型的河流等。

        一条贝塞尔曲线是由一组定义的控制点 P0到 Pn,在 n 调用它的顺序 (n = 1 为线性,2 为二次,等.)。第一个和最后一个控制点总是具有终结点的曲线。然而,中间两个控制点 (如果有的话) 一般不会位于曲线上 。

  (1)贝塞尔曲线包含两个控制点即 n = 2 称为线性的贝塞尔曲线

  (2)贝塞尔曲线包含三个控制点即 n = 3 称为二次贝塞尔曲线

  (3)贝塞尔曲线包含四个控制点即 n = 4,所以称为三次贝塞尔曲线。

   贝塞尔曲线返回点的贝塞尔函数,使用线性插值的概念作为基础。

二、公式

1.线性贝塞尔公式:(其等同于线性插值

给定点P0、P1,线性贝兹曲线只是一条两点之间的直线。这条线由下式给出:

效果图(文章中部分图片转载自CSDN):

2.二次贝塞尔公式:

二次方贝兹曲线的路径由给定点P0、P1、P2控制,这条线由下式给出:

效果图:

3.三次贝塞尔方程:

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

曲线的参数形式为:

效果图:

4.一般参数形式的贝塞尔方程:

 N阶贝兹曲线可如下推断。给定点P0、P1、…、Pn,其贝兹曲线即:

如上公式可如下递归表达: 用表示由点P0、P1、…、Pn所决定的贝兹曲线。

PS:二次贝塞尔曲线是点对点的两个线性贝塞尔曲线的线性插值,三次贝塞尔曲线是两条二次贝塞尔曲线的线性插值。

三、实现与应用

效果图:

通过调节起始点(左边的白球)、控制点(中间的白球)和结束点(右边的白球)可以获得到不同的贝塞尔曲线,然后使用LineRender组件将路径绘制出来,以方便观察。下面就是实现此功能的代码:

using UnityEngine;
using System.Collections.Generic;
[RequireComponent(typeof(LineRenderer))]
public class Bezier : MonoBehaviour
{
    public Transform[] controlPoints;
    public LineRenderer lineRenderer;
 
    private int layerOrder = 0;
    private int _segmentNum = 50;
 
 
    void Start()
    {
        if (!lineRenderer)
        {
            lineRenderer = GetComponent<LineRenderer>();
        }
        lineRenderer.sortingLayerID = layerOrder;
    }
 
    void Update()
    {
 
        DrawCurve();
 
    }
 
    void DrawCurve()
    {
            for (int i = 1; i <= _segmentNum; i++)
            {
                float t = i / (float)_segmentNum;
                int nodeIndex = 0;
                Vector3 pixel = CalculateCubicBezierPoint(t, controlPoints[nodeIndex].position,
                    controlPoints[nodeIndex+1].position, controlPoints[nodeIndex+2].position);
                lineRenderer.numPositions = i;
                lineRenderer.SetPosition(i - 1, pixel);
            }
 
    }
 
    //二次贝塞尔公式:B(t) = (1-t)²P。+ 2t(1-t)P₁ + t²P₂,t∈[0,1]
    Vector3 CalculateCubicBezierPoint(float t, Vector3 p0, Vector3 p1, Vector3 p2)
    {
        float u = 1 - t;
        float tt = t * t;
        float uu = u * u;
 
        Vector3 p = uu * p0;
        p += 2 * u * t * p1;
        p += tt * p2;
 
        return p;
    }
     
}

CalculateCubicBezierPoint()函数负责根据T值计算出对应的贝塞尔曲线中的点,DrawCurve()函数通过不断的改变T值,并调用CalculateCubicBezierPoint()获得坐标点,然后通过LineRenderer将这些点绘制出来。

为了使用方便,可以将计算贝赛尔曲线的方法放到一个工具类中——BezierUtils类:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
public class BezierUtils
{
    /// <summary>
    /// 根据T值,计算贝塞尔曲线上面相对应的点
    /// 二次贝塞尔公式:B(t) = (1-t)²P。+ 2t(1-t)P₁ + t²P₂,t∈[0,1]
    /// </summary>
    /// <param name="t"></param>T值
    /// <param name="p0"></param>起始点
    /// <param name="p1"></param>控制点
    /// <param name="p2"></param>目标点
    /// <returns></returns>根据T值计算出来的贝赛尔曲线点
    private static  Vector3 CalculateCubicBezierPoint(float t, Vector3 p0, Vector3 p1, Vector3 p2)
    {
        float u = 1 - t;
        float tt = t * t;
        float uu = u * u;
 
        Vector3 p = uu * p0;
        p += 2 * u * t * p1;
        p += tt * p2;
 
        return p;
    }
 
    /// <summary>
    /// 获取存储贝塞尔曲线点的数组
    /// </summary>
    /// <param name="startPoint"></param>起始点
    /// <param name="controlPoint"></param>控制点
    /// <param name="endPoint"></param>目标点
    /// <param name="segmentNum"></param>采样点的数量
    /// <returns></returns>存储贝塞尔曲线点的数组
    public static Vector3 [] GetBeizerList(Vector3 startPoint, Vector3 controlPoint, Vector3 endPoint,int segmentNum)
    {
        Vector3 [] path = new Vector3[segmentNum];
        for (int i = 1; i <= segmentNum; i++)
        {
            float t = i / (float)segmentNum;
            Vector3 pixel = CalculateCubicBezierPoint(t, startPoint,
                controlPoint, endPoint);
            path[i - 1] = pixel;
            Debug.Log(path[i-1]);
        }
        return path;
 
    }
}

通过调用 GetBeizerList( )方法就可以获得到一个包含着计算出的贝塞尔曲线的数组,然后让Obejct沿着数组里面的路径移动就可以模拟出各种曲线运动的效果了,比如炮弹的飞行轨迹,香蕉球、弧圈球等等各种各样的曲线效果了,比如下面的效果图:

博客中贝塞尔曲线工程的开源地址:https://github.com/XINCGer/Unity3DTraining/tree/master/BezierTest

作者:马三小伙儿
出处:http://www.cnblogs.com/msxh/p/6270468.html 
请尊重别人的劳动成果,让分享成为一种美德,欢迎转载。另外,文章在表述和代码方面如有不妥之处,欢迎批评指正。留下你的脚印,欢迎评论!

猜你喜欢

转载自blog.csdn.net/Le_Sam/article/details/84894209