曲线间平滑计算方法和一个Spline的实现

本文探讨了曲线平滑过渡的几种方法,包括2.5点线性平滑、三阶Bezier曲线、论文提及的算法以及Runge-Kutta和欧拉渐进法。特别介绍了M-Spline方法的实现,该方法生成的曲线过控制点并影响全局,适合特定场景。同时,文章提供了相关资源链接以供深入研究。
摘要由CSDN通过智能技术生成

Unity曲线编辑器和bezier曲线插值-----该篇是对上篇的曲线间平滑过渡问题的展开。

上面的曲线间平滑多度强烈依赖于2条二阶曲线粘合处的平滑。

1.5点线性平滑处理,大致思想是通过历史点信息 通过线性预测方法得出插值的点,该方法如果不加以校正的话,会蝴蝶效应,例如依据的点是越来越偏离真实点。图中 A B就是根据历史p0 p1 p2 一定方法(一般可以是曲率做为参考依据)计算出来

223439_Vwv1_1391394.png

2.利用三阶bezier曲线的,一个三点一线特性,大致是第一条曲线的第二个控制点和第一条曲线的终点和第二条曲线的第一个控制点,三点在一条线上的话,连接处就是平滑的,但是在实践的时候发现1个问题,虽然连接处平滑了,但是曲线 的曲率变化可能会偏差很大,导致过渡后曲率偏离过大, 也会导致抖动问题,看起来像是拐角突然变大or小。也依赖于拖动曲线的时候的让曲线间曲率变化不大。

224205_NQoX_1391394.png

如图p2 p3 p4 在同一条线上。这个特性在editor时候可以做自动微调计算,让他们在同一个线段上

 

3.一片论文提到的方法 http://www.ixueshu.com/document/720e4fbfdf8eec55318947a18e7f9386.html

4.之所以不平滑是因为他们交合处角度,位置的偏差导致,平滑计算可以针对角度和位置分别进行插值处理

5.RungeKutta 算法 可用在mspline 等曲线计算中,解决步长带来的精度的问题

6.欧拉渐进法euler,也可以实现和5一样的效果,是一阶的 RungeKutta 算法

(https://www.zhihu.com/question/34780726   赵恒的回答)

 

------------------------------------------------------------------------

M-Spline方法 的一个实现, 这种方法和bezier方法区别是,这种方法生成的曲线是过控制点的,并且每个点会影响全局生成的曲线信息,因此各自的适用情况不一样。而且比例是0-1全局的,因此一个完整的曲线不适用于过大的曲线描述,受限于float精度。。

using System;
using System.Runtime.InteropServices;
using UnityEngine;
using System.Collections;

public class MSplineScript : MonoBehaviour
{
    public static MSplineScript ins = null;

    protected Vector3[] dtbl;
    protected Vector3[] ftbl;
    public bool isMaked;
    private float length_;
    protected int lengthDiv = 8;
    public Vector3[] posTbl;
    protected float[] sectionLength;
    protected Method useMethod = Method.ImprovedEuler;
    void Awake()
    {
        ins = this;
    }
    ArrayList mpoints = new ArrayList();
    void Start()
    {
        ins = this;
        var ps = this.GetComponentsInChildren<Transform>();
        var vs = new Vector3[ps.Length];
        int i = 0;
        foreach (var p in ps)
        {
            vs[i] = p.position;
            ++i;
        }
        this.Make(vs);

        mpoints.Clear();
        var pp = this.GetComponentsInChildren<MPont>();
        foreach (var p in pp)
        {
            for (float iter = 0f; iter < 1f; iter += 0.001f)
            {
                if (Vector3.Distance(this.GetPoint(iter), p.transform.position) < 1f)
                // 注意这个1f的距离取决于 曲线的精度,如果曲线很长,那么这个1可能不够
                {
                    p.rate = iter;
                    break;
                }
            }
            mpoints.Add(p);
        }
    }
    public BezierDirection GetDirection(float rate)
    {
        for (int i = mpoints.Count - 2; i >= 0; i--)
        {
            var p = mpoints[i] as MPont;
            if (rate >= p.rate)
            {
                return p.direction;
            }
        }
        return BezierDirection.None;
    }
    protected f
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值