OpenGL ES is a subset of OpenGL, which is partially simplified for mobile terminal or embedded system. However, Android system integrates OpenGL ES, which facilitates us to fully use the computing and rendering capabilities of GPU through its interface.

OpenGL ES2.0 is based on programmable pipeline design. Compared to OpenGL ES 1.x, OpenGL ES 2.0 is a big change, more flexible, more powerful, and more efficient rendering, better effect. Android supports OpenGL ES as follows:

  • OpenGL ES 1.0 and 1.1 are supported by Android 1.0 and later
  • OpenGL ES 2.0 is supported by Android 2.2 and later
  • OpenGL ES 3.0 is supported by Android 4.3 and later
  • OpenGL ES 3.1 is supported by Android 5.0 and later

By contrast, learning OpenGL ES to choose version 2.0 is a relatively best choice, compatible with 4.0 or higher mobile devices, and OpenGL ES 3.x are backward compatible with OpenGL ES 2.0. This series was demonstrated and developed in OPENGL ES2.0.

Here we focus on two aspects of OpenGL ES:

  • Camera preview effect processing.
  • Video processing.

There are two basic classes in the Android framework that make it easy to create and manipulate shapes using the OpenGL ES API: GLSurfaceView and glSurfaceView.renderer. GLSurfaceView is a special View that manages The OpenGL Surface. It helps us to render the OpenGL surface onto the Android View, and encapsulates a lot of the configuration needed to create an OpenGL environment. It makes it easier to use OpenGL.

The GLSurfaceView.Renderer interface defines the methods needed to draw graphics in the GLSurfaceView. Normally we use GLSurfaceView. SetRenderer () method to set the interface implementation into the GLSurfaceView. This interface method is mainly:

  • OnSurfaceCreated () : This method is called when the GLSurfaceView is created. Use this method to perform operations that need to be performed only once, such as setting OpenGL environment parameters or initializing OpenGL graphics objects.
  • OnDrawFrame () : This method is called every time the GLSurfaceView is redrawn. Use this method as the primary method for drawing graphs.
  • OnSurfaceChanged () : The system calls this method when the GLSurfaceView size or device screen orientation changes. For example, the system calls this method when the device changes from portrait to landscape. We should use this method in response to changes to the GLSurfaceView container.

1. Write shaders (vertex shaders and slice shaders)

Set the version of OpenGL ES to use in the androidmanifest.xml file:

<uses-feature android:glEsVersion="0x00020000" android:required="true" />
Copy the code

To create a GLSurfaceView, set the glSurfaceView.renderer. Next we’ll focus on writing glSurfaceView.renderer.

public class ZkGLSurfaceView extends GLSurfaceView {

    public ZkGLSurfaceView(Context context) {
        this(context,null);
    }

    public ZkGLSurfaceView(Context context, AttributeSet attrs) {
        super(context, attrs);
        //使用OpenGL ES 2.0
        setEGLContextClientVersion(2); / / set the RenderersetRenderer(new MyRenderer(context)); // Set the refresh modesetRenderMode(RENDERMODE_WHEN_DIRTY); }}Copy the code

Fixed point shader

attribute vec4 vPosition;
attribute vec2 vCoordinate;
varying vec2 aCoordinate;
void main() {
    gl_Position = vPosition;
    aCoordinate = vCoordinate;
}
Copy the code

Chip shader

precision mediump float;
uniform sampler2D vTexture;
varying vec2 aCoordinate;
void main() {
    gl_FragColor = texture2D(vTexture,aCoordinate);
}
Copy the code

Gl_Position and gl_FragColor are both built-in variables of the Shader, and are fixed point position and slice color, respectively.

  • Attributes are generally used for quantities that vary from vertex to vertex. Such as vertex color, coordinates, etc

  • Varying is used to transfer the value between vertex and fragment, and is generally used to transfer the amount of vertex shader to the fragment shader

  • Uniform generally applies to the quantity that all vertices in a 3D object are the same. Such as light source position, uniform transformation matrix and so on

2. Set vertex and texture coordinates

// Vertex coordinates privatefloatF [] vertex = {1.0, 1.0, f / / the top left corner - 1.0 f to 1.0 f, / / left corner 1.0 f, 1.0 f / 1.0 f/right corner, 1.0 f / / the bottom right hand corner}; private finalfloat[] sCoord = {0 f, 0 f, / / 0 f the top left hand corner, 1 f, 1 f / / left corner, 0 f, / / the upper right corner of the 1 f, 1 / f/corner}; // Apply the underlying space to convert the coordinate data to FloatBuffer, To the incoming to OpenGL ES program mVertexBuffer = ByteBuffer. AllocateDirect (vertex. Length * 4). The order (ByteOrder. NativeOrder ()) .asFloatBuffer().put(vertex); mVertexBuffer.position(0); mFragmentBuffer = ByteBuffer.allocateDirect(sCoord.length * 4) .order(ByteOrder.nativeOrder()) .asFloatBuffer().put(sCoord); mFragmentBuffer.position(0);Copy the code

Vertex coordinates and texture coordinates must be wrapped in the same direction.

3. Load shaders

int vertex_shader = loadShader(GLES20.GL_VERTEX_SHADER,VERTEX_SHADER); int fragment_shader = loadShader(GLES20.GL_FRAGMENT_SHADER,FRAGMENT_SHADER); Private int loadShader(int glVertexShader, String vertexShader) { Vertex or slice) int glCreateShader = gles20. glCreateShader(glVertexShader); Gles20. glShaderSource(glCreateShader, vertexShader); int[] compiled = new int[1]; Gles20.glgetshaderiv (glCreateShader, gles20.gl_compile_status, compiled, 0);if(compiled[0] ! = GLES20.GL_TRUE){ GLES20.glDeleteShader(glCreateShader);return- 1; }return glCreateShader;
}
Copy the code

4. To create the Program

MProgram = gles20.glCreateProgram (); Gles20.glattachshader (mProgram, vertex_shader); // Add a shader program to the renderer. GLES20.glAttachShader(mProgram, fragment_shader); Gles20.gllinkprogram (mProgram); int[] linkStatus = new int[1]; GLES20.glGetProgramiv(mProgram, GLES20.GL_LINK_STATUS, linkStatus, 0);if(linkStatus[0] ! = GLES20.GL_TRUE){ String info = GLES20.glGetProgramInfoLog(mProgram); GLES20.glDeleteProgram(mProgram); throw new RuntimeException("Could not link program: " + info);
}
Copy the code

