【移动应用开发技术】OpenGL 实践中如何进行贝塞尔曲线绘制_第1页
【移动应用开发技术】OpenGL 实践中如何进行贝塞尔曲线绘制_第2页
【移动应用开发技术】OpenGL 实践中如何进行贝塞尔曲线绘制_第3页
【移动应用开发技术】OpenGL 实践中如何进行贝塞尔曲线绘制_第4页
【移动应用开发技术】OpenGL 实践中如何进行贝塞尔曲线绘制_第5页
免费预览已结束,剩余1页可下载查看

付费下载

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

【移动应用开发技术】OpenGL实践中如何进行贝塞尔曲线绘制

这篇文章给大家介绍OpenGL实践中如何进行贝塞尔曲线绘制,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。说到贝塞尔曲线,大家肯定都不陌生,网上有很多关于介绍和理解贝塞尔曲线的优秀文章和动态图。以下两个是比较经典的动图了。二阶贝塞尔曲线:https://upload-images.jianshu.io/upload_images/3117364-9956fa44b212edf5.jpg?imageMogr2/auto-orient/stripimage三阶贝塞尔曲线:https://upload-images.jianshu.io/upload_images/3117364-25783334f6ab5026.jpg?imageMogr2/auto-orient/stripimage由于在工作中经常要和贝塞尔曲线打交道,所以简单说一下自己的理解:现在假设我们要在坐标系中绘制一条直线,直线的方程很简单,就是y=x,很容易得到下图:https://upload-images.jianshu.io/upload_images/3117364-13d4a2daf7be4b42.png?imageMogr2/auto-orient/strip现在我们限制一下x的取值范围为0~1的闭区间,那么可以得出y的取值范围也是0~1。而在0~1的区间范围内,x能取的数有多少个呢?答案当然是无数个了。https://upload-images.jianshu.io/upload_images/3117364-a18dc102c1d9e7db.png?imageMogr2/auto-orient/strip同理,y的取值个数也是有无数个。每一个x都有唯一的y与之对应,一个(x,y)在坐标系上就是一个点。所以最终得到的0~1区间的线段,实际上是由无数的点组成的。那么这条线段有多长呢?长度是由x的取值范围来决定的,若x的取值为0~2,那么线段就长了一倍。另外,如果x的取值范围不是无数个,而是以0.05的间距从0到1之间递增,那么得到的就是一串点了。由于点是一个理想状态下的描述,在数学上点是没有宽高、没有面积的。但是,如果你在草稿纸上绘制一个点,不管你用到是铅笔、毛笔、水笔还是画笔,一个点总是要占面积的。毛笔画一个点的面积可能需要铅笔画几十个点了。由于点是一个理想状态下的描述,在数学上点是没有宽高、没有面积的。但是,如果你在草稿纸上绘制一个点,不管你用到是铅笔、毛笔、水笔还是画笔,一个点总是要占面积的。毛笔画一个点的面积可能需要铅笔画几十个点了。在实际生活中,如果要以0.05的间距在第一幅坐标系图中画出x在0~1区间的一串点,最终结果就和直接画一条线段没啥差别了。这就是现实和理想的差别了。理想一串点,现实一条线。我们把这个逻辑放到手机屏幕上。手机屏幕上的最小显示单位就是像素了,一个1920*1080的屏幕指的就是各方向上像素点的数量。假如绘制一条和屏幕一样宽的线段,一个点最小就算一个像素,最多也就1080个点了。点占的像素越多,那么实际绘制时需要的点的数量越少,这也算是潜在的优化项了。说完直线,再回到贝塞尔曲线上。曲线和直线都有一个共同点,它们都有各自特定的方程,只不过我们用的直线例子比较简单,既y=x,一眼看出计算结果。直线方程y=x,在数学上可以这么描述:y是关于x的函数,既y=F(x),其中x的取值决定了该直线的长度。根据上面的理解,这个长度的直线实际又是由在x的取值范围内对应的无数个点组成的。反观贝塞尔曲线方程以及对应的图形如下:二阶贝塞尔曲线:其中,P0和P2是起始点,P1是控制点。https://upload-images.jianshu.io/upload_images/3117364-b29c9e4819406e67.png?imageMogr2/auto-orient/striphttps://upload-images.jianshu.io/upload_images/3117364-44e901d2d038c207.png?imageMogr2/auto-orient/strip三阶贝塞尔曲线其中,P0和P3是起始点,P1和P2是控制点。https://upload-images.jianshu.io/upload_images/3117364-b829968810aa931f.png?imageMogr2/auto-orient/striphttps://upload-images.jianshu.io/upload_images/3117364-68586f553102d9c7.png?imageMogr2/auto-orient/strip不难理解,假设我们要绘制一条曲线,肯定要有起始和结束点来指定曲线的范围曲线。而控制点就是指定该曲线的弧度,或者说指定该曲线的弯曲走向,不同的控制点得出的曲线绘制结果是不一样的。另外,可以观察到,无论是几阶贝塞尔曲线,都会有参数t以及t的取值范围限定。t在0~1范围的闭区间内,那么t的取值个数实际上就有无数个了,这时的t就可以理解成上面介绍直线中讲到的x。这样一来,就可以把起始点、控制点当初固定参数,那么贝塞尔曲线计算公式就成了B=F(t),B是关于t的函数,而t的取值范围为0~1的闭区间。也就是说贝塞尔曲线,选定了起始点和控制点,照样可以看成是t在0~1闭区间内对应的无数个点所组成的。也就是说贝塞尔曲线,选定了起始点和控制点,照样可以看成是t在0~1闭区间内对应的无数个点所组成的。有了上面的阐述,在工(ban)程(zhuan)的角度上,就不难理解贝塞尔曲线到底怎么使用了。Android绘制贝塞尔曲线Android自带贝塞尔曲线绘制API,通过Path类的quadTo和cubicTo方法就可以完成绘制。

