【Unity】运行时创建曲线(贝塞尔的运用)

这篇具有很好参考价值的文章主要介绍了【Unity】运行时创建曲线(贝塞尔的运用)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

[Unity]运行时创建线(贝塞尔的运用)

1. 实现的目标

在运行状态下创建一条可以使用贝塞尔方法实时编辑的网格曲线。

2. 原理介绍

2.1 曲线的创建

unity建立网格曲线可以参考Unity程序化网格体的实现方法。主要分为顶点,三角面,UV和法线。笔者有类似的文章unity 线绳管道纯代码创建方法_,详细的讲解了网格线的创建方法,这次的不同点在于法线的确立方法上。

2.2贝塞尔曲线点的确立

笔者有文章Unity 贝塞尔曲线的创建_描述了贝塞尔的创建方法。

3. 实现过程

3.1曲线的创建方法

线的组成原理
曲线由横截面圆和中心轴线组成。横截面的法线方向为前后两点向量差,如下图绿色线为中心轴线,A点为横截面所在点,横截面的法线方法为向量 A D ⃗ \vec{AD} AD 既向量 C B ⃗ \vec{CB} CB 的单位向量;终点和起点的法线方向为自身和前点或者后一点的向量。

【Unity】运行时创建曲线(贝塞尔的运用),Unity,unity,游戏引擎

代码源码

3.1.1 横截圆的创建
           #region 横切圆创建
           /// <summary>
           /// 得到管线横切圆
           /// </summary>
           /// <param name="Count">段数</param>
           /// <param name="R">半径</param>
           /// <returns></returns>
           Vector3[] CircularSection(int Count, float R)
           {
               Vector3[] vector3s = new Vector3[Count];
               float angle = 360 / Count;
               Vector3 vector3 = new Vector3(R, 0, 0);
               for (int i = 0; i < Count; i++)
               {
                   //根据角度得到圆的分布点
                   vector3s[i] = vector3.ToAngle(angle * i, Vector3.zero, Vector3.forward);
               }
               return vector3s;
           }
           #endregion
          

​ vector3旋转扩展方法

        /// <summary>
        /// 角度旋转
        /// </summary>
        /// <param name="vector3"></param>
        /// <param name="angle">旋转角度</param>
        /// <param name="center">旋转中心点</param>
        /// <param name="direction">旋转轴</param>
        /// <returns></returns>
        public static Vector3 ToAngle(this Vector3 vector3, float angle, Vector3 center, Vector3 direction)
        {
            Vector3 pos = center;
            Quaternion quaternion = Quaternion.AngleAxis(angle, direction);
            Matrix4x4 matrix = new Matrix4x4();
            matrix.SetTRS(pos, quaternion, Vector3.one);
            vector3 = matrix.MultiplyPoint3x4(vector3);
            return vector3;
        }
3.1.2 中心线的确立
           class LinePoint
             {
                 Vector3 location;
                 Vector3 direction;
     
                 public Vector3 Location { get => location; set => location = value; }
                 public Vector3 Direction { get => direction; set => direction = value; }
             }
             /// <summary>
             /// 中心线的确立
             /// </summary>
             /// <param name="createPoint">曲线点</param>
             /// <returns></returns>
             List<LinePoint> SetLinePoint(Vector3[] createPoint)
             {
                 List<LinePoint> pipePoints = new List<LinePoint>();
                 int length = createPoint.Length;
                 for (int i = 0; i < length; i++)
                 {
                     if (i == 0)
                     {
                         Vector3 tangent = (createPoint[i + 1] - createPoint[i]).normalized;//法线
                         AddPipePoints(createPoint[i], tangent, ref pipePoints);
                     }
                     else if (i == length - 1)
                     {
                         Vector3 tangent = (createPoint[i] - createPoint[i - 1]).normalized;//法线
                         AddPipePoints(createPoint[i], tangent, ref pipePoints);
                     }
                     else
                     {
                         Vector3 tangent = (createPoint[i+1] - createPoint[i - 1]).normalized;//法线
                         AddPipePoints(createPoint[i], tangent, ref pipePoints);
                     }
                 }
                 return pipePoints;
             }
     /// <summary>
             /// 增加中心轴线点
             /// </summary>
             /// <param name="location">位置</param>
             /// <param name="direction">法线</param>
             void AddPipePoints(Vector3 location, Vector3 direction,  ref List<LinePoint> pipePoints)
             {
                 LinePoint pipePoint = new LinePoint();
                 pipePoint.Location = location;
                 pipePoint.Direction = direction;
                 pipePoints.Add(pipePoint);
             }
