前一阵子通过android.graphics.Camera实现翻牌效果,看源码知道是3x3的矩阵,我就想opengles也可以实现,然后就开始动手了
首先设置初始矩阵

Matrix.perspectiveM(projectionMatrix, 0, 90f, 1,  1, 50);Matrix.setLookAtM(viewMatrix, 0,        0.0f, 0.0f, 1.0f,        0.0f, 0.0f,0.0f,        0.0f, -1.0f, 0.0f);

perspectiveM设置摄像机视角矩阵,setLookAtM设置摄像头矩阵
旋转

Matrix.multiplyMM(modelMatrix, 0, projectionMatrix, 0, viewMatrix, 0);if(radian > 90){    Matrix.rotateM(modelMatrix,0,radian - 180,rx,ry,0);}else{    Matrix.rotateM(modelMatrix,0,radian,rx,ry,0);}

沿着x轴旋转或沿着y轴旋转,当角度等于90度的时候会消失掉,大于90度的时候会变为镜像,所以反一下就正常了
不过有点问题,设置GLES20.glViewport(0,0, width, height);的时候超出的部分看不见了
没办法,就把glViewport宽高扩大一倍,然后把显示部分居中

2018/11/9更新

这方法不行,在fbo模式下不能用,所以换了,具体看完整代码

private Rect rect = new Rect();public void setRect(int x,int y,int showWidth,int showHeight,int screenWidth,int screenHeight){    int top = screenHeight - showHeight - y - showHeight/2;    int left = x - showWidth/2;    int right = showWidth*2;    int bottom = showHeight*2;    rect.set(left,top,right,bottom);}
GLES20.glViewport(rect.left, rect.top, rect.right, rect.bottom);

setLookAtM也要改一下

Matrix.setLookAtM(viewMatrix, 0,        0.0f, 0.0f, 2.0f,        0.0f, 0.0f,0.0f,        0.0f, -1.0f, 0.0f);

看看效果

和安卓自定义View进阶-Matrix Camera这篇里提到的bug一样,而opengles的矩阵是4x4的,和android.graphics.Camera的不一样,不过通过这篇文章的思路在Matrix.scaleM()的源码内很快就找到了

modelMatrix[3] = modelMatrix[3]/scale;modelMatrix[7] = modelMatrix[7]/scale;

看看效果

接下来贴代码,懒得上传了

ShaderUtils.java

public class ShaderUtils {    private static final String TAG = "ShaderUtils";    public static void checkGlError(String label) {        int error;        while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {            Log.e(TAG, label + ": glError " + error);            throw new RuntimeException(label + ": glError " + error);        }    }    public static int createProgram(String vertexSource, String fragmentSource) {        int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexSource);        if (vertexShader == 0) {            return 0;        }        int pixelShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource);        if (pixelShader == 0) {            return 0;        }        int program = GLES20.glCreateProgram();        if (program != 0) {            GLES20.glAttachShader(program, vertexShader);            checkGlError("glAttachShader");            GLES20.glAttachShader(program, pixelShader);            checkGlError("glAttachShader");            GLES20.glLinkProgram(program);            int[] linkStatus = new int[1];            GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0);            if (linkStatus[0] != GLES20.GL_TRUE) {                Log.e(TAG, "Could not link program: ");                Log.e(TAG, GLES20.glGetProgramInfoLog(program));                GLES20.glDeleteProgram(program);                program = 0;            }        }        return program;    }    public static int loadShader(int shaderType, String source) {        int shader = GLES20.glCreateShader(shaderType);        if (shader != 0) {            GLES20.glShaderSource(shader, source);            GLES20.glCompileShader(shader);            int[] compiled = new int[1];            GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0);            if (compiled[0] == 0) {                Log.e(TAG, "Could not compile shader " + shaderType + ":");                Log.e(TAG, GLES20.glGetShaderInfoLog(shader));                GLES20.glDeleteShader(shader);                shader = 0;            }        }        return shader;    }    public static String readRawTextFile(Context context, int resId) {        InputStream inputStream = context.getResources().openRawResource(resId);        try {            BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));            StringBuilder sb = new StringBuilder();            String line;            while ((line = reader.readLine()) != null) {                sb.append(line).append("\n");            }            reader.close();            return sb.toString();        } catch (IOException e) {            e.printStackTrace();        }        return null;    }}

