贝塞尔曲线动画C++简单实践

本文介绍了如何使用C++实现贝塞尔曲线动画,详细探讨了一阶至N阶贝塞尔曲线的数学公式,并展示了在cmd和窗口环境中创建动画的实例。通过计算曲线散点坐标并结合二分法插值,实现了平滑的动画过渡效果。
摘要由CSDN通过智能技术生成

贝塞尔曲线简介

由于用计算机画图大部分时间是操作鼠标来掌握线条的路径,与手绘的感觉和效果有很大的差别。即使是一位精明的画师能轻松绘出各种图形,拿到鼠标想随心所欲的画图也不是一件容易的事。这一点是计算机万万不能代替手工的工作,所以人们只能颇感无奈。使用贝塞尔工具画图很大程度上弥补了这一缺憾。贝塞尔曲线是计算机图形图像造型的基本工具,是图形造型运用得最多的基本线条之一。它通过控制曲线上的四个点(起始点、终止点以及两个相互分离的中间点)来创造、编辑图形。
除此之外,贝塞尔曲线还经常用来做动画,让动画过渡更平滑。本文则记录如何使用贝塞尔曲线定制平滑的动画效果,并使用C++编写了cmd动画和窗口动画示例代码。

一阶贝塞尔

一阶贝塞尔曲线
设定图中运动的点为Ptt为运动时间,t∈(0,1),可得如下公式:
公式1

二阶贝塞尔

二阶贝塞尔曲线
在二阶贝塞尔曲线中,已知三点恒定(P0,P1,P2),设定在P0 P1中的点为Pa,在P1 P2中的点为PbPtPa Pb上的点,这三点都在相同时间t内做匀速运动。

由公式(1)可知
公式2,3,4
将公式(2)(3)代入公式(4)中,可得
公式5

三阶贝塞尔

三阶贝塞尔曲线
同理,根据以上的推导过程可得
公式6
由此可以推导
公式7

N阶贝塞尔曲线

四阶贝塞尔曲线:
四阶贝塞尔曲线
五阶贝塞尔曲线:
五阶贝塞尔曲线
N阶贝塞尔曲线公式:
N阶贝塞尔曲线公式

贝塞尔曲线在动画中的应用
  • 贝赛尔曲线广泛应用于绘图软件中,例如Adobe PhotoShop、Adobe Flash。
  • Android可以通过自定义的view来实现贝塞尔曲线
  • ios则可以使用UIBezierPath类来生成贝塞尔曲线
  • 前端,canvas bezierCurveTo,css animation-timing-function: cubic-bezier(x,x,x,x}都有关于贝赛尔曲线的一些应用。

贝塞尔曲线在动画中的应用一般是三阶贝塞尔曲线,通过两个控制点来描述一般的动画曲线。通常以动画完成度为y轴,时间为x轴,然后将时间带入动画曲线求得对应的动画完成度

但是上述公式描述的是点与点关系,想要分解为x,y坐标的关系,则需要继续推导,以三阶为例:贝塞尔曲线x与y坐标的关系
想要直观的感受曲线的效果可以前往: cubic-bezier
得到xy坐标关系后即可写代码进行实践了。

实践
求曲线散点坐标

由上面推导的曲线点的坐标和时间的关系可得:设曲线起点为(0,0),终点为(1,1),则t时刻点的位置仅与两个控制点P1 P2有关。先定义表示一个点的结构体:

  struct PointF
  {
   
    PointF() : x(0), y(0) {
   }
    PointF(double x, double y) : x(x), y(y) {
   }
    double x;
    double y;
  };

然后传入两个点的坐标进行初始化

  void init(double x1, double y1, double x2, double y2)
  {
   
    pc.x = 3.0 * x1;
    pb.x = 3.0 * (x2 - x1) - pc.x;
    pa.x = 1.0 - pc.x - pb.x;

    pc.y = 3.0 * y1;
    pb.y = 3.0 * (y2 - y1) - pc.y;
    pa.y = 1.0 - pc.y - pb.y;
  }