3.1.3网格创建
        /// <summary>
        /// 立体网格创建
        /// </summary>
        /// <param name="createPoint">创建的点数据</param>
        /// <param name="circularCount">圆的段数</param>
        /// <param name="circularR">圆的半径</param>
        /// <returns></returns>
        public Mesh CreateLine3D(Vector3[] createPoint, int circularCount, float circularR)
        {
            //截面圆
            Vector3[] circul = CircularSection(circularCount, circularR);
            //中心线
            List<LinePoint> centreLine = SetLinePoint(createPoint);
            //网格点数据
            Vector3[] meshPoint = CreateMeshPoint(centreLine, circul);
            float uvX = Vector3.Distance(circul[0], circul[1]);
            //返回网格
            return CreatMesh(centreLine, meshPoint, circul.Length, uvX);
        }
/// <summary>
        /// 创建网格点数据
        /// </summary>
        /// <param name="linePoint"></param>
        /// <param name="circular"></param>
        /// <returns></returns>
        Vector3[] CreateMeshPoint(List<LinePoint> linePoint, Vector3[] circular)
        {
            int length = linePoint.Count;
            int circularCount = circular.Length;
            Vector3[] meshPoint = new Vector3[length * circularCount];
            for (int i = 0; i < length; i++)
            {
                for (int j = 0; j < circularCount; j++)
                {
                    meshPoint[(i * circularCount) + j] = circular[j].FromToMoveRotation(linePoint[i].Location, linePoint[i].Direction);
                }
            }
            return meshPoint;
        }
        /// <summary>
        /// 网格创建
        /// </summary>
        /// <param name="linePoints">线的轴心线组</param>
        /// <param name="meshPoint">网格点</param>
        /// <param name="count">段数</param>
        /// <param name="uvX">uv宽度</param>
        /// <returns></returns>
        Mesh CreatMesh(List<LinePoint> linePoints, Vector3[] meshPoint, int count, float uvX)
        {
            Mesh mesh = new Mesh();
            mesh.vertices = meshPoint;
            mesh.triangles = GetTriangles(linePoints.Count, count);
            mesh.uv = GetUV(linePoints, count, uvX);
            mesh.RecalculateNormals();
            mesh.RecalculateBounds();
            return mesh;
        }
   /// <param name="length">线段段数</param>
        /// <param name="count">横截面段数(也就是圆的段数)</param>
        /// <returns></returns>
        int[] GetTriangles(int length, int count)
        {
            int[] triangles = new int[(count * (length - 1)) * 6];
            int k = 0;
            if (count == 1)
            {
                for (int i = 0; i < length-1; i++)
                {
                    int a = i * 2;
                    triangles[k] = a;
                    triangles[k + 1] = a + 1;
                    triangles[k + 2] = a + 3;
                    triangles[k + 3] = a;
                    triangles[k + 4] = a + 3;
                    triangles[k + 5] = a + 2;
                    k += 6;
                }
            }
            else
            {
                for (int i = 0; i < length - 1; i++)
                {
                    
                    for (int j = 0; j < count; j++)
                    {
                        if (j == count - 1)
                        {
                           // Debug.Log("k=" + k);
                            triangles[k] = (i * count) + j;
                            triangles[k + 1] = (i * count) + 0;
                            triangles[k + 2] = ((i + 1) * count) + 0;
                            triangles[k + 3] = (i * count) + j;
                            triangles[k + 4] = ((i + 1) * count) + 0;
                            triangles[k + 5] = ((i + 1) * count) + j;
                        }
                        else
                        {
                            triangles[k] = (i * count) + j;
                            triangles[k + 1] = (i * count) + j + 1;
                            triangles[k + 2] = ((i + 1) * count) + j + 1;
                            triangles[k + 3] = (i * count) + j;
                            triangles[k + 4] = ((i + 1) * count) + j + 1;
                            triangles[k + 5] = ((i + 1) * count) + j;
                        }
                        k += 6;
                    }
                }
            }
            return triangles;
        }
  /// <summary>
        /// 创建uv
        /// </summary>
        /// <param name="linePoints"></param>
        /// <param name="count"></param>
        /// <param name="uvX"></param>
        /// <returns></returns>
        Vector2[] GetUV(List<LinePoint> linePoints,int count, float uvX)
        {
            int length = linePoints.Count;
            if (count == 1) { count = 2; }
            Vector2[] uvs = new Vector2[(count * length)];
            float lineDis = 0;
            int k = 0;
            for (int i = 0; i < length; i ++)
            {
                
                if (i != 0)
                {
                    lineDis += Vector3.Distance(linePoints[i].Location, linePoints[i - 1].Location);
                }
                for (int j = 0; j < count; j++)
                {
                    Vector2 vector2;
                    if (j % 2 != 0)
                    {
                        vector2 = new Vector2(uvX, lineDis);
                    }
                    else
                    {
                        vector2 = new Vector2(0, lineDis);
                    }
                    uvs[k] = vector2;
                    k += 1;
                }
            }
            return uvs;
        }
