OpenGL绘制Bezier曲线的方法

 更新时间:2020年04月20日 14:37:19   作者:process-z.com  
这篇文章主要为大家详细介绍了OpenGL绘制Bezier曲线的方法,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

本文实例为大家分享了OpenGL绘制Bezier曲线的具体代码,供大家参考,具体内容如下

项目要求:

– 使用鼠标在屏幕中任意设置控制点,并生成曲线

– 使用鼠标和键盘的交互操作实现对曲线的修改。

项目总体介绍

本项目利用Bezier曲线生成算法生成可由用户自定义的曲线。可实现核心功能如下:

1、用户用鼠标左击屏幕任意处产生记录点。

2、鼠标右击屏幕任意处由先前的任意个数记录点和其先后关系生成Bezier曲线。

另有辅助输入功能:

1、按键盘‘C'键可清除所有记录点。

2、按键盘‘R'键可清除上一个记录点。

3、按键盘‘Q'键可推出程序。

项目设计思路

1、Bezier曲线介绍:

贝塞尔曲线就是这样的一条曲线,它是依据四个位置任意的点坐标绘制出的一条光滑曲线。在历史上,研究贝塞尔曲线的人最初是按照已知曲线参数方程来确定四个点的思路设计出这种矢量曲线绘制法。1962年,法国数学家Pierre Bézier第一个研究了这种矢量绘制曲线的方法,并给出了详细的计算公式,因此按照这样的公式绘制出来的曲线就用他的姓氏来命名是为贝塞尔曲线。

2、生成公式:

(1)线性公式(只有两个点情况)

给定点P0、P1,线性贝兹曲线只是一条两点之间的直线。这条线由下式给出:

且其等同于线性插值。

(2)二次方公式(三个点组成)

二次方贝兹曲线的路径由给定点P0、P1、P2的函数B(t)追踪:

TrueType字型就运用了以贝兹样条组成的二次贝兹曲线。

(3)三次方公式(四个点)

P0、P1、P2、P3四个点在平面或在三维空间中定义了三次方贝兹曲线。曲线起始于P0走向P1,并从P2的方向来到P3。一般不会经过P1或P2;这两个点只是在那里提供方向资讯。P0和P1之间的间距,决定了曲线在转而趋进P3之前,走向P2方向的“长度有多长”。

曲线的参数形式为:

现代的成象系统,如PostScript、Asymptote和Metafont,运用了以贝兹样条组成的三次贝兹曲线,用来描绘曲线轮廓。

(4)一般参数公式(n个点)

阶贝兹曲线可如下推断。给定点P0、P1、…、Pn,其贝兹曲线即:

N阶的贝兹曲线,即N-1阶贝兹曲线之间的插值。

#include<stdlib.h>
#include<stdio.h>
#include<math.h>
#include<GL/glut.h>
//定义控制点数目的最大值
#define MAX_CPTX 25 
int ncpts=0;//实际控制点个数
static int width=600,height=600;//窗口大小
typedef struct
{
 GLfloat x,y;
} POINT;
POINT cpts[MAX_CPTX];//存储控制点坐标
//求n!
int JieCheng(int n)
{
 if(n==1||n==0)
 {
 return 1;
 }
 else
 {
 return n*JieCheng(n-1);
 }
}
//求组合排列
double C(int n,int i)
{
 return ((double)JieCheng(n))/((double)(JieCheng(i)*JieCheng(n-i)));
}
//求一个数u的num次方
double N(double u,int n)
{
 double sum=1.0;
 if (n==0)
 {
 return 1;
 }
 for(int i=0;i<n;i++)
 {
 sum*=u;
 }
 return sum;
}
 
//绘制bezier曲线
void drawBezier(POINT *p)
{ 
 void display();
 if(ncpts<=0) return; 
 
 POINT *p1;
 p1=new POINT[1000];
 GLfloat u=0,x,y;
 int i,num=1;
 p1[0]=p[0];
 for(u=0;u<=1;u=u+0.001)
 { 
 x=0;
 y=0;
 for(i=0;i<ncpts;i++)
 { 
  x+=C(ncpts-1,i)*N(u,i)*N((1-u),(ncpts-1-i))*p[i].x;
  y+=C(ncpts-1,i)*N(u,i)*N((1-u),(ncpts-1-i))*p[i].y;
 }
 p1[num].x=x;
 p1[num].y=y;
 num++;
 } 
 
  glPointSize(4.0);
  glColor3f(0.0,0.0,0.0);
  glBegin(GL_LINE_STRIP);
  for(int k=0;k<1000;k++)
 glVertex2f(p1[k].x,p1[k].y);
  glEnd();
  glFlush();
 return;
}
 
 
 
