【转】贝塞尔曲线和曲面

原文地址:http://my.oschina.net/sweetdark/blog/183721

参数方程表现形式

在中学的时候,我们都学习过直线的参数方程:y = kx + b;其中k表示斜率,b表示截距(即与y轴的交点坐标)。类似地,我们也可以用一个参数方程来表示一条曲线。1962年,法国工程师贝塞尔发明了贝塞尔曲线方程。关于贝塞尔曲线的详细介绍可以参考(维基贝塞尔)。这里只介绍OpenGL实现贝塞尔的函数。

OpenGl定义一条曲线时,也把它定义为一个曲线方程。我们把这条曲线的参数成为u,它的值域就是曲线的定义域。曲面则需要u和v两个参数来描述。注意,u和v参数只表示了描述曲线的参数方程的范围,它们并没有反映实际的坐标值。其坐标可以表示为:

x = f(u); y = g(u); z = h(u);

如下图:

控制点

贝塞尔曲线的形状由控制点来控制。贝塞尔曲线的控制点个数为曲线的阶。根据控制点的个数,贝塞尔曲线又分为二次贝塞尔曲线,三次贝塞尔曲线,高阶贝塞尔曲线。

线性曲线

线性贝塞尔曲线演示动画,t in [0,1]

二次方曲线

为建构二次贝塞尔曲线,可以中介点Q0和Q1作为由0至1的t:

  • 由P0至P1的连续点Q0,描述一条线性贝塞尔曲线。

  • 由P1至P2的连续点Q1,描述一条线性贝塞尔曲线。

  • 由Q0至Q1的连续点B(t),描述一条二次贝塞尔曲线。

二次贝塞尔曲线的结构
二次贝塞尔曲线演示动画,t in [0,1]

三次方曲线

为建构高阶曲线,便需要相应更多的中介点。对于三次曲线,可由线性贝塞尔曲线描述的中介点Q0、Q1、Q2,和由二次曲线描述的点R0、R1所建构:

三次贝塞尔曲线的结构
三次贝塞尔曲线演示动画,t in [0,1]

连续性

两段曲线是否相连接,代表这两段曲线是否连续的。曲线的连续性分为4种,无连续,点连续,正切连续,曲率连续。下图分别表示了这几种情况:

其中曲率连续的曲线过渡的更平滑。我们可以通过参数来设置曲线的连续性。

求值器

OpenGL提供了一些函数来绘制贝塞尔曲线和曲面。我们只需要提供控制点和u,v作为参数,然后调用求值函数来绘制曲线。

2D曲线的例子:

//控制点 GLint numOfPoints = 4; static GLfloat controlPoints[4][3] = {{-4.0f, 0.0f, 0.0f},
{-6.0f, 4.0f, 0.0f},
{6.0f, -4.0f, 0.0f},
{4.0f, 0.0f, 0.0f}}; void SetupRC()
{glClearColor(0.0f, 0.0f, 0.0f, 1.0f);glColor3f(1.0f, 0.0f, 1.0f);
}
//画控制点
void DrawPoints()
{glPointSize(2.5f);glBegin(GL_POINTS); for (int i = 0; i < numOfPoints; ++i){glVertex3fv(controlPoints[i]);}glEnd();
} void ChangeSize(GLsizei w, GLsizei h)
{if (h == 0){h = 1;}glViewport(0, 0, w, h);//使用正交投影glMatrixMode(GL_PROJECTION);glLoadIdentity();gluOrtho2D(-10.0f, 10.0f, -10.0f, 10.0f);glMatrixMode(GL_MODELVIEW);glLoadIdentity();
} void RenderScene()
{glClear(GL_COLOR_BUFFER_BIT);//设置贝塞尔曲线,这个函数其实只需要调用一次,可以放在SetupRC中设置glMap1f(GL_MAP1_VERTEX_3, //生成的数据类型0.0f, //u值的下界100.0f, //u值的上界3, //顶点在数据中的间隔,x,y,z所以间隔是3numOfPoints, //u方向上的阶,即控制点的个数&controlPoints[0][0] //指向控制点数据的指针 );//必须在绘制顶点之前开启glEnable(GL_MAP1_VERTEX_3);//使用画线的方式来连接点glBegin(GL_LINE_STRIP);for (int i = 0; i <= 100; i++){glEvalCoord1f((GLfloat)i);}glEnd();DrawPoints();glutSwapBuffers();}

在RenderScene函数中调用glMap1f来为曲线创建映射。第一个参数为GL_MAP1_VERTEX3,设置求值器产生顶点为三元组(x,y,z).还可以设置为产生纹理坐标和颜色信息。参考glMap1.后面的两个参数设定了u的取值范围[0,100],第四个参数指定了顶点在数组中的间隔,由于顶点是由3个浮点数组成,所以间隔是3.第五个参数指定了控制点的个数,最后一个参数是控制点数组。然后我们需要启用求值器,调用如下:

glEnable(GL_MAP1_VERTEX3);

glEvalCoord1f函数,接受一个参数为曲线的参数值。调用这个函数会通过求值函数求出顶点坐标值,然后内部调用了glVertex。这里使用连线的方式来连接这些顶点:

glBegin(GL_LINE_STRIP);

for(i = 0; I <= 100; i++)

{

glEvalCoord1f((GLfloat)i);

}

glEnd();

计算曲线

OpenGl还提供了更简单的方式来完成上面的任务。我们可以通过glMapGrid函数来设置一个网格,来告诉OpenGL在u的值域的范围内创建一个包含各个点的空间对称的网格。然后,我们调用glEvalMesh,使用指定的图元(GL_LINE或GL_POINTS)来链接各个点。

我们用下面的两个函数调用

  glMapGrid1f(100, 0.0f, 100.0f);glEvalMesh1(GL_LINE, 0, 100);

可以替换下面的代码

glBegin(GL_LINE_STRIP);
for (int i = 0; i <= 100; i++){glEvalCoord1f((GLfloat)i);}
glEnd();

使用这种方式更为紧凑。

3D表面

创建一个贝塞尔曲面与创建一个贝塞尔曲线类似。除了给出u的定义域之外,还要给出v的定义域。下面的例子是创建一个贝塞尔曲面。与之前不同的是,我们沿着v的定义域定义了3组控制点。为了保持曲面的简单,这几组控制点只是z值不同。用这种方式画的曲面,看起来像是曲线沿z轴的扩展。

//控制点  GLint nNumPoints = 3;GLfloat ctrlPoints[3][3][3]= {{{  -4.0f, 0.0f, 4.0f},
{ -2.0f, 4.0f, 4.0f},
{  4.0f, 0.0f, 4.0f }},{{  -4.0f, 0.0f, 0.0f},
{ -2.0f, 4.0f, 0.0f},
{  4.0f, 0.0f, 0.0f }},{{  -4.0f, 0.0f, -4.0f},
{ -2.0f, 4.0f, -4.0f},
{  4.0f, 0.0f, -4.0f }}}; //画控制点  void DrawPoints(void)
{ int i,j;    glColor3f(1.0f, 0.0f, 0.0f); //把点放大一点,看得更清楚  glPointSize(5.0f);glBegin(GL_POINTS); for(i = 0; i < nNumPoints; i++)for(j = 0; j < 3; j++)glVertex3fv(ctrlPoints[i][j]);glEnd();
}
void RenderScene(void)
{
// Clear the window with current clearing color glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);// 保存模型视图矩阵  glMatrixMode(GL_MODELVIEW);glPushMatrix(); //旋转一定的角度方便观察  glRotatef(45.0f, 0.0f, 1.0f, 0.0f);glRotatef(60.0f, 1.0f, 0.0f, 0.0f);glColor3f(0.0f, 0.0f, 1.0f); //设置映射方式,只需要设置一次可以在SetupRC中调用。  glMap2f(GL_MAP2_VERTEX_3, //生成的数据类型  0.0f, // u的下界 10.0f, //u的上界  3, //数据中点的间隔  3, //u方向上的阶  0.0f, //v的下界  10.0f, //v的上界  9, // 控制点之间的间隔  3, // v方向上的阶  &ctrlPoints[0][0][0]); //控制点数组 //启用求值器  glEnable(GL_MAP2_VERTEX_3); //从0到10映射一个包含10个点的网格  glMapGrid2f(10,0.0f,10.0f,10,0.0f,10.0f); // 计算网格  glEvalMesh2(GL_LINE,0,10,0,10); //画控制点  DrawPoints();glPopMatrix();glutSwapBuffers();
}

在这里我们用glMap2f替换了之前的glMap1f, 这个函数指定了u和v两个域上的点。除了指定u的上界和下界之外,还要指定v的上界和下界。v定义域内点的距离是9,因为这里使用了3维数组,包含了3个u值,每个u值又包含了3个点,3x3=9。然后指定v方向上的阶,即每个u分支上v方向有多少个点。最后一个参数是指向控制点的指针。

然后我们设置求值器.

//启用求值器

glEnable(GL_MAP2_VERTEX_3);
//从0到10映射一个包含10个点的网格

glMapGrid2f(10,0.0f,10.0f,10,0.0f,10.0f);

计算网格网格表面,用线的方式表示。

// 计算网格
  glEvalMesh2(GL_LINE,0,10,0,10);

光照和法线

求值器还可以帮我们生成表面的法线,只需简单的修改一些代码:

把glEvalMesh2(GL_LINE, 0, 10, 0, 10);替换为glEvalMesh2(GL_FILL, 0, 10, 0, 10);然后在初始化时 SetupRC中调用glEnable(GL_AUTO_NORMAL);就可以得到一个收到光照的曲面了。

