当前位置: 首页 > news >正文

【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 的单位向量;终点和起点的法线方向为自身和前点或者后一点的向量。

代码源码

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+=3for (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贝塞尔曲线应用

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

创建曲线

保存曲线

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

读取再编辑

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

曲线浏览

相关文章:

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

[Unity]运行时创建线&#xff08;贝塞尔的运用&#xff09; 1. 实现的目标 在运行状态下创建一条可以使用贝塞尔方法实时编辑的网格曲线。 2. 原理介绍 2.1 曲线的创建 unity建立网格曲线可以参考Unity程序化网格体的实现方法。主要分为顶点&#xff0c;三角面&#xff0c…...

基于DSP的IIR数字滤波器(论文+源码)

1.系统设计 在本次基于DSP的IIR数字低通滤波计中&#xff0c;拟以TMS320F28335来作为系统的主控制器&#xff0c;通过ADC0832模数转换芯片来对输入信号进行采集&#xff1b;通过TLC5615来将低通滤波后的信号进行输出&#xff1b;同时结合MATLAB仿真软件&#xff0c;对设计的II…...

Django(一)

1.web框架底层 1.1 网络通信 注意&#xff1a;局域网 个人一般写程序&#xff0c;想要让别人访问&#xff1a;阿里云、腾讯云。 去云平台租服务器&#xff08;含公网IP&#xff09;程序放在云服务器 先以局域网为例 我的电脑【服务端】 import socket# 1.监听本机的IP和…...

微信小程序如何利用createIntersectionObserver实现图片懒加载

微信小程序如何利用createIntersectionObserver实现图片懒加载 节点布局相交状态 API 可用于监听两个或多个组件节点在布局位置上的相交状态。这一组API常常可以用于推断某些节点是否可以被用户看见、有多大比例可以被用户看见。 节点布局相交状态 API中有一个 wx.createInter…...

七:爬虫-数据解析之正则表达式

七&#xff1a;正则表达式概述 正则表达式&#xff0c;又称规则表达式,&#xff08;Regular Expression&#xff0c;在代码中常简写为regex、regexp或RE&#xff09;&#xff0c;是一种文本模式&#xff0c;包括普通字符&#xff08;例如&#xff0c;a 到 z 之间的字母&#xf…...

云原生之深入解析亿级流量架构之服务限流思路与方法

一、限流思路 ① 熔断 系统在设计之初就把熔断措施考虑进去&#xff0c;当系统出现问题时&#xff0c;如果短时间内无法修复&#xff0c;系统要自动做出判断&#xff0c;开启熔断开关&#xff0c;拒绝流量访问&#xff0c;避免大流量对后端的过载请求。系统也应该能够动态监测…...

【Python炫酷系列】祝考研的友友们金榜题名吖(完整代码)

文章目录 环境需求完整代码详细分析系列文章环境需求 python3.11.4及以上版本PyCharm Community Edition 2023.2.5pyinstaller6.2.0(可选,这个库用于打包,使程序没有python环境也可以运行,如果想发给好朋友的话需要这个库哦~)【注】 python环境搭建请见:https://want595.…...

KL散度、CrossEntropy详解

文章目录 0. 概述1. 信息量1.1 定义1.2 性质1.3 例子2. 熵 Entropy2.1 定义2.2 公式2.3 例子3. 交叉熵 Cross Entropy3.1 定义3.2 公式3.3 例子4. KL 散度(相对熵)4.1 公式...

【算法】红黑树

一、红黑树介绍 红黑树是一种自平衡二叉查找树&#xff0c;是在计算机科学中用到的一种数据结构&#xff0c;典型的用途是实现关联数组。 红黑树是在1972年由Rudolf Bayer发明的&#xff0c;当时被称为平衡二叉B树&#xff08;symmetric binary B-trees&#xff09;。后来&am…...

2023楚慧杯 WEB方向 部分:(

1、eaaeval 查看源码能看见账号&#xff1a;username169&#xff0c;密码&#xff1a;password196提交这个用户密码可以跳转到页面/dhwiaoubfeuobgeobg.php 通过dirsearch目录爆破可以得到www.zip <?php class Flag{public $a;public $b;public function __construct(){…...

STM32 CAN多节点组网项目实操 挖坑与填坑记录2

系列文章&#xff0c;持续探索CAN多节点通讯&#xff0c; 上一篇文章链接&#xff1a; STM32 CAN多节点组网项目实操 挖坑与填坑记录-CSDN博客文章浏览阅读120次。CAN线性组网项目开发过程中遇到的数据丢包问题&#xff0c;并尝试解决的记录和推测分析。开发了一个多节点线性…...

Flink 数据类型 TypeInformation信息

Flink流应用程序处理的是以数据对象表示的事件流。所以在Flink内部&#xff0c;我么需要能够处理这些对象。它们需要被序列化和反序列化&#xff0c;以便通过网络传送它们&#xff1b;或者从状态后端、检查点和保存点读取它们。为了有效地做到这一点&#xff0c;Flink需要明确知…...

基于python的leetcode算法介绍之递归

文章目录 零 算法介绍一 简单示例 辗转相除法Leetcode例题与思路[509. 斐波那契数](https://leetcode.cn/problems/fibonacci-number/)解题思路&#xff1a;题解&#xff1a; [206. 反转链表](https://leetcode.cn/problems/reverse-linked-list/)解题思路&#xff1a;题解&…...

2023年度佳作:AIGC、AGI、GhatGPT、人工智能大语言模型的崛起与挑战

目录 前言 01 《ChatGPT 驱动软件开发》 内容简介 02 《ChatGPT原理与实战》 内容简介 03 《神经网络与深度学习》 04 《AIGC重塑教育》 内容简介 05 《通用人工智能》 目  录 前言 2023年是人工智能大语言模型大爆发的一年&#xff0c;一些概念和英文缩写也在这一…...

Axure的交互以及情形的介绍

一. 交互 1.1 交互概述 通俗来讲就是&#xff0c;谁用了什么方法做了什么事情&#xff0c;主体"谁"对应的就是axure中的元件&#xff0c;"什么方法"对应的就是交互事件&#xff0c;比如单击事件、双击事件&#xff0c;"什么事情"对应的就是交互…...

【MATLAB第84期】基于MATLAB的波形叠加极限学习机SW-ELM代理模型的sobol全局敏感性分析法应用

【MATLAB第84期】基于MATLAB的波形叠加极限学习机SW-ELM代理模型的sobol全局敏感性分析法应用 前言 跟往期sobol区别&#xff1a; 1.sobol计算依赖于验证集样本&#xff0c;无需定义变量上下限。 2.SW-ELM自带激活函数&#xff0c;计算具有phi&#xff08;x&#xff09;e^x激…...

米游社区表情包整合网站源码

源码介绍 米游社表情包整合网站源码&#xff0c;来自Github大佬的项目&#xff0c;包含米游兔123枚&#xff0c;米游社 玩家12枚&#xff0c;崩坏 星穹铁道112枚&#xff0c;绝区零218枚&#xff0c;NAP32枚&#xff0c;崩坏RPG62枚&#xff0c;崩坏3-1282枚&#xff0c;原神 …...

easyexcel调用公共导出方法导出数据

easyexcel备忘 Slf4j public class ConditionDownloadUtil {//扫描在xboot 包下所有IService 接口的子类, 每次启动服务后, 重新扫描public final static Class[] classesExtendsIService ClassUtil.scanPackageBySuper("cn.exrick.xboot", IService.class).toArra…...

C语言插入排序算法及代码

一、原理 在待排序的数组里&#xff0c;从数组的第二个数字开始&#xff0c;通过构建有序序列&#xff0c;对于未排序数据&#xff0c;在已排序序列中从后向前扫描&#xff0c;找到相应位置并插入。 二、代码部分 #include<stdio.h> #include<stdlib.h> int ma…...

2023年中国法拍房用户画像和数据分析

法拍房主要平台 法拍房主要平台有3家&#xff0c;分别是阿里、京东和北交互联平台。目前官方认定纳入网络司法拍卖的平台共有7家&#xff0c;其中阿里资产司法拍卖平台的挂拍量最大。 阿里法拍房 阿里法拍房数据显示2017年&#xff0c;全国法拍房9000套&#xff1b;2018年&a…...

Android 清除临时文件,清空缓存

python 代码&#xff1a; import os import shutil import tracebackdef delete_folder(path):if os.path.exists(path):print(f"删除文件夹: {path}")shutil.rmtree(path)print("删除完成")def delete_file(path):if os.path.exists(path):print(f"删…...

Guava限流神器:RateLimiter使用指南

1. 引言 可能有些小伙伴听到“限流”这个词就觉得头大&#xff0c;感觉像是一个既复杂又枯燥的话题。别急&#xff0c;小黑今天就要用轻松易懂的方式&#xff0c;带咱们一探RateLimiter的究竟。 想象一下&#xff0c;当你去超市排队结账时&#xff0c;如果收银台开得越多&…...

【六大排序详解】开篇 :插入排序 与 希尔排序

插入排序 与 希尔排序 六大排序之二 插入排序 与 希尔排序1 排序1.1排序的概念 2 插入排序2.1 插入排序原理2.2 排序步骤2.3 代码实现 3 希尔排序3.1 希尔排序原理3.2 排序步骤3.3 代码实现 4 时间复杂度分析 Thanks♪(&#xff65;ω&#xff65;)&#xff89;下一篇文章见&am…...

凸优化问题求解

这里写目录标题 1. 线性规划基本定理2.单纯形法2.1 转轴运算 3. 内点法3.1 线性规划的内点法 1. 线性规划基本定理 首先我们指出&#xff0c;线性规划均可等价地化成如下标准形式 { min ⁡ c T x , s . t A x b , x ⪰ 0 , \begin{align}\begin{cases}\min~c^Tx,\\\mathrm{s.…...

文件操作入门指南

目录 一、为什么使用文件 二、什么是文件 2.1 程序文件 2.2 数据文件 2.3 文件名 三、文件的打开和关闭 3.1 文件指针 3.2 文件的打开和关闭 四、文件的顺序读写 ​编辑 &#x1f33b;深入理解 “流”&#xff1a; &#x1f342;文件的顺序读写函数介绍&#xff1a; …...

Axure之交互与情节与一些实例

目录 一.交互与情节简介 二.ERP登录页到主页的跳转 三.ERP的菜单跳转到各个页面的跳转 四.省市联动 五.手机下拉加载 今天就到这里了&#xff0c;希望帮到你哦&#xff01;&#xff01;&#xff01; 一.交互与情节简介 "交互"通常指的是人与人、人与计算机或物体…...

【数据库设计和SQL基础语法】--连接与联接--多表查询与子查询基础(二)

一、子查询基础 1.1 子查询概述 子查询是指在一个查询语句内部嵌套另一个查询语句的过程。子查询可以嵌套在 SELECT、FROM、WHERE 或 HAVING 子句中&#xff0c;用于从数据库中检索数据或执行其他操作。子查询通常返回一个结果集&#xff0c;该结果集可以被包含它的主查询使用…...

Android studio中导入opencv库

具体opencv库的导入流程参考链接&#xff1a;Android Studio开发之路 &#xff08;五&#xff09;导入OpenCV以及报错解决 一、出现的错误&#xff1a;NullPointerException: Cannot invoke “java.io.File.toPath()” because “this.mySdkLocation” is null 解决办法&#…...

Linux(1)_基础知识

第一部分 一、Linux系统概述 创始人&#xff1a;芬兰大学大一的学生写的Linux内核&#xff0c;李纳斯托瓦兹。 Linux时unix的类系统&#xff1b; 特点&#xff1a;多用户 多线程的操作系统&#xff1b; 开源操作系统&#xff1b; 开源项目&#xff1a;操作系统&#xff0c;应用…...

网络相关面试题

简述 TCP 连接的过程&#xff08;淘系&#xff09; 参考答案&#xff1a; TCP 协议通过三次握手建立可靠的点对点连接&#xff0c;具体过程是&#xff1a; 首先服务器进入监听状态&#xff0c;然后即可处理连接 第一次握手&#xff1a;建立连接时&#xff0c;客户端发送 syn 包…...

网站设计大概多少钱/产品推广找哪家公司

苹果在WWDC上展示了15英寸Retina Macbook Pro&#xff0c; 让大家对13英寸Retina Macbook Pro 期待有加&#xff0c;分析师也普遍认为更小尺寸的MacBook Pro是众望所归&#xff0c;因为这样的产品既方便携带&#xff0c;又可以降低消费压力。今天苹果上个月&#xff08;6.29&am…...

安卓开发者网站/免费web服务器网站

下载&#xff0c;安装 VLC 从http://download.videolan.org/pub/videolan/vlc/下载对应版本的VLC Portable文件 下载安装 win64 版本的软件安装包 安装好。 安装 python-VLC 插件包 pip install python-vlc 安装完成后 可以开始测试了 VLC 插件包一定 是依赖于VLC软件的&…...

律师网站建设/电脑优化软件推荐

2004年2月28日&#xff0c;在浙江大学软件学院和CSDN网站的大力支持下&#xff0c;ERPTAO组织在浙大成功地举办了第一次软件技术讲座。有上百名专业软件开发者及爱好者到场参加&#xff0c;两位主讲人熊节&#xff08;也就是我本人&#xff09;和石一楹为大家送上了关于重构思想…...

做网站cdn加速有什么用/推广优化排名

#include<iostream> #include<Windows.h>//Sleep调用 using namespace std; int main() {std::cout << "\n正在输出记录数据...... ";for( int i0; i < 100; i ) // 打印百分比 {std::cout.width(3);//i的输出为3位宽std::cout << i…...

阿旗建设局举报网站/学电脑培训班

今天在做搜索框的时候、遇到需要获取焦点之后做一些事情、实现方法也很简单、那就是绑定OnFocusChangeListener事件、实现 onFocusChange(View v, boolean hasFocus) 方法、第二个参数就是判断得到焦点或失去焦点、从而实现我得想要的效果、代码如下&#xff1a; EditText sear…...

微信公众号电商网站开发/珠海百度seo

在使用left join的过程中&#xff0c;总是遇到一个问题&#xff0c;就是将条件放在on中还是where条件中。 在查过一些资料和实际操作后&#xff0c;总结了一下&#xff1a; 在多张表连接时&#xff0c;都会生成一张中间表&#xff0c;然后再将这张临时表返回给用户。 …...