转载:http://blog.csdn.net/wangzhi0417/article/details/2002477

1.     前言

本人近来在学习曲线和曲面的知识,有一句话说得好:

“It can’t be truly said that you understand something until you can explain it clearly to someone else!”

抱着学习和交流的精神,写此教程,希望能和大家一同成长和提高;

本教程的绝大数资料参考自:

http://www.cs.mtu.edu/~shene/COURSES/cs3621/NOTES/notes.html

本教程将说明Bezier曲线、B样条和NURBS的要点,并在OpenGL中实现之,教程中将给出实现关键部分的代码;

2.     概述

在CAD中,设计师需要设计出各种各样的曲线;数学中,曲线是通过各种各样的方程表示的,比如一条通过点A(0,0)、B(1,1)的直线可以表示为:

y=x

或者用参数方程表示:

P(u) = (1-u)A+tB

再比如一个通过原点(1,2)、半径为2的圆可以表示为:

(x-1)^2 + (y-2)^2 = 4

或者用参数方程表示:

x = 2cos(u)+1

y = 2sin(u)+2

上面举例的是两种很简单的曲线,对于更复杂的曲线可以用更复杂的方程来表示(比如用高次多项式);

如果我们的设计师是一位数学家就好了,他可以根据自己的需要,设计出一个复杂的方程来表示自己想要的一条优美的曲线,但是事与愿违,设计师们往往想通过一种直观的方式来设计曲线,而不是利用方程。

因此,诸位科学家和工程师设计出了Bezier曲线、B样条和NURBS,下面是一个有四个控制点的Bezier曲线:

可以通过改变一个控制点的位置来改变曲线的形状,比如将上图曲线中左边第二个控制点往上移,就可以得到下面的曲线:

可以看到,这种曲线生成方式比较直观和灵活,我只需要放置控制点,然后调整控制点的位置来得到想要的曲线,这就避免了和复杂的数学方程打交道,岂不快哉?

Bezier曲线、B样条和NURBS都是根据控制点来生成曲线的,那么他们有什么区别了?简单来说,就是:

§  Bezier曲线中的每个控制点都会影响整个曲线的形状,而B样条中的控制点只会影响整个曲线的一部分,显然B样条提供了更多的灵活性;

§  Bezier和B样条都是多项式参数曲线,不能表示一些基本的曲线,比如圆,所以引入了NURBS,即非均匀有理B样条来解决这个问题;

Bezier曲线只是B样条的一个特例而已,而B样条又是NURBS的一个特例,它们的关系可以图示为:

下面我们从最基本的Bezier曲线讲起:

3.     Bezier曲线

3.1     举例

两个控制点

只有两个控制点P、Q的Bezier曲线是什么样子的?不难想像是线段PQ,如下图:

所以由控制点P、Q产生的Bezier曲线的方程是:

C(u) = (1-u)P + uQ       0<= u <= 1

曲线上参数为u的点是通过P和Q的线性组合得到的。

三个控制点

如果想得到一条弯曲的曲线,两个控制点是不够的,加上一个控制点R,那么由控制点P、Q和R生成的Bezier曲线又是什么样子的了?

假设生成的曲线为C(u),其中0<=u<=1,对应于某个特定的u,C(u)如何计算出来了?

我们先在PQ上求一点A(u)

A(u) = (1-u)P + uQ

在QR上求一点B(u)

B(u) = (1-u)Q + uR

再在生成的线段上求C(u)

C(u) = (1-u)A(u) + uB(u)

对应于下图,用这种迭代的方法求出的点C(u)就是Bezier曲线上参数为u的点!

我们可以用OpenGL写一个程序输出这个Bezier曲线:

glBegin(GL_LINE_STRIP);

for i = 1 to 50

u = i / 1.0;

C(u) = (1-u)A(u)+uB(u);

glVertex2f(C(u).x, C(u).y);

glEnd

输出的Bezier曲线如下图所示,曲线通过了点C(u):

可以将A(u)和B(u)的公式代入C(u)得到:

C(u) = (1-u)A(u)+uB(u)

= (1-u) [(1-u)P + uQ] + u [(1-u)Q + uR]

= (1-u)^2 P +2u(1-u) Q + u^2 R                        ( 0<=u<=1 )

上面的公式给出了从三个控制点P、Q和R,求取参数u对于的曲线上点的方法,如果u=0,则C(0)=P;如果u=1,则C(1)=R,说明曲线通过P和R,与上图的观察是一致的;

四个控制点