1

//

构建

path

路径,也就是选取

2

path.reset();

3

path.moveTo(p0x,

p0y);

4

//

绘制二阶贝塞尔曲线

5

path.quadTo(p1x,

p1y,

p2x,

p2y);

6

path.moveTo(p0x,

p0y);

7

path.close();

8

9

//

最后的绘制操作10

canvas.drawPath(path,

paint);这里的绘制实际上就是把贝塞尔曲线计算的方程式交给了Android系统内部去完成了,参数传递上只传递了起始点和控制点。我们可以通过自己的代码来计算这个方程式从而对逻辑上获得更多控制权,也就是把曲线拆分成许多个点组成,如果点的尺寸比较大,甚至可以减少点的个数实现同样的效果,达到绘制优化的目的。OpenGL绘制通过OpenGL可以实现我们上述的方案,把曲线拆分成多个点组成。这种方案要求我们在CPU上去计算贝塞尔曲线方程,根据t的每一个取值,计算出一个贝塞尔点,用OpenGL去绘制上这个点。这个点的绘制可以采用OpenGL中画三角形GL_TRIANGLES的形式去绘制,这样就可以给点带上纹理效果,不过这里面的坑略多,起始点和控制点都是运行时动态可变的实现难度会大于固定不变的。这里先介绍另一种方案,这种方案实现比较简单也能达到优化效果,我们可以把贝塞尔曲线的计算方程式交给GPU,在OpenGLShader中去完成。这样一来,我们只要给定起始点和控制点,中间计算贝塞尔曲线去填补点的过程就交给Shader去完成了。另外,通过控制t的数量,我们可以控制贝塞尔点填补的疏密。t越大,填补的点越多,超过一定阈值后,不会对绘制效果有提升,反而影响性能。t越小,那么贝塞尔曲线就退化成一串点组成了。所以说t的取值范围也能对绘制起到优化作用。绘制效果如下图所示:https://upload-images.jianshu.io/upload_images/3117364-3226705b73d588c2.jpg?imageMogr2/auto-orient/stripimage以下就是实际的代码部分了,关于OpenGL的基础理论部分可以参考之前写过的文章和公众号,就不再阐述了。在Shader中定义一个函数,实现贝塞尔方程:1vec2

fun(in

vec2

p0,

in

vec2

p1,

in

vec2

p2,

in

vec2

p3,

in

float

t){

2

float

tt

=

(1.0

-

t)

*

(1.0

-t);

3

return

tt

*

(1.0

-t)

*p0

4

+

3.0

*

t

*

tt

*

p1

5

+

3.0

*

t

*t

*(1.0

-t)

*p2

6

+

t

*t

*t

*p3;

7}该方程可以利用Shader中自带的函数优化一波:1vec2

fun2(in

vec2

p0,

in

vec2

p1,

in

vec2

p2,

in

vec2

p3,

in

float

t)

2{

3

vec2

q0

=

mix(p0,

p1,

t);

4

vec2

q1

=

mix(p1,

p2,

t);

5

vec2

q2

=

mix(p2,

p3,

t);

6

vec2

r0

=

mix(q0,

q1,

t);

7

vec2

r1

=

mix(q1,

q2,

t);

8

return

mix(r0,

r1,

t);

9}接下来就是具体的顶点着色器shader:

1//

对应

t

数据的传递

2attribute

float

aData;

3//

对应起始点和结束点

4uniform

vec4

uStartEndData;

5//

对应控制点

6uniform

vec4

uControlData;

7//

mvp

矩阵

8uniform

mat4

u_MVPMatrix;

910void

main()

{11

vec4

pos;12

pos.w

=

1.0;13

//

取出起始点、结束点、控制点14

vec2

p0

=

uStartEndData.xy;15

vec2

p3

=

uStartEndData.zw;16

vec2

p1

=

uControlData.xy;17

vec2

p2

=

uControlData.zw;18

//

取出

t

的值19

float

t

=

aData;20

//

计算贝塞尔点的函数调用21

vec2

point

=

fun2(p0,

p1,

p2,

p3,

t);22

//

定义点的

x,y

坐标23

pos.xy

=

point;24

//

要绘制的位置25

gl_Position

=

u_MVPMatrix

*

pos;26

//

定义点的尺寸大小27

gl_PointSize

=

20.0;28}代码中的uStartEndData对应起始点和结束点,uControlData对应两个控制点。这两个变量的数据传递通过glUniform4f方法就好了:

1

mStartEndHandle

=

glGetUniformLocation(mProgram,

"uStartEndData");

2

mControlHandle

=

glGetUniformLocation(mProgram,

"uControlData");

3

//

传递数据,作为固定值

4

glUniform4f(mStartEndHandle,

5

mStartEndPoints[0],

6

mStartEndPoints[1],

7

mStartEndPoints[2],

8

mStartEndPoints[3]);

9

glUniform4f(mControlHandle,10

mControlPoints[0],11

mControlPoints[1],12

mControlPoints[2],13

mControlPoints[3]);另外重要的变量就是aData了,它对应的就是t在0~1闭区间的划分的数量。1

private

float[]

genTData()

{2

float[]

tData

=

new

float[Const.NUM_POINTS];3

for

(int

i

=

0;

i

<

tData.length;

i

++)

{4

float

t

=

(float)

i

/

(float)

tData.length;5

tData[i]

=

t;6

}7

return

tData;8

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论