5. Create textures

private int loadTexture(int resId){ int[] textures = new int[1]; // Create and bind texture gles20. glGenTextures(1, Textures,0); GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[0]); GlActiveTexture (gles20.gl_texture0); GLES20.glUniform1i(mVTexture, 0); // Set the wrap and filter mode // Wrap (outside the texture coordinate range) : Gles20. glTexParameteri(glES20.gl_TEXture_2d, glES20.gl_TEXture_WRAP_s, glES20.gl_repeat); GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_REPEAT); // Filter (texture pixels mapped to coordinate points) : (Zoom out, zoom out: Gles20. glTexParameteri(glES20.gl_TEXture_2D, glES20.gl_texture_MIN_filter, glES20.gl_linear); GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR); Bitmap bitmap = BitmapFactory.decodeResource(mContext.getResources(), resId); // Set the image glutils.teximage2d (gles20.gl_texture_2d, 0, bitmap, 0); bitmap.recycle(); bitmap = null; Gles20.glbindtexture (gles20.gl_texture_2d, 0);return textures[0];
    }
Copy the code

6. Render images

    @Override
    public void onDrawFrame() { GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); GLES20. GlClearColor (1.0 f, 0, 0, 1 f); Gles20.gluseprogram (mProgram); Gles20.glbindtexture (gles20.gl_texture_2d, mTextureid); / / make effective GLES20 vertex attribute array. GlEnableVertexAttribArray (mVPosition); / / for vertex attribute assignment GLES20 glVertexAttribPointer (mVPosition, 2, GLES20 GL_FLOAT,false, 8, mVertexBuffer);

        GLES20.glEnableVertexAttribArray(mVCoordinate);
        GLES20.glVertexAttribPointer(mVCoordinate, 2, GLES20.GL_FLOAT, false, 8, mFragmentBuffer); Gles20.gldrawarrays (gles20.gl_triangle_strip, 0, 4); Gles20.glbindtexture (gles20.gl_texture_2d, 0); }Copy the code

Complete code:

public class MyRenderer implements GLSurfaceView.Renderer{

    private static final String VERTEX_SHADER = "attribute vec4 vPosition; \n"
            + "attribute vec2 vCoordinate; \n"
            + "varying vec2 aCoordinate; \n"
            + "void main() {\n"
            + "gl_Position = vPosition; \n"
            + "aCoordinate = vCoordinate; \n"
            + "}";

    private static final String FRAGMENT_SHADER = "precision mediump float; \n"
            + "uniform sampler2D vTexture; \n"
            + "varying vec2 aCoordinate; \n"
            + "void main() {\n"
            + "gl_FragColor = texture2D(vTexture,aCoordinate); \n"
            + "}";

