以前想在播放器上加一個那種卡頓的轉轉提示:java
相似:android
https://github.com/lsjwzh/MaterialLoadingProgressBargit
這種效果的github
因爲當時沒想到怎麼在opengl es上實現,因此就沒有作這個效果,後來有時間又去ide
研究了一下,好像這種效果會有一個加速減速的過程,我這裏是勻速的,須要的話也能夠再改改動畫
下面上代碼:spa
最主要的繪製代碼是這個Ringcode
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 }
主要就是計算好環上面的頂點,而後按照畫三角形的方法繪製orm
原理不難,主要是重複對頂點的計算。blog
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);表示圖像會隨着時間而進行旋轉
![](http://static.javashuo.com/static/loading.gif)
旋轉的速度能夠經過
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