//输入新的控制点
static void mouse(int button, int state,int x,int y)
{
void display();
float wx,wy;
//鼠标未按下左键,不做响应
if(state!=GLUT_DOWN)
 return;
else 
 {if(button==GLUT_LEFT_BUTTON)
 {
//转换坐标
wx=(2.0*x)/(float)(width-1)-1.0;
wy=(2.0*(height-1-y))/(float)(height-1)-1.0;
//判断控制点数目是否超过最大值
if(ncpts==MAX_CPTX)
 return;
//存储控制点
cpts[ncpts].x=wx;
cpts[ncpts].y=wy;
ncpts++;
//绘制控制点
glColor3f(0.0,0.0,0.0);
glPointSize(5.0);
glBegin(GL_POINTS);
glVertex2f(wx,wy);
glEnd();
glFlush();
}
if(button==GLUT_RIGHT_BUTTON)
{
display();
drawBezier(cpts);
}
}
}
void display(void)
{
 int i;
 glClear(GL_COLOR_BUFFER_BIT);
 glColor3f(0.0,0.0,0.0);
 glPointSize(5.0);
 glBegin(GL_POINTS);
 for (i = 0; i < ncpts; i++)
  glVertex2f(cpts[i].x,cpts[i].y);
 glEnd();
 glFlush();
 
}
//键盘回调函数
void keyboard(unsigned char key,int x,int y)
{
 switch (key)
 {
  case 'q': case 'Q':
   exit(0);
   break;
  case 'c': case 'C':
 ncpts = 0;
 glutPostRedisplay();
   break;
 case 'r': case 'R':
 ncpts--;
 glutPostRedisplay();
 break;
 }
}
 
//重绘函数
void reshape(int w,int h)
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-1.0,1.0,-1.0,1.0,-1.0,1.0);
glMatrixMode(GL_MODELVIEW);
glViewport(0,0,w,h);//调整视口
width=w;
height=h;
}
int main(int argc, char **argv)
{
//初始化
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_RGB);
glutInitWindowSize(width,height);
glutCreateWindow("zjc2012211763");
//注册回调函数
glutDisplayFunc(display);
glutMouseFunc(mouse);
glutKeyboardFunc(keyboard);
glutReshapeFunc(reshape);
glClearColor(1.0,1.0,1.0,1.0);
glColor3f(0.0,0.0,0.0);
glutMainLoop();
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • 用C语言实现贪吃蛇小游戏

    用C语言实现贪吃蛇小游戏

    这篇文章主要为大家详细介绍了用C语言实现贪吃蛇小游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-05-05
  • VS Code C/C++环境配置教程(无法打开源文件“xxxxxx.h”或者检测到 #include 错误,请更新includePath)(POSIX API)

    VS Code C/C++环境配置教程(无法打开源文件“xxxxxx.h”或者检测到 #include 错误,请更新in

    这篇文章主要介绍了VS Code C/C++环境配置教程(无法打开源文件“xxxxxx.h” 或者 检测到 #include 错误。请更新includePath) (POSIX API),本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-08-08
  • C语言实现C++继承和多态的代码分享

    C语言实现C++继承和多态的代码分享

    本文主要给大家简单讲诉了C和C++的区别以及如何使用C语言模拟实现C++继承和多态,并附上示例代码,是篇相当不错的文章,推荐给喜欢C语言的小伙伴们
    2017-07-07
  • C语言中设置进程优先顺序的方法

    C语言中设置进程优先顺序的方法

    这篇文章主要介绍了C语言中设置进程优先顺序的方法,包括setpriority()函数和getpriority()函数以及nice()函数,需要的朋友可以参考下
    2015-08-08
  • C++ 实现2048游戏示例

    C++ 实现2048游戏示例

    《2048》是比较流行的一款数字游戏。原版2048首先在github上发布,原作者是Gabriele Cirulli。它是基于《1024》和《小3传奇》的玩法开发而成的新型数字游戏。
    2014-06-06
  • mfc入门教程之通过控制变量制作计算器

    mfc入门教程之通过控制变量制作计算器

    这篇文章主要介绍了mfc入门教程之通过控制变量制作计算器,非常不错,具有一定的参考借鉴价值,需要的朋友可以参考下
    2019-04-04
  • 深入理解C++之策略模式

    深入理解C++之策略模式

    下面小编就为大家带来一篇深入理解C++之策略模式。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-06-06
  • C语言二进制思想以及数据的存储

    C语言二进制思想以及数据的存储

    本文主要介绍了C语言的二进制思想以及数据的存储,这里对二进制和数据存储做了详细的说明,对开始学习C语言的同学比较有参考价值
    2016-07-07
  • C++实现点云添加高斯噪声功能

    C++实现点云添加高斯噪声功能

    所谓高斯噪声是指它的概率密度函数服从高斯分布(即正态分布)的一类噪声,这篇文章主要给大家介绍了关于C++实现点云添加高斯噪声功能的相关资料,需要的朋友可以参考下
    2021-07-07
  • 关于C++为什么不加入垃圾回收机制解析

    关于C++为什么不加入垃圾回收机制解析

    C++为什么不加入垃圾回收机制呢?现在肯定还有很多人不太了解,不过没关系,下面小编就为大家详细的介绍下究竟C++为什么不加入垃圾回收机制。一起跟随小编过来看看吧
    2017-01-01

最新评论