如果有四个控制点P、Q、R和S,给定一个参数值u,0<=u<=1,如何求u对应的Bezier曲线上的点?还是用上述迭代的方法,最后得到的方程是:

C(u) = (1-u)^3 P + 3u(1-u)^2 Q + 3u^2(1-u) R + u^3 S

绘制出来的曲线如下图所示:

大家重点要理解和记住这里迭代求C(u)的概念,这是一些重要算法的基础;

3.2     Bezier曲线的定义

定义:给定n+1个控制点P0、P1、P2、...和Pn,由它们定义的Bezier曲线为:

其中系数定义为:

由上面的定义得知Bezier曲线上对应于参数u的点C(u)是所有控制点的一个加权和;举三个控制点P0、P1和P2的Bezier曲线为例子,我们已经知道它的方程是:

C(u) = (1-u)^2 P0 +2u(1-u) P1 + u^2 P2                 ( 0<=u<=1 )

显然C(u)是P0、P1和P2的一个加权和,这里的系数(权值)很重要:

B2,0(u) = (1-u)^2

B2,1(u) = 2u(1-u)

B2,2(u) = u^2

Bn,i(u)叫做Bernstein多项式,满足0<=Bn,i(u) <=1;

好了,如果现在我们要写一个程序,让用户用鼠标输入n+1个控制点P0、P1、...和Pn,如何生成对应的Bezier曲线了?我们当然可以根据定义求一系列u对应的点C(u):

glBegin(GL_LINE_STRIP);

for i = 1 to 50

u = i / 1.0;

// evaluate C(u)

C(u) = (0.0, 0.0);

for each control point Pi

// calculate Bn,i(u) using definition

Bn,i(u) = ...

C(u) += Bn,i(u) * Pi;

glVertex2f(C(u).x, C(u).y);

glEnd

这个方法有什么问题了?答案是这不是数值稳定的算法,因为Bn,i(u)的计算会引起浮点除法,从而导致误差的产生,为了解决这个问题,de Casteljau算法隆重登场了!

3.3     de Casteljau算法

de Casteljau算法要解决的问题清楚了吧?就是要根据n+1个控制点P0...Pn,和一个参数值u,求得对应于曲线上的点C(u),这个算法就是利用我们前面例子部分的迭代的方法求这个点;如下图示:

其中最左边的0i为控制点Pi,整个图显示了迭代的过程,迭代次数为n;

de Casteljau算法的具体描述:

Input: array P[0:n] of n+1 control points and a real number u in [0,1]

Output: point on curve, C(u)

Working: point array Q[0:n]

for i=0 to n do

Q[i] = P[i]

for k=1 to n do          // the times of recursion is n!

for i=0 to n-k do

Q[i] = (1-u)Q[i] + uQ[i+1]

return Q[0];

3.4     示例程序

我写了一个生成Bezier曲线的小程序,用户通过点击鼠标确定控制点,当控制点的数目大于2的时候生成曲线,程序很容易懂,只有一个地方需要注意:

在设置裁剪区域的时候,需要这样调用:

glOrtho(0, windowWidth, 0, windowHeight, -10.0, 10.0);

其中windowWidth、windowHeight要和在指定窗口大小的参数保持一致:

glutInitWindowSize(windowWidth,windowHeight);

源文件:deCasteljau.h Bezier_Basic.cpp

好的,到现在我已经完成了Bezier曲线的介绍,下面我们将进入最为复杂的B样条曲线;

