android opengles 实现翻牌效果 - Go语言中文社区

android opengles 实现翻牌效果


前一阵子通过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"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.hyq.hm.glesrotate3d.MainActivity">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
        <SeekBar
            android:id="@+id/seek_bar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:max="180"
            android:layout_margin="20dp"/>
        <SurfaceView
            android:id="@+id/surface_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    </LinearLayout>

</android.support.constraint.ConstraintLayout>

 

 

 

版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/u010302327/article/details/83657544
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
  • 发表于 2020-06-28 03:56:56
  • 阅读 ( 760 )
  • 分类:

0 条评论

请先 登录 后评论

官方社群

GO教程

推荐文章

猜你喜欢