【转】贝塞尔曲线和曲面相关推荐

  1. 计算机图形学【GAMES-101】5、几何(距离函数SDF、点云、贝塞尔曲线、曲面细分、曲面简化)

    快速跳转: 1.矩阵变换原理Transform(旋转.位移.缩放.正交投影.透视投影) 2.光栅化(反走样.傅里叶变换.卷积) 3.着色计算(深度缓存.着色模型.着色频率) 4.纹理映射(重心坐标插值 ...

  2. 11、计算机图形学——几何(贝塞尔曲线与曲面)

    一.贝塞尔曲线 1.1.简介 下图中蓝色的线就是贝塞尔曲线,每条贝塞尔曲线都有控制点(下图中有四个),贝塞尔曲线必须经过第1个和最后一个控制点,并且需要和第起止控制点相切 1.2.如何得到贝塞尔曲线 ...

  3. 音视频开发之旅(40)-贝塞尔曲线和曲面

    目录 贝塞尔曲线基本知识 画贝塞尔曲线 让曲线动起来 画贝塞尔曲面 资料 收获 本篇最终实现效果如下: 篇外说明:由于有必要学习使用下kotlin,后续的java层代码实现尽量采用kotlin 一.贝 ...

  4. Bézier曲线 和 Bézier曲面 ( 贝塞尔曲线 和 贝塞尔曲面 )

    Bézier曲线 定义 给定空间n+1个点的位置矢量Pi(i=0,1,2-),则Bezier参数曲线上各点坐标的插值公式是:P(t)=∑i=0nPiBi,n(t),t∈[0,1]P(t)=\sum_{ ...

  5. 光滑曲线_计算机图形学十:贝塞尔曲线与贝塞尔曲面

    贝塞尔曲线与贝塞尔曲面 1 贝塞尔曲线(Bézier Curves) 在进入具体原理讲解之前,首先看一下一条实际的贝塞尔曲线长什么样子 其中 为 控制点,蓝色所表示曲线正是非常著名的贝塞尔曲线了,可以 ...

  6. 贝塞尔曲线与贝塞尔曲面

    1. 贝塞尔曲线(Bézier Curves) 在进入具体原理讲解之前,首先看一下一条实际的贝塞尔曲线长什么样子 其中为控制点,蓝色所表示曲线正是非常著名的贝塞尔曲线了,可以从图中观察到,曲线会与初始 ...

  7. 贝塞尔曲线和贝塞尔曲面_TimelineMax:处理贝塞尔(Bézier)补间

    贝塞尔曲线和贝塞尔曲面 当您需要高级功能时,GSAP插件非常有用. 我将在本教程中解释的BezierPlugin可以帮助沿定义为点/值数组的弯曲贝塞尔曲线路径上的几乎任何一个或多个属性设置动画. 在跳 ...

  8. 图形学实验三 贝塞尔曲线、旋转曲面、扫掠曲面

    实验三 实验要求: 本次实验的内容主要为:绘制下面三种形状. 贝塞尔曲线的绘制 Surfaces of revolution Sweep Surfaces 实现思路及实现结果: 1.贝塞尔曲线 用鼠标 ...

  9. 计算机图形学十:几何2—贝塞尔曲线(Bézier Curves)与贝塞尔曲面(Bézier Surfaces)

    贝塞尔曲线与贝塞尔曲面 1 贝塞尔曲线(Bézier Curves) 2 贝塞尔曲面(Bézier Surfaces) Reference (本篇文章同步发表于知乎专栏:https://zhuanla ...

最新文章

  1. java mysql乐观锁_java乐观锁使用
  2. 东北黑木耳 微信公共帐号 销售 批发 分享 交流 东北鸿顺山特产品有限公司
  3. maven项目没有错,但是在项目头上有红叉的解决方法
  4. .NET Core使用EF分页查询数据报错:OFFSET语法错误问题
  5. 如何判断设备是上电复位还是软复位(主动调用复位接口或者看门狗复位,W600)
  6. 两个例子详解并发编程的可见性问题和有序性问题,通过volatile保证可见性和有序性以及volatile的底层原理——缓存一致性协议MESI和内存屏障禁止指令重排
  7. ADSL之PPPOE
  8. FreeRTOS列表
  9. LINUX的一些简单命令 时间修改
  10. Linux下rz,sz与ssh的配合使用
  11. Linux操作系统内核源码目录结构详解
  12. 计算最大子段(分治法)
  13. JAVA 基础语法(六)——方法(函数)
  14. 《Java 8 实战》 学习笔记一(行为参数化)
  15. excel查询mysql数据库表,?如何通过Excel查询MySQL数据库
  16. 2022年小游戏----游戏背包系统之搭建背包UI
  17. 陶哲轩实分析 6.4 节习题试解
  18. 智能园区中的身份识别的原理是什么?
  19. MPI: 虚拟拓扑和近邻通信
  20. Linux IPC:命名管道的使用

热门文章

  1. CSS选择器常见用法总结
  2. 问题 A: 电路维修
  3. 《概率论与数理统计》期末考试卷
  4. 用java简单写一个信息管理系统(尚硅谷项目二)
  5. android Canvas OpenGLES
  6. 基于python-实训基地管理系统-django框架计算机毕业设计源码+系统+数据库+lw文档+调试部署
  7. springboot 接受数组对象
  8. 发现微创软件在我心目中排全国第一的一个理由
  9. 【CSS样式按钮点击的样式,按钮被点击时的样式】
  10. 希捷1TB硬盘变31MB问题解决