3.2贝塞尔曲线的建立方法

源码

 /// <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 - 4; i += 3)
        {

            var p0 = controlPoints[i];
            var p1 = controlPoints[i + 1];
            var p2 = controlPoints[i + 2];
            var p3 = controlPoints[i + 3];
            float dis = Vector3.Distance(p0, p3);
            int count = Mathf.CeilToInt(segmentsPerCurve * dis);
            if (count < segmentsPerCurve)
            {
                count = segmentsPerCurve;
            }

            for (int j = 0; j <= count; j++)
            {
                var t = j / (float)count;
                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;
    }

3.3贝塞尔曲线应用

基于上述方法实现了贝塞尔创建,保存,读取,在编辑功能。
案例下载地址

创建曲线

【Unity】运行时创建曲线(贝塞尔的运用),Unity,unity,游戏引擎

保存曲线

保存方法有两种分别是,长期保存和暂时保存。长期保存是将保存数据写入本地文件,项目重启也可以读取;暂时保存是在项目运行期间保存数据,重启后丢失。demo使用暂时保存的方法

【Unity】运行时创建曲线(贝塞尔的运用),Unity,unity,游戏引擎

读取再编辑

读取曲线后可以继续编辑当前曲线

【Unity】运行时创建曲线(贝塞尔的运用),Unity,unity,游戏引擎

曲线浏览

【Unity】运行时创建曲线(贝塞尔的运用),Unity,unity,游戏引擎文章来源地址https://www.toymoban.com/news/detail-760671.html

到了这里,关于【Unity】运行时创建曲线(贝塞尔的运用)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【游戏开发实战】Unity实现类似GitHub地球射线的效果(LineRenderer | 贝塞尔曲线)

    一、前言 嗨,大家伙,我是新发。 好久不见,这是2022年第一篇博客,今天有同学私信我,问我在 Unity 中如何实现这种地球辐射线的效果, 这一看,我就想到了 GitHub 主页的地球射线, 那么,今天就来讲讲如何实现这个效果吧~ 本文最终效果如下: 本文工程源码见文章末尾

    2024年02月06日
    浏览(96)
  • 【unity小技巧】使用贝塞尔曲线实现导弹随机攻击敌人,也可以用于平滑拾取物品

    参考原视频链接: 【视频】:https://www.bilibili.com/video/BV1aU4y1v7yM/ 注意 :本文为学习笔记记录,推荐支持原作者,去看原视频自己手敲代码理解更加深入

    2024年02月13日
    浏览(39)
  • Unity实现杀戮尖塔出牌效果( 三. 贝塞尔曲线引导箭头绘制,卡牌使用效果制作)

    1. 攻击类型卡牌 ①拖拽超过一定高度之后卡牌会移动到手牌中心位置 ②出现攻击引导箭头 (塞贝尔曲线) ③成功指向目标怪物后打出 2. 技能能力类型卡牌 ①可自由拖动 ②脱离手牌高度后打出 这里只展示此效果核心代码内容,重复代码不做赘述,上期(二.鼠标指向卡牌时,

    2024年04月12日
    浏览(64)
  • 二阶贝塞尔曲线生成弧线

    本文分享一个二阶贝塞尔曲线曲线生成弧线的算法。 示例使用openlayers实现。

    2024年01月22日
    浏览(47)
  • 【LVGL笔记】-- 贝塞尔曲线绘制

    什么是贝塞尔曲线 贝塞尔曲线 (Bézier Curve,也被称为贝塞尔多项式(Bézier Polynomial),是由一系列控制点(Control Point)所定义的一条平滑曲线。 Pierre Bézier 于1960年开始利用该曲线设计雷诺的车身线条,故命名为贝塞尔曲线。目前,贝塞尔曲线被广泛应用于图形设计、路径

    2024年02月02日
    浏览(44)
  • c++计算贝塞尔曲线(折线平滑为曲线)坐标方法

    效果可查看上一篇博文: js手动画平滑曲线,贝塞尔曲线拟合 【代码】js手动画平滑曲线,贝塞尔曲线拟合。 https://blog.csdn.net/qiufeng_xinqing/article/details/131711963?spm=1001.2014.3001.5502 代码如下:

    2024年02月16日
    浏览(37)
  • CSS动画中的贝塞尔曲线

    最近在学习CSS动画,其中动画时间函数的部分涉及到了 贝塞尔曲线 的相关知识。对于这部分知识,之前一直没有好好学习过,正好借着这个机会学习下。 首先简单介绍下贝塞尔曲线。 贝塞尔曲线(Bézier curve),又称贝兹曲线或贝济埃曲线,是应用于二维图形应用程序的数学曲

    2024年02月09日
    浏览(69)
  • 彻底搞懂贝塞尔曲线的原理

    贝塞尔曲线介绍 我们在前面讲了绘制自定义曲线,而实际开发过程还会遇到更复杂的图形绘制,比如下面的这些图形: 这时候就需要用到贝塞尔曲线了。下面是百科关于贝塞尔曲线的介绍。 贝塞尔曲线就是这样的一条曲线,它是依据四个位置任意的点坐标绘制出的一条光滑

    2024年02月20日
    浏览(43)
  • 贝塞尔曲线的python实现(简单易理解)

    贝塞尔曲线在计算机图形学中被大量使用,通常可以产生平滑的曲线。比如ps中的钢笔工具,就是利用的这种原理。由于用计算机画图大部分时间是操作鼠标来掌握线条的路径,与手绘的感觉和效果有很大的差别。即使是一位精明的画师能轻松绘出各种图形,拿到鼠标想随心

    2024年02月16日
    浏览(44)
  • Godot插值、贝塞尔曲线和Astar寻路

    线性插值是采用一次多项式上进行的插值计算,任意给定两个值A和B,那么在A和B之间的任意值可以定义为: P(t) = A * (1 - t) + B * t,0 = t = 1。 数学中用于线性拟合,游戏应用可以做出跟随效果(宠物跟随、npc跟随) 贝塞尔是插值的应用之一。贝塞尔曲线是为工业设计,是图形

    2024年04月14日
    浏览(42)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包