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.mzph.cn/news/584261.shtml

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

相关文章

openGauss学习笔记-177 openGauss 数据库运维-逻辑复制-逻辑解码-逻辑解码概述

文章目录 openGauss学习笔记-177 openGauss 数据库运维-逻辑复制-逻辑解码-逻辑解码概述177.1 功能描述177.2 注意事项177.3 性能 openGauss学习笔记-177 openGauss 数据库运维-逻辑复制-逻辑解码-逻辑解码概述 177.1 功能描述 openGauss对数据复制能力的支持情况为&#xff…

资助26项!基金委公布一批原创探索项目资助结果!

根据《国家自然科学基金原创探索计划项目实施方案&#xff08;试行&#xff09;》要求&#xff0c;现将2023年度数理科学部资助的专项项目&#xff08;指南引导类原创探索计划项目&#xff09;相关信息予以公示&#xff1a; 国家自然科学基金委员会 数理科学部 2023年12月26日…

TypeScript 中 never 和 void 的区别

在 TypeScript 中&#xff0c;never 和 void 都是用来表示函数的返回类型或表达式的类型&#xff0c;但有着不同的含义。 void 表示函数没有返回值&#xff0c;也可以用作变量的类型&#xff0c;表示变量不接收任何值。在函数中&#xff0c;void 表示函数没有返回任何值&#…

es修改mapping映射

在Elasticsearch中&#xff0c;一旦一个字段被创建&#xff0c;它的数据类型通常是固定的&#xff0c;不能直接修改。这是因为Elasticsearch是基于倒排索引的&#xff0c;字段的数据类型在创建索引时确定&#xff0c;并且与索引的结构相关联。 然而&#xff0c;如果确实需要更…

Linux 内核学习笔记: hlist 的理解

前言 最近阅读 Linux 内核时&#xff0c;遇到了 hlist&#xff0c;这个 hlist 用起来像是普通的链表&#xff0c;但是为何使用 hlist&#xff0c;hlist 是怎么工作的&#xff1f; 相关代码 hlist_add_head(&clk->clks_node, &core->clks); /*** clk_core_link_…

开题答辩ppt模板和逻辑

PPT模板和逻辑 分三个部分 1. 立题依据、研究内容 2. 技术路线、技术创新 3. 工作基础、进度安排 Part1&#xff1a;3页 1.1 选题背景 背景1、背景2、背景3&#xff08;纵向递进式or横向并列式&#xff0c;每一个是一个新信息。&#xff09; optional&#xff1a;冲突/问…

vue3项目使用pako库解压后端返回zip数据

文章目录 前言一、pako 介绍一些特点和功能&#xff1a;简单示例 二、vue3 实战示例1.安装后引入库安装:引用用自定义hooks 抽取共用逻辑部署小插曲 前言 外部接口返回一个图片数据是经过zip压缩的&#xff0c;前端需要把这个数据处理成可以显示的图片。大概思路&#xff1a;z…

68内网安全-域横向PTHPTKPTT哈希票据传递

今天讲PTH&PTK&PTT&#xff0c; PTH(pass the hash) #利用 lm 或 ntlm 的值进行的渗透测试 PTT(pass the ticket) #利用的票据凭证 TGT 进行的渗透测试 用的Kerberos 协议 PTK(pass the key) #利用的 ekeys aes256 进行的渗透测试 lm加密算法是2003以前的老版&…

vitis HLS中实现canny算法的IP核

一、前言 canny边缘检测主要用于提取图像的边缘&#xff0c;是最常用且有效的边缘检测算法。在AMD赛灵思提供的库函数中&#xff0c;使用xf::cv::Canny和xf::cv::EdgeTracing两个函数实现canny边缘提取。本文举例说明如何在vitis HLS 2023.1中实现canny算法。 二、xf::cv::Cann…

JUC常用并发工具类

