Unity 贝塞尔曲线工具获取运动轨迹

Unity 贝塞尔曲线工具获取运动轨迹

  • 一、介绍贝塞尔曲线
  • 二、Unity中贝塞尔曲线工具介绍
    • 1.创建一个空物体挂在上BezierSpline.cs脚本组件
    • 2.由上图可知刚创建出来的有两个点和两个手柄组成
    • 3.我们可修改其坐标看下效果
    • 4.这样我们就可以获得这两个点之间的指定数量的点来作为某个物体的运动轨迹
    • 5.增加点
  • 三、脚本构成如下
    • 此工具总共三个脚本构成
      • 1.放在Editor文件夹下的BezierSplineInspector.cs
      • 2.Bezier.cs
      • 3.BezierSpline.cs

一、介绍贝塞尔曲线

贝塞尔曲线是一种由四个或更多个控制点确定的光滑曲线。它是由法国数学家Pierre Bézier发明的,为计算机图形学提供了基础。贝塞尔曲线可以用来描述直线和曲线,并且可以通过调整控制点的位置来改变曲线的形状。贝塞尔曲线在计算机图形学、计算机辅助设计(CAD)和计算机动画等领域中广泛应用。

贝塞尔曲线的特点是光滑且可控制。通过调整控制点的位置和数量,可以创建各种形状的曲线,包括直线、曲线、圆弧和复杂的曲线路径。贝塞尔曲线的形状由控制点的位置和相对位置决定,控制点之间的曲线段称为贝塞尔曲线的分段。

贝塞尔曲线有多种类型,包括一次贝塞尔曲线、二次贝塞尔曲线和三次贝塞尔曲线。一次贝塞尔曲线由两个控制点确定,二次贝塞尔曲线由三个控制点确定,三次贝塞尔曲线由四个控制点确定。同类型的贝塞尔曲线具有不同的特性和应用场景。

贝塞尔曲线在计算机图形学中的应用非常广泛。它可以用来创建平滑的曲线路径、绘制复杂的图形和形状、实现动画效果等。在计算机辅助设计中,贝塞尔曲线被用来绘制曲线和曲面,用于建模和设计。在计算机动画中,贝塞尔曲线可以用来控制物体的运动轨迹和形变。

总结起来,贝塞尔曲线是一种由控制点确定的光滑曲线,它在计算机图形学、计算机辅助设计和计算机动画等领域中有广泛的应用。

二、Unity中贝塞尔曲线工具介绍

在这里插入图片描述

1.创建一个空物体挂在上BezierSpline.cs脚本组件

在这里插入图片描述

2.由上图可知刚创建出来的有两个点和两个手柄组成

3.我们可修改其坐标看下效果

在这里插入图片描述

4.这样我们就可以获得这两个点之间的指定数量的点来作为某个物体的运动轨迹

在这里插入图片描述

5.增加点

在这里插入图片描述

三、脚本构成如下

此工具总共三个脚本构成

1.放在Editor文件夹下的BezierSplineInspector.cs

