Android daily learning: Bezier curve drawing OpenGL Practice

Speaking of Bezier curves, I am sure you are not familiar with, there are many online articles about the presentations and the excellent and dynamic view of understanding the Bezier curve.

The following are two of the more classic action figure.

Second-order Bezier curve:

image

Third-order Bezier curve:

image

As often and Bezier curves to deal with at work, so briefly about their own understanding:

Now suppose we want to draw a line in the coordinate system, a simple straight line equation is y = x, it is easy to obtain the following diagram:

image.png

Now we look to limit x ranges from closed interval from 0 to 1, you can obtain the range of y is from 0 to 1.

And in the interval from 0 to 1, x can take a number of how many do? The answer is of course the countless.

image.png

Similarly, the number of the value of y is also numerous. Each has a unique y x corresponding thereto, a (x, y) is a point on the coordinate system.

Therefore section line 0-1 finally obtained, is actually formed by numerous dots.

So how long is this segment of it? Length is in the range of x is determined, if the value of x is 0-2, then twice as long line segments.

Further, if the range of x is not numerous, but a pitch of 0.05 increments from 0 to 1, then the string is the point obtained.

Since a point is described in the ideal state, there is no mathematical point in width and height, there is no area.
However, if you draw a point on rough paper, whether you use a pencil, brush, pen or paintbrush, a point always to occupy the area.
Area brush painting a pencil point may require dozens of points.

In real life, if a pitch of 0.05 x drawn in a coordinate system of the drawing point in a string of 0 to 1 range, and the final result lacks direct draw a line differences.

This is the difference between the ideal and reality. Ideal for a bunch of points, the reality of a line.


We put this logic into the phone screen.

The smallest display units on the phone screen is a pixel, and a 1920 * 1080 screen refers to the number of pixels up parties.

If you draw a line, and as wide as the screen, a minimum even if a pixel point, most will be 1080 points.

The more sites that are pixels, the fewer the number of the actual needs of plotted points, it would be the potential for optimization items.


Then straight, and then back to the Bezier curve.

曲线和直线都有一个共同点,它们都有各自特定的方程,只不过我们用的直线例子比较简单,既 y = x ,一眼看出计算结果。

直线方程 y = x,在数学上可以这么描述:y 是关于 x 的函数,既 y = F(x) ,其中 x 的取值决定了该直线的长度。

根据上面的理解,这个长度的直线实际又是由在 x 的取值范围内对应的无数个点组成的。

反观贝塞尔曲线方程以及对应的图形如下:

  • 二阶贝塞尔曲线:其中,P0 和 P2 是起始点,P1 是控制点。

image.png

image.png

  • 三阶贝塞尔曲线其中,P0 和 P3 是起始点,P1 和 P2 是控制点。

image.png

image.png


不难理解,假设我们要绘制一条曲线,肯定要有起始和结束点来指定曲线的范围曲线。

而控制点就是指定该曲线的弧度,或者说指定该曲线的弯曲走向,不同的控制点得出的曲线绘制结果是不一样的。

另外,可以观察到,无论是几阶贝塞尔曲线,都会有参数 t 以及 t 的取值范围限定。

t 在 0~1 范围的闭区间内,那么 t 的取值个数实际上就有无数个了,这时的 t 就可以理解成上面介绍直线中讲到的 x 。

这样一来,就可以把起始点、控制点当初固定参数,那么贝塞尔曲线计算公式就成了 B = F(t) ,B 是关于 t 的函数,而 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 绘制

Our above-described embodiment can be realized by OpenGL, to split into a plurality of curve points. This solution requires us to calculate the Bezier curve equation up in the CPU, according to each value of t, a Bessel points calculated, using OpenGL to draw at this point.

The plotted points form a triangle drawn in OpenGL GL_TRIANGLES can be used to draw, so that you can bring to the point of texture effects, but there's a pit slightly more difficult to achieve dynamic variable will be the starting point and the control points are running greater than fixed.

Here we introduce another scheme, which is relatively simple optimization can achieve the effect, we can calculate the Bezier curve equation to the GPU, to be completed in OpenGL Shader.

Thus, we only given starting point and a control point Bezier curve is calculated to fill the intermediate point to complete the process on to the Shader.

In addition, by controlling the number of t, we can control the density fill Bezier points.

The larger t, the more filling point, beyond a certain threshold, there will not enhance the effect of the draw, but affect performance.

t is smaller, the Bezier curve degenerates into a series of dots. So the range of t can also play a role in optimizing the drawing.

Plotted results as shown below:

image

The following is the actual code section, and on the basis of the theoretical part of OpenGL written before the public can refer to the article and number, it is no longer elaborated.

Shader define a function, the realization of Bessel's equation:

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}

The wave equation can optimize the use of Shader function comes with:

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}

The next is a specific vertex shader 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 code corresponding to start and end points, uControlData corresponding to two control points.

Data transfer like these two variables by the method 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]); 

Another important variable is the aData, which corresponds to the number of division is 0 to 1 closed interval of t.

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 is to function in the above 0-1 into a closed interval Const.NUM_POINTS parts, a value of each array are present tData, and finally passed to the function glVertexAttribPointer by Shader.

The last real draw, we draw the form GL_POINTS enough.

1 GLES20.glDrawArrays(GLES20.GL_POINTS, 0, Const.NUM_POINTS );

These are the OpenGL Bezier curve drawing little practice.

Guess you like

Origin blog.51cto.com/14606040/2461865