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

这篇具有很好参考价值的文章主要介绍了Unity ——使用贝塞尔曲线对三维管状物体进行弯曲。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

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

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

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

效果图

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

0 引言

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

1 贝塞尔曲线

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

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

1.1 一阶贝塞尔曲线

标准公式:

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

 示意图:

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

代码实现:

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

1.2二阶贝塞尔曲线

标准公式:

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

示意图:

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

代码实现:

    // 二阶贝塞尔曲线,参数对应上方原理内的二阶曲线参数.
    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三阶贝塞尔曲线

标准公式:

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

示意图:

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

   // 三阶贝塞尔曲线,参数对应上方原理内的三阶曲线参数.
    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 阶贝塞尔曲线

标准公式:

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

代码实现:

//贝塞尔曲线公式
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

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

 对应代码如下:

// 对原来的顶点做贝塞尔曲线变换,得到弯曲变换后对应的点位置
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。 

目前该方法对于管状的三维物体效果较佳,对于形状复杂的三维物体效果很差。该方法要求三维物体的顶点数要尽量多才能有效果。顶点数少的话很容易造成三维物体的扭曲变形。文章来源地址https://www.toymoban.com/news/detail-501350.html

到了这里,关于Unity ——使用贝塞尔曲线对三维管状物体进行弯曲的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • Unity实现杀戮尖塔出牌效果( 三. 贝塞尔曲线引导箭头绘制,卡牌使用效果制作)

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

    2024年04月12日
    浏览(38)
  • Bezier Curve 贝塞尔曲线 - 在Unity中实现路径编辑

    贝塞尔曲线( Bezier Curve ),又称贝兹曲线或贝济埃曲线,是计算机图形学中相当重要的参数曲线,在我们常用的软件如 Photo Shop 中就有贝塞尔曲线工具,本文简单介绍贝塞尔曲线在Unity中的实现与应用。 给顶点P 0 、P 1 ,只是一条两点之间的直线,公式如下: B(t) = P 0 + (P

    2024年01月23日
    浏览(33)
  • 【游戏开发实战】Unity实现类似GitHub地球射线的效果(LineRenderer | 贝塞尔曲线)

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

    2024年02月06日
    浏览(81)
  • 二阶贝塞尔曲线生成弧线

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

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

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

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

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

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

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

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

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

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

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

    2024年04月14日
    浏览(32)
  • 贝塞尔曲线的python实现(简单易理解)

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

    2024年02月16日
    浏览(30)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包