计算t时刻的xy坐标

  double calcX(double t)
  {
   
    return ((pa.x * t + pb.x) * t + pc.x) * t;
  }

  double calcY(double t)
  {
   
    return ((pa.y * t + pb.y) * t + pc.y) * t;
  }

根据给定的采样计算出[0,1]时刻的n个曲线上的点坐标,即可绘制出曲线图。

  for (int i = 0; i < size; ++i) {
    // size即为采样个数,然后计算出对应采样时刻的曲线坐标
    sample_[i] = PointF(calcX(i * 1.0 / size), calcY(i * 1.0 / size));
  }

得到曲线坐标后可绘制曲线图看下:
贝塞尔曲线图
其中蓝色的曲线是贝塞尔曲线,绿色和红色的曲线分别表示贝塞尔曲线上的y坐标和x坐标与t的关系,即y随时间先慢,再快,最后慢。x随时间先快,再变慢,最后变快。

将曲线应用到动画

得到曲线散点坐标后,该怎么将其应用到动画呢?
因为我们已经设了x坐标在[0,1]之间,而动画一般就是分为动画完成度和时间的关系,而我们设动画的时间也在[0,1],那么就可以给定动画的时刻t,然后通过曲线散点坐标求得对应的动画完成度。
即通过x坐标求y坐标,因为我们只有散点坐标,时刻t不一定跟已有点的x坐标相同,因此需要找到最接近的时刻t的两个点进行插值,即可求得近似的y坐标,也即动画完成度。
废话不多说,直接上代码,使用二分法查找最近的两点并插值求y:

double GetYAtX(double x)
{
   
  int head = 0;
  int tail = size - 1;
  int center;
  while (head <= tail) {
   
    center = (head + tail) / 2;
    if (sample_[center].x < x) {
   
      head = center + 1;
    } else if (sample_[center].x > x) {
   
      tail = center - 1;
    } else {
   
      break;
    }
  }

  if (head < size - 1) {
   
    double x0 = sample_[head].x;
    double x1 = sample_[head + 1].x;
    double y0 = sample_[head].y;
    double y1 = sample_[head + 1].y;
    return (x - x0) / 
  • 6
    点赞
  • 45
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
贝塞尔曲线是一种平滑的曲线,可以用于制作动画效果。在canvas中,我们可以使用贝塞尔曲线来绘制路径,并通过动画让路径呈现出流畅的变化。 下面是一个使用贝塞尔曲线实现动画效果的示例: ```html <canvas id="myCanvas" width="500" height="500"></canvas> ``` ```javascript // 获取canvas元素 var canvas = document.getElementById("myCanvas"); var ctx = canvas.getContext("2d"); // 定义起点、终点和控制点 var startPoint = {x: 50, y: 50}; var endPoint = {x: 450, y: 450}; var controlPoint = {x: 250, y: 50}; // 定义动画帧数和当前帧数 var frames = 60; var currentFrame = 0; // 绘制贝塞尔曲线路径 function drawBezierPath() { ctx.beginPath(); ctx.moveTo(startPoint.x, startPoint.y); ctx.quadraticCurveTo(controlPoint.x, controlPoint.y, endPoint.x, endPoint.y); ctx.stroke(); } // 清除canvas function clearCanvas() { ctx.clearRect(0, 0, canvas.width, canvas.height); } // 动画函数 function animate() { clearCanvas(); drawBezierPath(); currentFrame++; // 当前帧数小于动画帧数时,继续执行动画 if (currentFrame < frames) { controlPoint.y += 2; requestAnimationFrame(animate); } } // 启动动画 animate(); ``` 在这个示例中,我们定义了起点、终点和控制点的坐标,并使用`quadraticCurveTo()`方法绘制了贝塞尔曲线路径。然后定义了动画帧数和当前帧数,以及动画函数`animate()`。在动画函数中,我们清除canvas,重新绘制路径,将控制点的y坐标逐渐增加,实现动画效果。 你可以根据自己的需求修改起点、终点和控制点的坐标,以及动画帧数和控制点的移动方式,来实现不同的贝塞尔曲线动画效果。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值