LineRender组件绘制平滑曲线连接几个点

LineRender组件绘制平滑曲线连接几个点


项目背景

给定一组点,使用 unity3d 中的Linerender组件绘制平滑曲线连接几个点,考虑到 unity 中常用的贝塞尔曲线只经过首位两个控制点,不经过其余控制点,故采用 Catmull-Rom样条曲线

在这里插入图片描述


实现方法

创建一个空物体 Empty

在这里插入图片描述


选中Empty,添加组件 LineRender

在这里插入图片描述


创建C#脚本 SmoothCurveHandler.cs ,挂在随便一个控制点上,选择参数如图。

在这里插入图片描述


代码

SmoothCurveHandler.cs

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

public class SmoothCurveHandler : MonoBehaviour
{
    [SerializeField] LineRenderer lineRender;

    [SerializeField] List<Transform> posList;

    const int countBetween2Point = 20;

    Vector3[] curvePoints;

    void Start()
    {
        // 为当前物体添加  LineRenderer 组件。
        lineRender = gameObject.AddComponent<LineRenderer>();
        // 设置材料的属性
        //lineRender.material = new Material(Shader.Find("Particles/Additive"));
        // 设置线段的起点颜色和终点颜色
        lineRender.startColor = Color.blue;
        lineRender.endColor = Color.red;
        // 设置线段起点宽度和终点宽度
        lineRender.startWidth = 0.3f;
        lineRender.endWidth = 0.3f;

        curvePoints = new Vector3[countBetween2Point * (posList.Count - 1) + 1];

        lineRender.positionCount = curvePoints.Length;
    }

    void Update()
    {
        CalculateCurve();
        lineRender.SetPositions(curvePoints);
    }

    Vector3 firstPos, curPos, nextPos, lastPos;
    void CalculateCurve()
    {
        //依次计算相邻两点间曲线
        //由四个点确定一条曲线(当前相邻两点p1,p2,以及前后各一点p0,p3)
        for (int i = 0; i < posList.Count - 1; i++)
        {
            //特殊位置增加虚拟点
            //如果p1点是第一个点,不存在p0点,由p1,p2确定一条直线,在向量(p2p1)方向确定虚拟点p0
            if (i == 0)
                firstPos = posList[i].position * 2 - posList[i + 1].position;
            else
                firstPos = posList[i - 1].position;
            //中间点
            curPos = posList[i].position;
            nextPos = posList[i + 1].position;
            //特殊位置增加虚拟点,同上
            if (i == posList.Count - 2)
                lastPos = posList[i + 1].position * 2 - posList[i].position;
            else
                lastPos = posList[i + 2].position;

            CatmulRom(firstPos, curPos, nextPos, lastPos, ref curvePoints, countBetween2Point * i);
        }
        //加入最后一个点位
        curvePoints[curvePoints.Length - 1] = posList[posList.Count - 1].position;
    }

    //平滑过渡两点间曲线(p1,p2为端点,p0,p3是控制点)
    void CatmulRom(Vector2 p0, Vector2 p1, Vector2 p2, Vector2 p3, ref Vector3[] points, int startIndex)
    {
        //计算Catmull-Rom样条曲线
        float t0 = 0;
        float t1 = GetT(t0, p0, p1);
        float t2 = GetT(t1, p1, p2);
        float t3 = GetT(t2, p2, p3);

        float t;
        for (int i = 0; i < countBetween2Point; i++)
        {
            t = t1 + (t2 - t1) / countBetween2Point * i;

            Vector2 A1 = (t1 - t) / (t1 - t0) * p0 + (t - t0) / (t1 - t0) * p1;
            Vector2 A2 = (t2 - t) / (t2 - t1) * p1 + (t - t1) / (t2 - t1) * p2;
            Vector2 A3 = (t3 - t) / (t3 - t2) * p2 + (t - t2) / (t3 - t2) * p3;

            Vector2 B1 = (t2 - t) / (t2 - t0) * A1 + (t - t0) / (t2 - t0) * A2;
            Vector2 B2 = (t3 - t) / (t3 - t1) * A2 + (t - t1) / (t3 - t1) * A3;

            Vector2 C = (t2 - t) / (t2 - t1) * B1 + (t - t1) / (t2 - t1) * B2;

            points[startIndex + i] = C;
        }
    }

    float GetT(float t, Vector2 p0, Vector2 p1)
    {
        return t + Mathf.Pow(Mathf.Pow((p1.x - p0.x), 2) + Mathf.Pow((p1.y - p0.y), 2), 0.5f);
    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值