using UnityEditor;
using UnityEngine;[CustomEditor(typeof(BezierSpline))]
public class BezierSplineInspector : Editor
{private const int stepsPerCurve = 10;private const float directionScale = 0.5f;private const float handleSize = 0.04f;private const float pickSize = 0.06f;private static Color[] modeColors = {Color.white,Color.yellow,Color.cyan};private BezierSpline spline;private Transform handleTransform;private Quaternion handleRotation;private int selectedIndex = -1;public override void OnInspectorGUI(){spline = target as BezierSpline;EditorGUI.BeginChangeCheck();bool loop = EditorGUILayout.Toggle("Loop", spline.Loop);if (EditorGUI.EndChangeCheck()){Undo.RecordObject(spline, "Toggle Loop");EditorUtility.SetDirty(spline);spline.Loop = loop;}if (selectedIndex >= 0 && selectedIndex < spline.ControlPointCount){DrawSelectedPointInspector();}if (GUILayout.Button("Add Curve")){Undo.RecordObject(spline, "Add Curve");spline.AddCurve();EditorUtility.SetDirty(spline);}}private void DrawSelectedPointInspector(){GUILayout.Label("Selected Point");EditorGUI.BeginChangeCheck();Vector3 point = EditorGUILayout.Vector3Field("Position", spline.GetControlPoint(selectedIndex));if (EditorGUI.EndChangeCheck()){Undo.RecordObject(spline, "Move Point");EditorUtility.SetDirty(spline);spline.SetControlPoint(selectedIndex, point);}EditorGUI.BeginChangeCheck();BezierControlPointMode mode = (BezierControlPointMode)EditorGUILayout.EnumPopup("Mode", spline.GetControlPointMode(selectedIndex));if (EditorGUI.EndChangeCheck()){Undo.RecordObject(spline, "Change Point Mode");spline.SetControlPointMode(selectedIndex, mode);EditorUtility.SetDirty(spline);}}private void OnSceneGUI(){spline = target as BezierSpline;handleTransform = spline.transform;handleRotation = Tools.pivotRotation == PivotRotation.Local ?handleTransform.rotation : Quaternion.identity;Vector3 p0 = ShowPoint(0);for (int i = 1; i < spline.ControlPointCount; i += 3){Vector3 p1 = ShowPoint(i);Vector3 p2 = ShowPoint(i + 1);Vector3 p3 = ShowPoint(i + 2);Handles.color = Color.gray;Handles.DrawLine(p0, p1);Handles.DrawLine(p2, p3);Handles.DrawBezier(p0, p3, p1, p2, Color.white, null, 2f);p0 = p3;}ShowDirections();}private void ShowDirections(){Handles.color = Color.green;Vector3 point = spline.GetPoint(0f);Handles.DrawLine(point, point + spline.GetDirection(0f) * directionScale);int steps = stepsPerCurve * spline.CurveCount;for (int i = 1; i <= steps; i++){point = spline.GetPoint(i / (float)steps);Handles.DrawLine(point, point + spline.GetDirection(i / (float)steps) * directionScale);}}private Vector3 ShowPoint(int index){Vector3 point = handleTransform.TransformPoint(spline.GetControlPoint(index));float size = HandleUtility.GetHandleSize(point);if (index == 0){size *= 2f;}Handles.color = modeColors[(int)spline.GetControlPointMode(index)];if (Handles.Button(point, handleRotation, size * handleSize, size * pickSize, Handles.DotCap)){selectedIndex = index;Repaint();}if (selectedIndex == index){EditorGUI.BeginChangeCheck();point = Handles.DoPositionHandle(point, handleRotation);if (EditorGUI.EndChangeCheck()){Undo.RecordObject(spline, "Move Point");EditorUtility.SetDirty(spline);spline.SetControlPoint(index, handleTransform.InverseTransformPoint(point));}}return point;}
}

2.Bezier.cs

using UnityEngine;public static class Bezier
{public static Vector3 GetPoint(Vector3 p0, Vector3 p1, Vector3 p2, float t){t = Mathf.Clamp01(t);float oneMinusT = 1f - t;returnoneMinusT * oneMinusT * p0 +2f * oneMinusT * t * p1 +t * t * p2;}public static Vector3 GetFirstDerivative(Vector3 p0, Vector3 p1, Vector3 p2, float t){return2f * (1f - t) * (p1 - p0) +2f * t * (p2 - p1);}public static Vector3 GetPoint(Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, float t){t = Mathf.Clamp01(t);float OneMinusT = 1f - t;returnOneMinusT * OneMinusT * OneMinusT * p0 +3f * OneMinusT * OneMinusT * t * p1 +3f * OneMinusT * t * t * p2 +t * t * t * p3;}public static Vector3 GetFirstDerivative(Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, float t){t = Mathf.Clamp01(t);float oneMinusT = 1f - t;return3f * oneMinusT * oneMinusT * (p1 - p0) +6f * oneMinusT * t * (p2 - p1) +3f * t * t * (p3 - p2);}
}

3.BezierSpline.cs

