说到贝塞尔曲线,大家肯定都不陌生,网上有很多关于介绍和理解贝塞尔曲线的优秀文章和动态图。
以下两个是比较经典的动图了。
二阶贝塞尔曲线:
三阶贝塞尔曲线:
由于在工作中经常要和贝塞尔曲线打交道,所以简单说一下自己的理解:
现在假设我们要在坐标系中绘制一条直线,直线的方程很简单,就是 y=x
,很容易得到下图:
现在我们限制一下 x 的取值范围为 0~1
的闭区间,那么可以得出 y 的取值范围也是 0~1
。
而在 0~1
的区间范围内,x 能取的数有多少个呢?答案当然是无数个了。
同理,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 的取值范围内对应的无数个点组成的。
反观贝塞尔曲线方程以及对应的图形如下:
不难理解,假设我们要绘制一条曲线,肯定要有起始和结束点来指定曲线的范围曲线。
而控制点就是指定该曲线的弧度,或者说指定该曲线的弯曲走向,不同的控制点得出的曲线绘制结果是不一样的。
另外,可以观察到,无论是几阶贝塞尔曲线,都会有参数 t 以及 t 的取值范围限定。
t 在 0~1 范围的闭区间内,那么 t 的取值个数实际上就有无数个了,这时的 t 就可以理解成上面介绍直线中讲到的 x 。
这样一来,就可以把起始点、控制点当初固定参数,那么贝塞尔曲线计算公式就成了 B = F(t) ,B 是关于 t 的函数,而 t 的取值范围为 0~1 的闭区间。
也就是说贝塞尔曲线,选定了起始点和控制点,照样可以看成是 t 在 0~1 闭区间内对应的无数个点所组成的。
有了上面的阐述,在工(ban)程(zhuan)的角度上,就不难理解贝塞尔曲线到底怎么使用了。
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 可以实现我们上述的方案,把曲线拆分成多个点组成。这种方案要求我们在 CPU 上去计算贝塞尔曲线方程,根据 t 的每一个取值,计算出一个贝塞尔点,用 OpenGL 去绘制上这个点。
这个点的绘制可以采用 OpenGL 中画三角形 GL_TRIANGLES
的形式去绘制,这样就可以给点带上纹理效果,不过这里面的坑略多,起始点和控制点都是运行时动态可变的实现难度会大于固定不变的。
这里先介绍另一种方案,这种方案实现比较简单也能达到优化效果,我们可以把贝塞尔曲线的计算方程式交给 GPU, 在 OpenGL Shader 中去完成。
这样一来,我们只要给定起始点和控制点,中间计算贝塞尔曲线去填补点的过程就交给 Shader 去完成了。
另外,通过控制 t 的数量,我们可以控制贝塞尔点填补的疏密。
t 越大,填补的点越多,超过一定阈值后,不会对绘制效果有提升,反而影响性能。
t 越小,那么贝塞尔曲线就退化成一串点组成了。所以说 t 的取值范围也能对绘制起到优化作用。
绘制效果如下图所示:
以下就是实际的代码部分了,关于 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;
9
10void 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 }
以上函数就是把 t 在 0~1 闭区间分成 Const.NUM_POINTS
份,每一份的值都存在 tData 数组中,最后通过 glVertexAttribPointer
函数传递给 Shader 。
最后实际绘制时,我们采用 GL_POINTS
的形式绘制就好了。
1 GLES20.glDrawArrays(GLES20.GL_POINTS, 0, Const.NUM_POINTS );
以上就是 OpenGL 绘制贝塞尔曲线的小实践。
具体的代码部分可以参考我的项目:
https://github.com/glumes/AndroidOpenGLTutorial
在参考中,也有一个 OpenGL 绘制贝塞尔曲线的例子,不过他绘制的是贝塞尔曲线面,采用的是 GL_TRIANGLES
的形式,而且在 tData
数组的构造也有些不同,但是都大同小异了,看明白了本文的例子也不难理解参考的文章。
参考
本文由哈喽比特于3年以前收录,如有侵权请联系我们。
文章来源:https://mp.weixin.qq.com/s/vbkx2IHpIdfKJRlTl_CejQ
京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。
日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。
据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。
今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。
日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。
近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。
据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。
9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...
9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。
据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。
特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。
据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。
近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。
据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。
9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。
《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。
近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。
社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”
2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。
罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。