从Bezier到NURBS曲线(1) - Bezier曲线相关推荐

  1. Hermite曲线与Bezier曲线的关系

    结论 最近在研究3次样条曲线.曲线由四个控制点控制,依次记为P0,P1,P2,P3.在绘制Hermite曲线的时候,发现如果令P0处的导数为3倍P1-P0,P3处的导数为3倍P3-P2,则P0,P1, ...

  2. 贝塞尔曲线(Bezier)之 QQ 消息拖拽动画效果

    博主声明: 转载请在开头附加本文链接及作者信息,并标记为转载.本文由博主 威威喵 原创,请多支持与指教. 本文首发于此   博主:威威喵  |  博客主页:https://blog.csdn.net/ ...

  3. 计算机图形学 实验7 《复杂图形绘制-Bezier曲线与Hermite曲线》

    计算机图形学 实验7 <复杂图形绘制-Bezier曲线与Hermite曲线> 一.实验目的 学习样条曲线的绘制. 二.实验内容 1.绘制Bezier曲线: 2.绘制Hermite曲线. 三 ...

  4. 贝塞尔曲线(Bezier)之水波纹的手机充电动画效果(一)

    博主声明: 转载请在开头附加本文链接及作者信息,并标记为转载.本文由博主 威威喵 原创,请多支持与指教. 本文首发于此   博主:威威喵  |  博客主页:https://blog.csdn.net/ ...

  5. 贝塞尔曲线(Bezier)之花束直播爱心点赞动画效果

    博主声明: 转载请在开头附加本文链接及作者信息,并标记为转载.本文由博主 威威喵 原创,请多支持与指教. 本文首发于此   博主:威威喵  |  博客主页:https://blog.csdn.net/ ...

  6. 贝塞尔曲线(Bezier Curve)原理及公式推导

    1. 定义 贝塞尔曲线(Bezier curve),又称贝兹曲线或贝济埃曲线,是应用于二维图形应用程序的数学曲线.一般的矢量图形软件通过它来精确画出曲线,贝兹曲线由线段与节点组成,节点是可拖动的支点, ...

  7. 贝塞尔曲线(Bezier)之水波纹的手机充电动画效果(二)

    博主声明: 转载请在开头附加本文链接及作者信息,并标记为转载.本文由博主 威威喵 原创,请多支持与指教. 本文首发于此   博主:威威喵  |  博客主页:https://blog.csdn.net/ ...

  8. 贝塞尔曲线(Bezier Curve)原理、公式推导及matlab代码实现

    1. 定义 贝塞尔曲线(Bezier curve),又称贝兹曲线或贝济埃曲线,是应用于二维图形应用程序的数学曲线.一般的矢量图形软件通过它来精确画出曲线,贝兹曲线由线段与节点组成,节点是可拖动的支点, ...

  9. java画bezier曲面_计算机图形学上机实验4-实现Bezier曲线和Bezier曲面的绘制

    <计算机图形学上机实验4-实现Bezier曲线和Bezier曲面的绘制>由会员分享,可在线阅读,更多相关<计算机图形学上机实验4-实现Bezier曲线和Bezier曲面的绘制(9页珍 ...

  10. bezier.CSS_SVG_canvas画_贝兹曲线

    ZC:(1).SVG可以绘制 贝兹曲线:(2).canvas能绘制 贝兹曲线:(3).现在(20180202)查资料发现,css 貌似不能绘制 贝兹曲线,css使用贝兹曲线 主要是用于控制动画的速度, ...

最新文章

  1. 这 23 道题,全世界的数学家花费 100 年时间,只解答了一半
  2. GitLab-怎样使用GitLab托管项目
  3. java 中的路径问题总结(绝对路径与相对路径) .
  4. Python--day47--mysql索引注意事项
  5. Java中BigDecimal的8种舍入模式
  6. 手把手教你做数据产品经理
  7. oracle+包锁源头,oracle琐碎笔记 - 石奈子0314
  8. 使用PHPExcel实现Excel文件的导入和导出(模板导出)
  9. 最大功率跟踪mppt
  10. 计算机类专业要求高中选课,高一选课|12个学科门类、94个专业大类选课要求和招生人数分析...
  11. Kubernetes Dashboard 终结者:KubeSphere
  12. IEC 60664-1-2020【现行】低压供电系统内设备的绝缘配合第1部分:原则、要求和试验
  13. 香港科大【526清水湾思享会@杭州】暨香港科大EMBA第四届校友会【浙江分会】启动仪式成功举行...
  14. SQL窗口函数OVER用法整理
  15. ios微信组件跳转_在iOS9中突破微信App跳转的限制
  16. libusb系列-007-Qt下使用libusb1.0.26源码
  17. 计算机用户名如何修改,如何修改电脑用户名
  18. 无线传感器网络Dv-hop定位算法
  19. search - indexOf区别
  20. 比Visio牛逼的流程图工具,Visio替代品!

热门文章

  1. JS键盘事件对象之keyCode、charCode、which属性对比
  2. js 判断是否是 整数
  3. 移动端自适应布局方案尝试
  4. 关于ibatis中sqlMap配置文件中使用到,的处理
  5. 7月第3周社交网站综合排行Top10:新浪微博居首
  6. Netty-Pipeline组件
  7. 多线程中使用CheckForIllegalCrossThreadCalls = false访问窗口
  8. 101 Symmetric Tree
  9. 分享一下滑动验证码的模拟滑动攻克
  10. Android 贝塞尔曲线