bitmap_fragment_sharder.glsl

precision mediump float;varying vec2 vTexCoord;uniform sampler2D sTexture;void main() {    gl_FragColor = texture2D(sTexture,vTexCoord);}

bitmap_vertext_shader.glsl

attribute vec4 aPosition;attribute vec2 aTexCoord;varying vec2 vTexCoord;uniform mat4 uMatrix;void main() {    vTexCoord=aTexCoord;    gl_Position = uMatrix*aPosition;}

EGLUtils.java

public class EGLUtils {    private static final int EGL_RECORDABLE_ANDROID = 0x3142;    private EGLSurface eglSurface = EGL14.EGL_NO_SURFACE;    private EGLContext eglCtx = EGL14.EGL_NO_CONTEXT;    private EGLDisplay eglDis = EGL14.EGL_NO_DISPLAY;    public void initEGL(Surface surface) {        eglDis = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);        int[] version = new int[2];        EGL14.eglInitialize(eglDis, version, 0, version, 1);        int confAttr[] = {                EGL14.EGL_RED_SIZE, 8,                EGL14.EGL_GREEN_SIZE, 8,                EGL14.EGL_BLUE_SIZE, 8,                EGL14.EGL_ALPHA_SIZE, 8,                EGL14.EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT,                EGL_RECORDABLE_ANDROID, 1,                EGL14.EGL_SAMPLE_BUFFERS, 1,                EGL14.EGL_SAMPLES, 4,                EGL14.EGL_NONE        };        EGLConfig[] configs = new EGLConfig[1];        int[] numConfigs = new int[1];        EGL14.eglChooseConfig(eglDis, confAttr, 0, configs, 0, 1, numConfigs, 0);        int ctxAttr[] = {                EGL14.EGL_CONTEXT_CLIENT_VERSION, 2,// 0x3098                EGL14.EGL_NONE        };        eglCtx = EGL14.eglCreateContext(eglDis, configs[0], EGL14.EGL_NO_CONTEXT, ctxAttr, 0);        int[] surfaceAttr = {                EGL14.EGL_NONE        };        eglSurface = EGL14.eglCreateWindowSurface(eglDis, configs[0], surface, surfaceAttr, 0);        EGL14.eglMakeCurrent(eglDis, eglSurface, eglSurface, eglCtx);    }    public EGLContext getContext() {        return eglCtx;    }    public void swap() {        EGL14.eglSwapBuffers(eglDis, eglSurface);    }    public void release() {        if (eglSurface != EGL14.EGL_NO_SURFACE) {            EGL14.eglMakeCurrent(eglDis, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_CONTEXT);            EGL14.eglDestroySurface(eglDis, eglSurface);            eglSurface = EGL14.EGL_NO_SURFACE;        }        if (eglCtx != EGL14.EGL_NO_CONTEXT) {            EGL14.eglDestroyContext(eglDis, eglCtx);            eglCtx = EGL14.EGL_NO_CONTEXT;        }        if (eglDis != EGL14.EGL_NO_DISPLAY) {            EGL14.eglTerminate(eglDis);            eglDis = EGL14.EGL_NO_DISPLAY;        }    }}

GLBitmap.java

public class GLBitmap {    private int aPositionHandle;    private int uMatrixHandle;    private int uTextureSamplerHandle;    private int aTextureCoordHandle;    private int programId;    private int textureId;    private FloatBuffer vertexBuffer;    private final float[] vertexData = {            1f, -1f,0,            -1f, -1f,0,            1f, 1f,0,            -1f, 1f,0    };    private FloatBuffer textureVertexBuffer;    private final float[] textureVertexData = {            1f, 0f,//右下            0f, 0f,//左下            1f, 1f,//右上            0f, 1f//左上    };    private final float[] modelMatrix=new float[16];    private final float[] projectionMatrix= new float[16];    private final float[] viewMatrix = new float[16];    private Bitmap bitmap;    private Context context;    public GLBitmap(Context context,int id){        this.context = context;        scale = context.getResources().getDisplayMetrics().density;        vertexBuffer = ByteBuffer.allocateDirect(vertexData.length * 4)                .order(ByteOrder.nativeOrder())                .asFloatBuffer()                .put(vertexData);        vertexBuffer.position(0);        textureVertexBuffer = ByteBuffer.allocateDirect(textureVertexData.length * 4)                .order(ByteOrder.nativeOrder())                .asFloatBuffer()                .put(textureVertexData);        textureVertexBuffer.position(0);        bitmap = BitmapFactory.decodeResource(context.getResources(),id);    }    public void surfaceCreated(){        String vertexShader = ShaderUtils.readRawTextFile(context, R.raw.bitmap_vertext_shader);        String fragmentShader = ShaderUtils.readRawTextFile(context, R.raw.bitmap_fragment_sharder);        programId = ShaderUtils.createProgram(vertexShader, fragmentShader);        aPositionHandle = GLES20.glGetAttribLocation(programId, "aPosition");        uMatrixHandle=GLES20.glGetUniformLocation(programId,"uMatrix");        uTextureSamplerHandle=GLES20.glGetUniformLocation(programId,"sTexture");        aTextureCoordHandle=GLES20.glGetAttribLocation(programId,"aTexCoord");        final int[] texture=new int[1];        GLES20.glGenTextures(1,texture,0);        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D,texture[0]);        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);        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);        GLUtils.texImage2D(GLES20.GL_TEXTURE_2D,0,GLES20.GL_RGBA,bitmap,0);                textureId = texture[0];        Matrix.perspectiveM(projectionMatrix, 0, 90f, 1,  1, 50);        Matrix.setLookAtM(viewMatrix, 0,                0.0f, 0.0f, 2.0f,                0.0f, 0.0f,0.0f,                0.0f, -1.0f, 0.0f);        GLES20.glUseProgram(programId);        GLES20.glEnableVertexAttribArray(aPositionHandle);        GLES20.glVertexAttribPointer(aPositionHandle, 2, GLES20.GL_FLOAT, false,                12, vertexBuffer);        GLES20.glEnableVertexAttribArray(aTextureCoordHandle);        GLES20.glVertexAttribPointer(aTextureCoordHandle,2,GLES20.GL_FLOAT,false,8,textureVertexBuffer);        GLES20.glUseProgram(0);    }    private int radian = 0;    public void setRadian(int radian) {        this.radian = radian;    }    private int rx = 0;    private int ry = -1;    public void setType(int type){        if(type == 0){            rx = 0;            ry = -1;            s = 1.6f;        }else{            rx = -1;            ry = 0;            s = 1.5f;        }    }    private Rect rect = new Rect();    public void setRect(int showWidth,int showHeight,int screenWidth,int screenHeight){        int left,top,viewWidth,viewHeight;        float sh = screenWidth*1.0f/screenHeight;        float vh = showWidth*1.0f/showHeight;        if(sh < vh){            left = 0;            viewWidth = screenWidth;            viewHeight = (int)(showHeight*1.0f/showWidth*viewWidth);            top = (screenHeight - viewHeight)/2;        }else{            top = 0;            viewHeight = screenHeight;            viewWidth = (int)(showWidth*1.0f/showHeight*viewHeight);            left = (screenWidth - viewWidth)/2;        }        int w = (int) (viewWidth*s);        int f = (w - viewWidth)/2;        rect.set(left - f,top,w,viewHeight);    }    private float scale = 1;    private float s = 1.6f;    public int getWidth(){        return bitmap.getWidth()/10;    }    public int getHeight(){        return bitmap.getHeight()/10;    }    void surfaceDraw(){        GLES20.glViewport(rect.left, rect.top, rect.right, rect.bottom);        Matrix.multiplyMM(modelMatrix, 0, projectionMatrix, 0, viewMatrix, 0);        if(radian > 90){            Matrix.rotateM(modelMatrix,0,radian - 180,rx,ry,0);        }else{            Matrix.rotateM(modelMatrix,0,radian,rx,ry,0);        }        Matrix.scaleM(modelMatrix,0,1.0f,s,1f);        modelMatrix[3] = modelMatrix[3]/scale;        modelMatrix[7] = modelMatrix[7]/scale;        GLES20.glClearColor(0,0,0,0);        GLES20.glUseProgram(programId);        GLES20.glUniformMatrix4fv(uMatrixHandle,1,false,modelMatrix,0);        GLES20.glActiveTexture(GLES20.GL_TEXTURE0);        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D,textureId);        GLES20.glUniform1i(uTextureSamplerHandle,0);        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D,0);        GLES20.glUseProgram(0);    }}

MainActivity.java

public class MainActivity extends AppCompatActivity {    private Handler bitmapHandler;    private HandlerThread bitmapThread;    private SurfaceView surfaceView;    private EGLUtils eglUtils;    private GLBitmap glBitmapX;//    private GLBitmap glBitmapY;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        SeekBar seekBar = findViewById(R.id.seek_bar);        seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {            @Override            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {                rotate(progress);            }            @Override            public void onStartTrackingTouch(SeekBar seekBar) {            }            @Override            public void onStopTrackingTouch(SeekBar seekBar) {            }        });        glBitmapX = new GLBitmap(this,R.drawable.ic_jn);        glBitmapX.setType(1);//        glBitmapY = new GLBitmap(this,R.drawable.ic_m);//        glBitmapY.setType(1);        bitmapThread = new HandlerThread("AudioMediaCodec");        bitmapThread.start();        bitmapHandler = new Handler(bitmapThread.getLooper());        surfaceView = findViewById(R.id.surface_view);        surfaceView.getHolder().addCallback(new SurfaceHolder.Callback() {            @Override            public void surfaceCreated(final SurfaceHolder holder) {                bitmapHandler.post(new Runnable() {                    @Override                    public void run() {                        eglUtils = new EGLUtils();                        eglUtils.initEGL(holder.getSurface());                        glBitmapX.surfaceCreated();//                        glBitmapY.surfaceCreated();                    }                });            }            @Override            public void surfaceChanged(SurfaceHolder holder, int format, final int width, final int height) {                bitmapHandler.post(new Runnable() {                    @Override                    public void run() {                        glBitmapX.setRect(glBitmapX.getWidth(),glBitmapX.getHeight(),width,height);//                        glBitmapY.setRect(width - glBitmapX.getWidth() - 50,height - glBitmapY.getHeight() - 100,glBitmapY.getWidth(),glBitmapY.getHeight(),width,height);                        GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);                        glBitmapX.surfaceDraw();//                        glBitmapY.surfaceDraw();                        eglUtils.swap();                    }                });            }            @Override            public void surfaceDestroyed(SurfaceHolder holder) {                bitmapHandler.post(new Runnable() {                    @Override                    public void run() {                      eglUtils.release();                    }                });            }        });    }    private void rotate(final int rotate){        bitmapHandler.post(new Runnable() {            @Override            public void run() {                GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);                glBitmapX.setRadian(rotate);                glBitmapX.surfaceDraw();//                glBitmapY.setRadian(rotate);//                glBitmapY.surfaceDraw();                eglUtils.swap();            }        });    }    @Override    protected void onDestroy() {        super.onDestroy();        bitmapThread.quit();        bitmapThread = null;    }}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>                        

 

 

 

更多相关文章

  1. Android底部导航栏之BottomNavigationBar
  2. android UI设计的一些心得与问题解决(无效果图)
  3. Android(安卓)动态控制控件的位置
  4. android的TextView在设置ellipsize可能显示方框的问题
  5. Android(安卓)项目配置之 Version Name & Code
  6. android 动态设置读取文件的编码格式(charset)
  7. 笔记33--ListView和ScrollView点击事件的冲突
  8. 关于EditText的属性和常识
  9. android中 关于listitem 获得焦点时,改变其背景

随机推荐

  1. android 弹出选择框,简单通用弹出选择框
  2. Android图标靠界面的右边的实现
  3. 如何隐藏Android4.0及以上版本的ActionBa
  4. ProgressBar属性小结
  5. Android应用程序调用系统解锁页面
  6. AndroidMainifest标签使用说明3——<acti
  7. Shape使用
  8. Android(安卓)按钮添加单击事件
  9. Android官方入门文档[6]添加Action按钮
  10. Android(安卓)Gradle版本问题