参考链接:【Unity】弹性鱼竿简单实现-通过贝塞尔曲线修改Mesh - 简书

参考论文:吴晓亮, 黄襄念. Unity 中使用贝塞尔曲线对三维物体进行弯曲[J]. 现代计算机, 2016 (5): 57-59.

unity项目下载:https://download.csdn.net/download/weixin_43042683/87690343

效果图

0 引言

随着虚拟现实的发展,在游戏引擎中对三维物体进行弯曲效果的模拟越来越重要。 在三维游戏引擎中,需要对一些三维的物体进行弯曲,以达到游戏操作中实时模拟物体弯曲。说到弯曲,自然而然想到曲线,从曲线的角度出发,那么关键就是如何生成曲线,以及如何根据曲线修改物体形状,从而达到弯曲的效果。 生成曲线的话,可以直接想到用贝塞尔曲线,传统的贝塞尔曲线算法被用 于各类图形制作软件中,如 Photoshop 等软件,但多限于二维线条的应用,在三维物体上的应用较少。 通过贝塞尔曲线算法结合三维物体的网格顶点,可以实现对条形三维物体进行弯曲变化。

1 贝塞尔曲线

Bézier curve(贝塞尔曲线)是应用于二维图形应用程序的数学曲线。 曲线定义:起始点、终止点(也称锚点)、控制点。通过调整控制点,贝塞尔曲线的形状会发生变化。 1962年,法国数学家Pierre Bézier第一个研究了这种矢量绘制曲线的方法,并给出了详细的计算公式,因此按照这样的公式绘制出来的曲线就用他的姓氏来命名,称为贝塞尔曲线。

参考链接:Unity 贝塞尔曲线(Beizer curve)的原理与运用

1.1 一阶贝塞尔曲线

标准公式:

示意图:

代码实现:

    // 一阶贝塞尔曲线,参数P0、P1、t对应上方原理内的一阶曲线参数.Vector3 Bezier(Vector3 p0, Vector3 p1, float t){return (1 - t) * p0 + t * p1;}

1.2二阶贝塞尔曲线

标准公式:

示意图:

代码实现:

    // 二阶贝塞尔曲线,参数对应上方原理内的二阶曲线参数.Vector3 Bezier(Vector3 p0, Vector3 p1, Vector3 p2, float t){Vector3 p0p1 = (1 - t) * p0 + t * p1;Vector3 p1p2 = (1 - t) * p1 + t * p2;Vector3 temp = (1 - t) * p0p1 + t * p1p2;return temp;}

1.3三阶贝塞尔曲线

标准公式:

示意图:

   // 三阶贝塞尔曲线,参数对应上方原理内的三阶曲线参数.Vector3 Bezier(Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, float t){Vector3 temp;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;temp = (1 - t) * p0p1p2 + t * p1p2p3;return temp;}

1.4 n 阶贝塞尔曲线

标准公式:

代码实现:

//贝塞尔曲线公式
private Vector3 CalculateBezier(float t)
{Vector3 ret = new Vector3(0, 0, 0);int n = 阶数;for(int i = 0; i <= n; i++){Vector3 pi = 第i个控制点的坐标;ret = ret + Mathf.Pow(1 - t, n - i) * Mathf.Pow(t, i) * Cn_m(n, i) * pi;}return ret;
}
//组合数方程
private int Cn_m(int n, int m)
{int ret = 1;for(int i = 0; i < m; i++){ret = ret * (n - i) / (i + 1);  }return ret;
}

设计思路

在三维物体上添加多个控制点,其中控制点可以使用n个空节点来代替,控制点的坐标即为空节点的坐标。至于t值,可以看作顶点到底部的距离与整个三维物体长度的比值,0<= t <=1。这样设计的话,我们第一个控制点P0应该在三维物体的底部位置,而最后一个控制点Pn应该在三维物体的顶部位置。

2.弯曲的实现

根据上面公式计算出的只是一条曲线,而我们的目的是三维物体模型能按照这个曲线进行弯曲。

对于管状物体来说,我们计算出来的曲线其实是它的中心线,而mesh顶点应该位于中心线的两侧,所以顶点弯曲后的坐标是应该要由贝塞尔曲线计算的坐标经过一定变换得来。
经过观察可以发现,弯曲后顶点的坐标P'应由计算出的曲线上的坐标P进行两次偏移得出:在该点法线方向上进行偏移a、在垂直于弯曲面的方向上进行偏移b

对应代码如下:

// 对原来的顶点做贝塞尔曲线变换,得到弯曲变换后对应的点位置
private void UpdateBezierBend()
{   oriVertices = 模型未弯曲时的顶点数组;topPos = 最后一个控制点的坐标,用来计算模型长度;bendVector = 弯曲方向;for(int i = 0; i < oriVertices.Length; i++){//获取顶点坐标,计算t值Vector3 oriPos = oriVertices[i];float t = oriPos.y / topPos.y;//获取顶点在贝塞尔曲线上对应的坐标Vector3 p = CalculateBezier(t); //获取顶点在曲线上应有的法线偏移向量Vector3 vectorA = GetBendNormalVector(t, oriPos, bendVector); //获取顶点在曲线上应有的垂直偏移向量Vector3 vectorB = new Vector3(oriPos.x, 0, oriPos.z) - Vector3.Project(new Vector3(oriPos.x, 0, oriPos.z), bendVector); //获取顶点最终弯曲位置vector3 p' = p + vectorA + vectorB;}todo-修改顶点坐标;
}
// 获取指定点上的法向量偏移
private Vector3 GetBendNormalVector(float t, Vector3 oriPos, Vector3 bendVector)
{Vector3 tangentVector = CalculateBezierTangent(t);//切线斜率Vector3 normalVector = 由法线和切线互相垂直计算出法线方向;//法线向量的模应为到投影到弯曲面后,到中心点的距离float magnitude = Vector3.Project(new Vector3(oriPos.x, 0, oriPos.z), bendVector).magnitude;normalVector = normalVector.normalized * magnitude;return normalVector;
}
//对曲线公式求导得出切线向量
private Vector3 CalculateBezierTangent(float t)
{Vector3 ret = new Vector3(0, 0, 0);int n = 阶数;for(int i = 0; i <= n; i++){Vector3 pi = 第i个控制点的坐标;ret = ret + (-1 * (n - i) * Mathf.Pow(1 - t, n - i - 1) * Mathf.Pow(t, i) * Cn_m(n, i) * pi + i * Mathf.Pow(1 - t, n - i) * Mathf.Pow(t, i - 1) * Cn_m(n, i) * pi);}return ret;
}

这样我们就实现了通过控制点生成曲线,通过曲线弯曲物体的方法。

3.构造受力模型

简单构造一个受力模型,通过物体施加拉力,拉力使控制点发生变化,从而使物体弯曲。设定一个Cube为施加拉力F的物体,然后为每个控制点设定一个完全弯曲所需要的力Fc,然后设定控制点朝拉力方向弯曲的角度为:
a = Mathf.Clamp(F/Fc, 0, 1.0) * 拉力与控制点的夹角;
为了模拟比较真实的弯曲效果,Fc可以看成三维物体每小节的的弹力大小,越靠近底部的控制点Fc就越大,越难弯曲,反之,越靠近顶部的控制点Fc越小,也就越容易弯曲。
代码如下:

private void UpdateControlPoint()
{float F = Cube.force;//根据受力计算各个控制点旋转角度n = 控制点数量;for(int i = 1; i < n - 1; i++)//第一个和最后一个点不计算弯曲{//计算最大弯曲方向Vector3 toVector = 施力物体相对控制点pi的方向;Quaternion maxRotation =  Quaternion.FromToRotation(Vector3.up, toVector);//计算弯曲比例float rotateRate = Mathf.Clamp(F / Fc, 0f, 1.0f);//设置旋转角度pi.localRotation = Quaternion.Lerp(Quaternion.Euler(0, 0, 0), maxRotation, rotateRate);}
}

4. 结语

该方法做出来的弯曲效果还是很自然的(如效果图),使用也比较简单,且不需要关节控制。但是比较吃性能,另外考虑到光照,顶点坐标更新后需要重新计算下mesh的法线信息normals。

目前该方法对于管状的三维物体效果较佳,对于形状复杂的三维物体效果很差。该方法要求三维物体的顶点数要尽量多才能有效果。顶点数少的话很容易造成三维物体的扭曲变形。

Unity ——使用贝塞尔曲线对三维管状物体进行弯曲相关推荐

  1. unity之贝塞尔曲线

    简介 什么是贝塞尔曲线 贝塞尔曲线(Bezier curve),又称 贝兹曲线 或 贝济埃曲线 ,由法国工程师皮埃尔·贝塞尔(Pierre Bézier)所广泛发表,当时主要用于汽车主体设计.现主要应 ...

  2. 书小宅之网页设计——二次贝塞尔曲线和三次贝塞尔曲线

    贝塞尔曲线起始点和终止点在曲线上,方向控制点不再曲线上.二次贝塞尔曲线有一个控制点,三次贝塞尔曲线有两个控制点. 二次贝塞尔曲线 定义和用法 quadraticCurveTo() 方法通过使用表示二次 ...

  3. 【HTML 中的二次贝塞尔曲线 和三次贝塞尔曲线】(使用说明详解)

    二次 贝塞尔曲线 和三次 贝塞尔曲线 使用说明 1. 二次 贝塞尔曲线 和三次 贝塞尔曲线 1.1 贝塞尔曲线的 基本知识 1.2 贝塞尔曲线 生成动图 1.3 HTML 中 画贝塞尔曲线的 2 种方 ...

  4. 二次贝塞尔曲线转换为三次贝塞尔曲线

    二次贝塞尔曲线转换为三次贝塞尔曲线 在使用cairo绘图的时候,发现cairo不支持二次贝塞尔曲线的绘制,为了与QT实现的canvas的行为一致,cairo必须同样实现二次贝塞尔曲线的绘制.思路是将二 ...

  5. 贝塞尔曲线 unity两点画曲线弧线三点

    分享一下今天做的 贝塞尔曲线 三点决定一条曲线, 建立三个小球, 给第一个小球加LineRenderer LineRenderer要世界空间模式 给第一个小球加脚本, using UnityEngin ...

  6. unity 控制点 贝塞尔曲线_在Unity中使用贝塞尔曲线(转)

    鼎鼎大名的贝塞尔曲线相信大家都耳熟能详.这两天因为工作的原因需要将贝塞尔曲线加在工程中,那么MOMO迅速的研究了一下成果就分享给大家了哦.贝塞尔曲线的原理是由两个点构成的任意角度的曲线,这两个点一个是 ...

  7. 【Unity】贝塞尔曲线关于点、长度、切线计算在 Unity中的C#实现

    写在前面 最近给项目做了个路径编辑,基本思路是满足几个基本需求: [额外说明]其实本篇和这个没关系,可以跳过"写在前面"这部分,跨到正文部分 编辑时: ① 随意增减.插入.删除路点 ...

  8. unity 控制点 贝塞尔曲线_在Unity中使用贝塞尔曲线

    前言 最近项目需要呈现各种轨道且随机性较强,在找了一天插件后打算自己实现平滑曲线,思路是策划对关卡中的轨道放置任意个节点,我通过代码将所有节点绘制成一条平滑的曲线,每两个节点之间通过三阶贝塞尔实现,最 ...

  9. canvas笔记-二次贝塞尔曲线与三次贝塞尔曲线的用法

    此博文不研究其算法,只记录下其用法. 首先是二次贝塞尔曲线! 函数是这样的 quadraticCurveTo(cpx, cpy, x, y); 其中cpx为贝塞尔控制点x: 其中cpy为贝塞尔控制点y ...

最新文章

  1. hexo 搜索_Hexo--本地搜索localsearch之url路径问题
  2. 查看linux4222端口,linux 内核 ALIGN 含义
  3. [开源]基于姿态估计的运动计数APP开发(一)
  4. CMOS Sensor的调试分享
  5. node mysql安装目录_nodejs 指定全局安装路径和缓存路径
  6. ScaleGestureDetector使用注意事项
  7. ios 请在设置中打开相机权限_在iOS中请求摄像头权限对话框启动(Prime权限)
  8. Pycharm报错解决:error:please select a valid Python interpreter 及一些基本设置
  9. kafka集群为什么需要三个节点_Kafka突然宕机了?稳住,莫慌!
  10. 用vs2012的命令利用xsd文件生成对应的C#类,把xml的string类型映射到生成的类
  11. 你知道数据库索引的工作原理吗?
  12. paip.mysql 全文索引查询空白解决
  13. UVa 10082 WERTYU
  14. The Chivalrous Cow(BFS+最短路径)
  15. 个人对*xx与**xx的理解
  16. 对首次认定为虹口区四新示范企业给予20万元奖励
  17. 163邮箱开启SMTP权限
  18. dns114.114.114..114
  19. 如何使用CorelDRAW 2019快速制作幻影图像效果
  20. 程序员用 AI 修复百年前的老北京视频后,火了!

热门文章

  1. 企业安全之内部代码管理平台Gitlab下载及权限审计
  2. 博采众长,郁锦香酒店凭品牌硬实力打造高端酒店投资领域热门产品
  3. excel怎么合并多个工作簿到一个表格
  4. 爆款小程序是如何诞生的?
  5. 2023年内蒙古医科大学内科学考研难度、参考书及上岸前辈经验
  6. 抖音运营:名字、头像、账号简介...那些抖音主页里的涨粉技巧
  7. 计算复杂性读书笔记(二): 论怎么把一个证明写得有意思
  8. 通过telnet管理华为路由器
  9. 如何关闭垂直同步(图解)
  10. 华为车BU王军被停职,余承东独掌智能车业务丨HiEV独家