using UnityEngine;
using System;public class BezierSpline : MonoBehaviour
{[SerializeField]public Vector3[] points;[SerializeField]private BezierControlPointMode[] modes;[SerializeField]private bool loop;public bool Loop{get{return loop;}set{loop = value;if (value == true){modes[modes.Length - 1] = modes[0];SetControlPoint(0, points[0]);}}}public int ControlPointCount{get{return points.Length;}}public Vector3 GetControlPoint(int index){return points[index];}public void SetControlPoint(int index, Vector3 point){if (index % 3 == 0){Vector3 delta = point - points[index];if (loop){if (index == 0){points[1] += delta;points[points.Length - 2] += delta;points[points.Length - 1] = point;}else if (index == points.Length - 1){points[0] = point;points[1] += delta;points[index - 1] += delta;}else{points[index - 1] += delta;points[index + 1] += delta;}}else{if (index > 0){points[index - 1] += delta;}if (index + 1 < points.Length){points[index + 1] += delta;}}}points[index] = point;EnforceMode(index);}public BezierControlPointMode GetControlPointMode(int index){return modes[(index + 1) / 3];}public void SetControlPointMode(int index, BezierControlPointMode mode){int modeIndex = (index + 1) / 3;modes[modeIndex] = mode;if (loop){if (modeIndex == 0){modes[modes.Length - 1] = mode;}else if (modeIndex == modes.Length - 1){modes[0] = mode;}}EnforceMode(index);}private void EnforceMode(int index){int modeIndex = (index + 1) / 3;BezierControlPointMode mode = modes[modeIndex];if (mode == BezierControlPointMode.Free || !loop && (modeIndex == 0 || modeIndex == modes.Length - 1)){return;}int middleIndex = modeIndex * 3;int fixedIndex, enforcedIndex;if (index <= middleIndex){fixedIndex = middleIndex - 1;if (fixedIndex < 0){fixedIndex = points.Length - 2;}enforcedIndex = middleIndex + 1;if (enforcedIndex >= points.Length){enforcedIndex = 1;}}else{fixedIndex = middleIndex + 1;if (fixedIndex >= points.Length){fixedIndex = 1;}enforcedIndex = middleIndex - 1;if (enforcedIndex < 0){enforcedIndex = points.Length - 2;}}Vector3 middle = points[middleIndex];Vector3 enforcedTangent = middle - points[fixedIndex];if (mode == BezierControlPointMode.Aligned){enforcedTangent = enforcedTangent.normalized * Vector3.Distance(middle, points[enforcedIndex]);}points[enforcedIndex] = middle + enforcedTangent;}public int CurveCount{get{return (points.Length - 1) / 3;}}public Vector3 GetPoint(float t){int i;if (t >= 1f){t = 1f;i = points.Length - 4;}else{t = Mathf.Clamp01(t) * CurveCount;i = (int)t;t -= i;i *= 3;}return transform.TransformPoint(Bezier.GetPoint(points[i], points[i + 1], points[i + 2], points[i + 3], t));}public Vector3 GetVelocity(float t){int i;if (t >= 1f){t = 1f;i = points.Length - 4;}else{t = Mathf.Clamp01(t) * CurveCount;i = (int)t;t -= i;i *= 3;}return transform.TransformPoint(Bezier.GetFirstDerivative(points[i], points[i + 1], points[i + 2], points[i + 3], t)) - transform.position;}public Vector3 GetDirection(float t){return GetVelocity(t).normalized;}public void AddCurve(){Vector3 point = points[points.Length - 1];Array.Resize(ref points, points.Length + 3);point.x += 1f;points[points.Length - 3] = point;point.x += 1f;points[points.Length - 2] = point;point.x += 1f;points[points.Length - 1] = point;Array.Resize(ref modes, modes.Length + 1);modes[modes.Length - 1] = modes[modes.Length - 2];EnforceMode(points.Length - 4);if (loop){points[points.Length - 1] = points[0];modes[modes.Length - 1] = modes[0];EnforceMode(0);}}public void Reset(){points = new Vector3[] {new Vector3(1f, 0f, 0f),new Vector3(2f, 0f, 0f),new Vector3(3f, 0f, 0f),new Vector3(4f, 0f, 0f)};modes = new BezierControlPointMode[] {BezierControlPointMode.Free,BezierControlPointMode.Free};}
}public enum BezierControlPointMode
{Free,Aligned,Mirrored
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/298175.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

算法学习系列(十一):KMP算法

目录 引言一、算法概念二、题目描述三、思路讲解三、代码实现四、测试 引言 这个KMP算法就是怎么说呢&#xff0c;就是不管算法竞赛还是找工作笔试面试&#xff0c;都是非常爱问爱考的&#xff0c;其实也是因为这个算法比较难懂&#xff0c;其实就是很难&#xff0c;所以非常个…

Apache Commons CLI:构建命令行应用的利器

引言 大家好&#xff01;我是小黑&#xff0c;本文聊聊如何用Apache Commons CLI构建命令行应用。咱们都知道&#xff0c;命令行界面&#xff08;CLI&#xff09;虽然看起来不如图形界面那么花哨&#xff0c;但在许多场景下&#xff0c;它的效率和便利性是无与伦比的。特别是对…

直排轮滑教程7

单脚弧线平衡练习 1&#xff0c;下面接下来是单脚弧线平衡练习法&#xff0c;前面是双脚弧线平衡练习法。 2&#xff0c;这个动作练好了&#xff0c;今后在滑左右转弧的时候&#xff0c;就非常自如了。 3&#xff0c;需要一个平衡控制能力&#xff0c;就是单腿的滑行控制能…

【洛谷算法题】P4414-[COCI2006-2007#2] ABC【入门2分支结构】Java题解

&#x1f468;‍&#x1f4bb;博客主页&#xff1a;花无缺 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! 本文由 花无缺 原创 收录于专栏 【洛谷算法题】 文章目录 【洛谷算法题】P4414-[COCI2006-2007#2] ABC【入门2分支结构】Java题解&#x1f30f;题目描述&a…

STM32F407-14.3.10-表73具有有断路功能的互补通道OCx和OCxN的输出控制位-1x111

如上表所示&#xff0c;MOE1&#xff0c;OSSR1&#xff0c;CCxE1&#xff0c;CCxNE1时&#xff0c;OCx与OCxN对应端口的输出状态取决于OCx_REF与极性选择&#xff08;CCxP&#xff0c;CCxNP&#xff09; 死区。 -------------------------------------------------------------…

常见的Ubuntu命令30条(二)

Ubuntu命令是指在Ubuntu操作系统中用于执行各种任务和操作的命令行指令。这些命令可以用于管理系统、配置网络、安装软件、浏览文件等。Ubuntu命令通常在终端&#xff08;Terminal&#xff09;应用程序中输入并执行。 history&#xff1a;显示命令行历史记录。grep&#xff1a…

C++_const常成员作用

介绍 常成员是什么 1.常成员关键词为&#xff1a;const 2.常成员有&#xff1a;常成员变量、常成员函数、常成员对象 常成员有什么用 1.常成员变量&#xff1a;用于在程序中定义不可修改内部成员变量的函数 2.常成员函数&#xff1a;只能够访问成员变量&#xff0c;不可以修改成…

Python - 深夜数据结构与算法之 Heap Binary Heap

目录 一.引言 二.堆与二叉堆介绍 1.Heap 堆 2.Binary Heap 二叉堆 3.HeapifyUp 添加节点 4.HeapifyDown 删除节点 5.Heap 时间复杂度 6.Insert & Delete 代码实现 三.经典算法实战 1.Smallest-K [M14] 2.Sliding-Window-Max [239] 3.Ugly-Number [264] 4.Top-…

工具系列:TensorFlow决策森林_(2)排序学习Learning to Rank

文章目录 安装 TensorFlow Decision Forests导入库什么是排序模型&#xff1f;让我们训练一个排序模型使用排序模型进行预测 欢迎来到 TensorFlow决策森林&#xff08; TF-DF&#xff09;的 学习排序Learning to Rank。 在本文中&#xff0c;您将学习如何使用 TF-DF进行排序…

股市中的Santa Claus Rally (圣诞节行情)

圣诞节行情 Santa Claus Rally Santa Claus Rally 是指 12 月 25 日圣诞节前后股市的持续上涨这样一个现象。《股票交易员年鉴》的创始人 Yale Hirsch 于 1972 年创造了这个定义&#xff0c;他将当年最后五个交易日和次年前两个交易日的时间范围定义为反弹日期。 根据 CFRA Re…

Redis基础-Redis概念及常见命令

1.nosql数据库 NoSQL数据库是一种提供了非关系型数据存储的数据库系统&#xff0c;与传统的关系型数据库&#xff08;如SQL数据库&#xff09;不同。NoSQL数据库的特点是灵活性高&#xff0c;能够处理结构化、半结构化或非结构化数据。它们通常用于大数据和实时Web应用。NoSQL数…

Web Components入门不完全指北

目前流行的各类前端框架&#xff0c;不管是react, angular还是vue&#xff0c;都有一个共同点&#xff0c;那就是支持组件化开发&#xff0c;但事实上随着浏览器的发展&#xff0c;现在浏览器也原生支持组件式开发&#xff0c;本文将通过介绍Web Components 的三个主要概念&…