JUC常用并发工具类 1、什么是JUC? JUC 就是 java.util.concurrent 包&#xff0c;这个包俗称 JUC&#xff0c;里面都是解决并发问题的一些东西&#xff0c;该包的位置位于 java 下 面的 rt.jar 包下面。 2、4大常用并发工具类 2.1 CountDownLatch CountDownLatch&#x…

基于Java车间工时管理系统(源码+部署文档)

博主介绍&#xff1a; ✌至今服务客户已经1000、专注于Java技术领域、项目定制、技术答疑、开发工具、毕业项目实战 ✌ &#x1f345; 文末获取源码联系 &#x1f345; &#x1f447;&#x1f3fb; 精彩专栏 推荐订阅 &#x1f447;&#x1f3fb; 不然下次找不到 Java项目精品实…

《新传奇》期刊投稿论文发表

《新传奇》杂志是经国家新闻出版总署批准、面向国内外公开发行的综合性社科期刊&#xff0c;由湖北省文联主管&#xff0c;湖北今古传奇传媒集团有限公司主办&#xff0c;湖北优秀期刊。本刊旨在坚守初心、引领创新&#xff0c;展示高水平研究成果&#xff0c;支持优秀学术人才…

flink中值得监控的几个指标

背景 为了维持flink的正常运行&#xff0c;对flink的日常监控就变得很重要&#xff0c;本文我们就来看一下flink中要监控的几个重要的指标 重要的监控指标 1.算子的处理速度的指标&#xff1a;numRecordsInPerSecond/numRecordsOutPerSecond,这有助于你了解到算子的是否正在…

如何使用 NFTScan NFT API 在 Gnosis 网络上开发 Web3 应用

Gnosis Chain 是一个兼容 EVM 的区块链&#xff0c;专注于快速且低成本的交易功能&#xff0c;采用独特的双通证模型&#xff1b;xDai 是一种用于交易、支付和手续费的稳定币&#xff0c;权益证明&#xff08;PoS&#xff09;保护将由 GNO 通过共识层 Gnosis Beacon Chain 提供…

【JVM】虚拟机的组成+字节码文件组成+类的生命周期

什么是JVM&#xff1f; JVM 本质上是一个运行在计算机上的程序&#xff0c;他的职责是运行Java字节码文件。 JVM的功能 1.解释和运行&#xff1a;对字节码文件中的指令实时的解释成机器码让计算机执行。 2.内存管理&#xff1a;自动为对象、方法等分配内存&#xff0c;自动…

【C++干货铺】STL中set和map的介绍和使用

个人主页点击直达&#xff1a;小白不是程序媛 C系列专栏&#xff1a;C干货铺 代码仓库&#xff1a;Gitee 目录 序列式容器 关联式容器 键值对 树形结构的关联式容器 set set的介绍 set的使用 set的模板参数列表 set的构造 ​编辑 set的容量 set的删除和查找 mult…

web等保评测需要实机查看的操作系统、服务器、数据库和应用部分

“等保测评”全称是信息安全等级保护测评。是经公安部认证的具有资质的测评机构&#xff0c;依据国家信息安全等级保护规范规定&#xff0c;受有关单位委托&#xff0c;按照有关管理规范和技术标准&#xff0c;对信息系统安全等级保护状况进行检测评估的活动。 本文陆续将遇到的…

C#中的垃圾回收(简单理解)

在C#中&#xff0c;当一个对象称为垃圾后任会占用内存空间&#xff0c;时间一长&#xff0c;就会导致内容空间的不足。为了清除这些无用的垃圾对象&#xff0c;释放一定的内容空间&#xff0c;C#中引用了垃圾回收机制。在这种机制下&#xff0c;程序员不需要过多关心垃圾对象回…

2023“SEED”第四届江苏大数据--新能源赛道 复赛Btop2总结

第一名是真的强&#xff01;基本都是第一&#xff0c;难以撼动。 昨天新能源赛道终于落下了帷幕&#xff0c;真的不是一般的卷。最后的排名都到了0.0几分的差距。跟队友很辛运复赛B榜单目前进入top3的行列&#xff0c;下面简单总结一下赛事过程。 初赛按照天级别预测未来一周各…