• Android 基于OpenGL ES2.0 的CircleProgressBar


    之前想在播放器上加一个那种卡顿的转转提示:

    类似:

    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

  • 相关阅读:
    计算机考研复试真题 数字求和
    计算机考研复试真题 简单计算器
    计算机考研复试真题 N阶楼梯上楼问题
    P1082 [NOIP2012 提高组] 同余方程
    进制转换
    浮点数加法
    N的阶乘
    1055 The World's Richest (25 分)
    1028 List Sorting (25 分)
    1062 Talent and Virtue (25 分)
  • 原文地址:https://www.cnblogs.com/george-cw/p/6586983.html
Copyright © 2020-2023  润新知