    private floatF [] vertex = {1.0, 1.0, f / / the top left corner - 1.0 f to 1.0 f, / / left corner 1.0 f, 1.0 f / 1.0 f/right corner, 1.0 f / / the bottom right hand corner}; private finalfloat[] sCoord = {0 f, 0 f, / / 0 f the top left hand corner, 1 f, 1 f / / left corner, 0 f, / / the upper right corner of the 1 f, 1 / f/corner}; private FloatBuffer mVertexBuffer; private FloatBuffer mFragmentBuffer; private int mProgram; private int mVPosition; private int mVCoordinate; private int mVTexture; private Context mContext; private int mTextureid; public MyRenderer(Context context){ mContext = context; mVertexBuffer = ByteBuffer.allocateDirect(vertex.length * 4) .order(ByteOrder.nativeOrder()) .asFloatBuffer().put(vertex); mVertexBuffer.position(0); mFragmentBuffer = ByteBuffer.allocateDirect(sCoord.length * 4) .order(ByteOrder.nativeOrder()) .asFloatBuffer().put(sCoord); mFragmentBuffer.position(0); } @Override public void onSurfaceCreated(GL10 gl, EGLConfig config) { int vertex_shader = loadShader(GLES20.GL_VERTEX_SHADER,VERTEX_SHADER); int fragment_shader = loadShader(GLES20.GL_FRAGMENT_SHADER,FRAGMENT_SHADER); mProgram = GLES20.glCreateProgram(); GLES20.glAttachShader(mProgram, vertex_shader); GLES20.glAttachShader(mProgram, fragment_shader); GLES20.glLinkProgram(mProgram); int[] linkStatus = new int[1]; GLES20.glGetProgramiv(mProgram, GLES20.GL_LINK_STATUS, linkStatus, 0);if(linkStatus[0] ! = GLES20.GL_TRUE){ String info = GLES20.glGetProgramInfoLog(mProgram); GLES20.glDeleteProgram(mProgram); throw new RuntimeException("Could not link program: " + info);
        }

        mVPosition = GLES20.glGetAttribLocation(mProgram, "vPosition");
        mVCoordinate = GLES20.glGetAttribLocation(mProgram, "vCoordinate");
        mVTexture = GLES20.glGetUniformLocation(mProgram, "vTexture"); mTextureid = loadTexture(R.drawable.fengj); } private int loadTexture(int resId){ int[] textures = new int[1]; // Create and bind texture gles20. glGenTextures(1, Textures,0); GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[0]); GlActiveTexture (gles20.gl_texture0); GLES20.glUniform1i(mVTexture, 0); // Set the wrap and filter mode // Wrap (outside the texture coordinate range) : Gles20. glTexParameteri(glES20.gl_TEXture_2d, glES20.gl_TEXture_WRAP_s, glES20.gl_repeat); GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_REPEAT); // Filter (texture pixels mapped to coordinate points) : (Zoom out, zoom out: Gles20. glTexParameteri(glES20.gl_TEXture_2D, glES20.gl_texture_MIN_filter, glES20.gl_linear); GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR); Bitmap bitmap = BitmapFactory.decodeResource(mContext.getResources(), resId); // Set the image glutils.teximage2d (gles20.gl_texture_2d, 0, bitmap, 0); bitmap.recycle(); bitmap = null; Gles20.glbindtexture (gles20.gl_texture_2d, 0);return textures[0];
    }

    private int loadShader(int glVertexShader, String vertexShader) {
        int glCreateShader = GLES20.glCreateShader(glVertexShader);
        GLES20.glShaderSource(glCreateShader, vertexShader);
        GLES20.glCompileShader(glCreateShader);
        int[] compiled = new int[1];
        GLES20.glGetShaderiv(glCreateShader, GLES20.GL_COMPILE_STATUS, compiled, 0);
        if(compiled[0] ! = GLES20.GL_TRUE){ GLES20.glDeleteShader(glCreateShader);return- 1; }returnglCreateShader; } @Override public void onSurfaceChanged(GL10 gl, int width, int height) { GLES20.glViewport(0, 0, width, height); } @Override public void onDrawFrame(GL10 gl) { GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); GLES20. GlClearColor (1.0 f, 0, 0, 1 f); Gles20.gluseprogram (mProgram); Gles20.glbindtexture (gles20.gl_texture_2d, mTextureid); / / make effective GLES20 vertex attribute array. GlEnableVertexAttribArray (mVPosition); / / for vertex attribute assignment GLES20 glVertexAttribPointer (mVPosition, 2, GLES20 GL_FLOAT,false, 8, mVertexBuffer);

        GLES20.glEnableVertexAttribArray(mVCoordinate);
        GLES20.glVertexAttribPointer(mVCoordinate, 2, GLES20.GL_FLOAT, false, 8, mFragmentBuffer); Gles20.gldrawarrays (gles20.gl_triangle_strip, 0, 4); Gles20.glbindtexture (gles20.gl_texture_2d, 0); }}Copy the code