之前想在播放器上加一个那种卡顿的转转提示:
类似:
https://github.com/lsjwzh/MaterialLoadingProgressBar
这种效果的
由于当时没想到怎么在opengl es上实现,所以就没有做这个效果,后来有时间又去
研究了一下,好像这种效果会有一个加速减速的过程,我这里是匀速的,需要的话也可以再改改
下面上代码:
最主要的绘制代码是这个Ring
1 package com.example.zhongchangwen.openglescircleprogressbar; 2 3 import android.opengl.GLES20; 4 5 import java.nio.ByteBuffer; 6 import java.nio.ByteOrder; 7 import java.nio.FloatBuffer; 8 9 /** 10 * Created by zhongchangwen on 2017/3/17. 11 */ 12 13 public class Ring { 14 private FloatBuffer vertexBuffer; 15 16 private final String vertexShaderCode = 17 "uniform mat4 uMVPMatrix;" + 18 "attribute vec4 vPosition;" + 19 "void main() {" + 20 " gl_Position = uMVPMatrix * vPosition;" + 21 "}"; 22 23 private final String fragmentShaderCode = 24 "precision mediump float;" + 25 "uniform vec4 vColor;" + 26 "void main() {" + 27 " gl_FragColor = vColor;" + 28 "}"; 29 private final int mProgram; 30 31 private int mPositionHandle; 32 private int mColorHandle; 33 private int mMVPMatrixHandle; 34 35 private int vertexCount = 360 * 2; 36 private float radius = 1.0f; 37 // Outer vertices of the circle 38 private int outerVertexCount = vertexCount / 2 - 1; 39 40 static final int COORDS_PER_VERTEX = 3; 41 private float ringCoords[] = new float[vertexCount * COORDS_PER_VERTEX]; // (x,y,z) for each vertex 42 private final int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertex 43 44 ByteBuffer bb = ByteBuffer.allocateDirect(ringCoords.length * 4); 45 private float mProgressArc = 1 / 6.0f; 46 private boolean positive = true; 47 private float position = 0.0f; 48 private int mRepeat = 0;//重复次数,六次一个周期 49 private float mRadius = 0.5f;//半径 51 float color[] = {0.63671875f, 0.76953125f, 0.22265625f, 1.0f}; 52 53 public Ring() { 54 55 bb.order(ByteOrder.nativeOrder()); 56 57 generateVertex(mProgressArc); 58 59 // create empty OpenGL ES Program 60 mProgram = Utils.initProgram(vertexShaderCode, fragmentShaderCode); 61 } 62 63 private void generateVertex(float progressArc) { 64 float center_x = 0.0f; 65 float center_y = 0.0f; 66 int idx = 0; 67 68 if (positive) { 69 for (int i = 0; i < outerVertexCount; ++i) { 70 float percent = (i / (float) (outerVertexCount - 1)); 71 float rad = (float) (percent * Math.PI * progressArc) + position; 72 73 //Vertex position 74 float outer_x = (center_x + radius * (float) Math.cos(rad)) * mRadius; 75 float outer_y = (center_y + radius * (float) Math.sin(rad)) * mRadius; 76 77 ringCoords[idx++] = outer_x; 78 ringCoords[idx++] = outer_y; 79 ringCoords[idx++] = 3.0f; 80 81 ringCoords[idx++] = outer_x; 82 ringCoords[idx++] = outer_y; 83 ringCoords[idx++] = 5.0f; 84 } 85 } else { 86 for (int i = 0; i < outerVertexCount; ++i) { 87 float percent = (i / (float) (outerVertexCount - 1)); 88 float rad = (float) (percent * Math.PI * progressArc) + (11 / 6.0f - mProgressArc) * (float) Math.PI + position; 89 90 //Vertex position 91 float outer_x = (center_x + radius * (float) Math.cos(rad))*0.5f; 92 float outer_y = (center_y + radius * (float) Math.sin(rad))*0.5f; 93 94 ringCoords[idx++] = outer_x; 95 ringCoords[idx++] = outer_y; 96 ringCoords[idx++] = 3.0f; 97 98 ringCoords[idx++] = outer_x; 99 ringCoords[idx++] = outer_y; 100 ringCoords[idx++] = 5.0f; 101 } 102 103 } 104 105 vertexBuffer = bb.asFloatBuffer(); 106 vertexBuffer.put(ringCoords); 107 vertexBuffer.position(0); 108 109 if (positive) { 110 mProgressArc += 0.01f; 111 } else { 112 mProgressArc -= 0.01f; 113 } 114 115 if (mProgressArc >= 11 / 6.0f) { 116 positive = false; 117 } 118 if (mProgressArc <= 1 / 6.0f) { 119 positive = true; 120 mRepeat++; 121 position = -1 / 3.0f * (float) Math.PI * mRepeat; 122 if (mRepeat >= 6) 123 mRepeat = 0; 124 } 125 } 126 127 public void draw(float[] mvpMatrix) { 128 // Add program to OpenGL ES environment 129 GLES20.glUseProgram(mProgram); 130 131 // get handle to vertex shader's vPosition member 132 mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition"); 133 134 // Enable a handle to the triangle vertices 135 GLES20.glEnableVertexAttribArray(mPositionHandle); 136 137 //refresh the ring's state 138 generateVertex(mProgressArc); 139 140 // Prepare the triangle coordinate data 141 GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX, 142 GLES20.GL_FLOAT, false, 143 vertexStride, vertexBuffer); 144 145 // get handle to fragment shader's vColor member 146 mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor"); 147 148 // Set color for drawing the triangle 149 GLES20.glUniform4fv(mColorHandle, 1, color, 0); 150 151 // get handle to shape's transformation matrix 152 mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix"); 153 154 // Pass the projection and view transformation to the shader 155 GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0); 156 157 // Draw the ring 158 GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, vertexCount); 159 160 // Disable vertex array 161 GLES20.glDisableVertexAttribArray(mPositionHandle); 162 } 163 }
主要就是计算好环上面的顶点,然后按照画三角形的方法绘制
原理不难,主要是重复对顶点的计算。
mProgressArc * PI 是环的弧度,这里取1/6*PI 到 11/6*PI
positive 表示绘制方向,true表示顺时针绘制,false表示逆时针绘制
然后:
在渲染类里面处理一下投影的效果:
1 public void onDrawFrame(GL10 unused){ 2 // Redraw background color 3 GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); 4 5 // Set the camera position (View matrix) 6 Matrix.setLookAtM(mViewMatrix, 0, 0, 0, -3, 0f, 0f, 0f, 0f, 1.0f, 0.0f); 7 8 // Calculate the projection and view transformation 9 Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0); 10 11 float[] scratch = new float[16]; 12 //set the animation cycle time to 1 second; 1000ms * 0.360 == 360 degree 13 long time = SystemClock.uptimeMillis() % 1000L; 14 //positive is anticlockwise; negative is clockwise 15 float angle = -0.360f * ((int) time); 16 17 Matrix.setRotateM(mRotationMatrix, 0, angle, 0, 0, -1.0f); 18 Matrix.multiplyMM(scratch, 0, mMVPMatrix, 0, mRotationMatrix, 0); 19 20 // Draw shape 21 mRing.draw(scratch); 22 }
mRing.draw(scratch);表示图像会随着时间而进行旋转
旋转的速度可以通过
long time = SystemClock.uptimeMillis() % 1000L;
float angle = -0.360f * ((int) time);
控制这个表示1秒旋转360度
long time = SystemClock.uptimeMillis() % 2000L;
float angle = -0.180f ((int)time);
表示两秒转360度
mRing.draw(mMVPMatrix);
表示不加旋转的原本动画
附上github地址:
https://github.com/george-cw/OpenGLESCircleProgressBar