什么是OpenGL?

openGL是一个图形绘制专业编程接口,功能比较强大,可以绘制二维,三维,它与硬件没有关系,也可以在不同的平台上使用,

进行良好的移植,使用较为广泛

分析OpenGL坐标系和android坐标系

openGL的世界左边是从屏幕的中心点是0,0 android 手机中心点是从屏幕左上角开始的如图:

 

android:

android的坐标点要用opengl的方式来显示就要换算成opengl的方式,就像是2长图片的重合坐标上的修改,下面直接撸代码

代码部分:

开始之前,我们需要建立2个文件,一个是顶点着色器,一个是片源着色器

顶点着色器是处理顶点、法线等数据,片元着色器是处理光、阴影、遮挡、环境等等对物体表面的影响,最终生成一副图像

在res下面建立一个文件,camera.vert顶点 camera_planyuan.frag片元

下面介绍一下数据类型:float    浮点型

                                       vec2   含两个浮点型数据的向量

                                      vec4  含四个浮点型数据的向量(xyzw,rgba,stpq)

                                      sampler2D  2D纹理采样器(代表一层纹理)

           内置函数            exture2D (采样器,坐标)  采样指定位置的纹理

           内置变量            顶点   gl_Position      vec4 顶点位置

                                      片元  gl_FragColor   vec4 颜色

顶点着色器代码

// 把顶点坐标给这个变量, 确定要画画的形状attribute vec4 vPosition;//接收纹理坐标,接收采样器采样图片的坐标attribute vec4 vCoord;//变换矩阵, 需要将原本的vCoord(01,11,00,10) 与矩阵相乘 才能够得到 surfacetexure(特殊)的正确的采样坐标uniform mat4 vMatrix;//传给片元着色器 像素点varying vec2 aCoord;void main(){    //内置变量 gl_Position ,我们把顶点数据赋值给这个变量 opengl就知道它要画什么形状了    gl_Position = vPosition;    // 进过测试 和设备有关    aCoord = (vMatrix * vCoord).xy;    //aCoord =  vec2((vCoord*vMatrix).x,(vCoord*vMatrix).y);}

片元着色器代码

#extension GL_OES_EGL_image_external : require//SurfaceTexture比较特殊//float数据是什么精度的precision mediump float;//采样点的坐标varying vec2 aCoord;//采样器uniform samplerExternalOES vTexture;void main(){    //变量 接收像素值    // texture2D:采样器 采集 aCoord的像素    //赋值给 gl_FragColor 就可以了    gl_FragColor = texture2D(vTexture,aCoord);}

然后我们建立一个类,集成GLSurfaceView  来配置一下OPenGL版本信息 setRenderer(new DouyinRenderer(this));这是一个内部接口,我们建立一个实现类,来实现这个接口

package com.note.opengl.widget;import android.content.Context;import android.opengl.GLSurfaceView;import android.util.AttributeSet;import com.note.opengl.DouyinRenderer;/** * Created by m.wang on 2018/11/6. */public class DouyinView extends GLSurfaceView{    public DouyinView(Context context) {        this(context,null);    }    public DouyinView(Context context, AttributeSet attrs) {        super(context, attrs);        /***         * 配置GLSurfaceView         */        //1.首先是设置EGL版本        setEGLContextClientVersion(2);        //设置一个渲染器        setRenderer(new DouyinRenderer(this));        //设置按需加载  连续渲染 就是自动回调onDrawFrame        setRenderMode(RENDERMODE_WHEN_DIRTY);    }}

DouyinRenderer类说明

DouyinRenderer实现内部类 GLSurfaceView.Renderer接口 有三个方法1.onSurfaceCreated创建画布2.onSurfaceChanged画布改变时候会调用3.onDrawFrame开始画画的时候调用

package com.note.opengl;import android.graphics.SurfaceTexture;import android.hardware.Camera;import android.opengl.GLES20;import android.opengl.GLSurfaceView;import com.note.opengl.filter.ScreenFiter;import com.note.opengl.util.CameraHelper;import com.note.opengl.widget.DouyinView;import javax.microedition.khronos.egl.EGLConfig;import javax.microedition.khronos.opengles.GL10;/** * Created by m.wang on 2018/11/6. */public class DouyinRenderer implements GLSurfaceView.Renderer, SurfaceTexture.OnFrameAvailableListener {    private DouyinView mView;    private CameraHelper cameraHelper;    private SurfaceTexture surfaceTexture;    private float[] mtx = new float[16];    private int[] mTextrues;    private ScreenFiter mScreenFiter;    public DouyinRenderer(DouyinView douyinView) {         mView = douyinView;    }    /**     * 创建画布     * @param gl10     * @param eglConfig     */    @Override    public void onSurfaceCreated(GL10 gl10, EGLConfig eglConfig) {        //初始化摄像头        cameraHelper = new CameraHelper(Camera.CameraInfo.CAMERA_FACING_BACK);        //通过openGL 创建一个纹理id        mTextrues = new int[1];        GLES20.glGenTextures(mTextrues.length,mTextrues,0);        //准备摄像头绘制的画布        surfaceTexture = new SurfaceTexture(mTextrues[0]);        surfaceTexture.setOnFrameAvailableListener(this);        mScreenFiter = new ScreenFiter(mView.getContext());    }    /**     * 画布发生改变     * @param gl10     * @param i     * @param i1     */    @Override    public void onSurfaceChanged(GL10 gl10, int i, int i1) {        //开启预览        cameraHelper.starPreview(surfaceTexture);        mScreenFiter.onReady(i,i1);    }    /**     * 开始画画     * @param gl10     */    @Override    public void onDrawFrame(GL10 gl10) {        //画画前清理屏幕 告诉openGL 需要把屏幕清理该改颜色        GLES20.glClearColor(0,0,0,0);        //执行清理功能        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);        //把摄像头的数据取出来 更新纹理 然后才能从openGL从surfacetexure        surfaceTexture.updateTexImage();        //在确立坐标时候获得变化居正        surfaceTexture.getTransformMatrix(mtx);        mScreenFiter.onDrawFrame(mTextrues[0],mtx);    }    /**     * 回调方式是 有一个有效的新数据得时候回调     * @param surfaceTexture     */    @Override    public void onFrameAvailable(SurfaceTexture surfaceTexture) {        mView.requestRender();    }}

以上有两个工具类

1.ScreenFiter是把我们写的两个顶点着色器文件和便宜着色器文件读到String之中来

String vertexSource = OpenUtils.readRawTextFile(context,R.raw.camera);String fragSource = OpenUtils.readRawTextFile(context,R.raw.camera_planyuan);
package com.note.opengl.filter;import android.content.Context;import android.opengl.GLES11Ext;import android.opengl.GLES20;import com.note.opengl.R;import com.note.opengl.util.OpenUtils;import java.nio.ByteBuffer;import java.nio.ByteOrder;import java.nio.FloatBuffer;/** * Created by m.wang on 2018/11/6. * 负责往屏幕上渲染 */public class ScreenFiter {    private int mProgram;    private int mWidth;    private int mHieght;    private int vPosition;    private int vCoord;    private int vMatrix;    private int vTexture;    private FloatBuffer mVertexBuffer;    private FloatBuffer mTextureBuffer;    public ScreenFiter(Context context){        //获取顶点着色器 读出来        String vertexSource = OpenUtils.readRawTextFile(context,R.raw.camera);        String fragSource = OpenUtils.readRawTextFile(context,R.raw.camera_planyuan);        //通过字符串代码        //使用openGL        //1.创建顶点着色器        int vShaderId = GLES20.glCreateShader(GLES20.GL_VERTEX_SHADER);        //2.创建片元做着色器        GLES20.glShaderSource(vShaderId,vertexSource);        GLES20.glCompileShader(vShaderId);        //主动获取成功、失败        int[] status = new int[1];        GLES20.glGetShaderiv(vShaderId,GLES20.GL_COMPILE_STATUS,status,0);        if (status[0] != GLES20.GL_TRUE){//方面找出错误原因            throw new IllegalStateException("着顶点色器配置失败");        }        int fShaderId = GLES20.glCreateShader(GLES20.GL_FRAGMENT_SHADER);        //2.创建片元做着色器        GLES20.glShaderSource(fShaderId,fragSource);        GLES20.glCompileShader(fShaderId);        //主动获取成功、失败        GLES20.glGetShaderiv(fShaderId,GLES20.GL_COMPILE_STATUS,status,0);        if (status[0] != GLES20.GL_TRUE){//方面找出错误原因            throw new IllegalStateException("片源着色器配置失败");        }        //3.创建着色器程序(运行到GPU上)        mProgram = GLES20.glCreateProgram();        //把着色器塞到程序当中        GLES20.glAttachShader(mProgram,vShaderId);        GLES20.glAttachShader(mProgram,fShaderId);        //链接着色器        GLES20.glLinkProgram(mProgram);        //获得程序是否配置成功        GLES20.glGetProgramiv(mProgram,GLES20.GL_LINK_STATUS,status,0);        if (status[0] != GLES20.GL_TRUE){            throw new IllegalStateException("着色器配置失败");        }        //已经塞到着色器中了 释放资源        GLES20.glDeleteShader(vShaderId);        GLES20.glDeleteShader(fShaderId);        //获得着色器三个变量        vPosition = GLES20.glGetAttribLocation(mProgram,"vPosition");        vCoord = GLES20.glGetAttribLocation(mProgram,"vCoord");        vMatrix = GLES20.glGetUniformLocation(mProgram,"vMatrix");        vTexture = GLES20.glGetUniformLocation(mProgram,"vTexture");        //顶点坐标        mVertexBuffer = ByteBuffer.allocateDirect(4 * 2 * 4).order(ByteOrder.nativeOrder())                .asFloatBuffer();        mVertexBuffer.clear();        float[] v = {-1.0f, -1.0f,                1.0f, -1.0f,                -1.0f, 1.0f,                1.0f, 1.0f};        mVertexBuffer.put(v);        //顶点坐标        mTextureBuffer = ByteBuffer.allocateDirect(4 * 2 * 4).order(ByteOrder.nativeOrder())                .asFloatBuffer();        mTextureBuffer.clear();        float[] t = {1.0f, 0.0f,                1.0f, 1.0f,                0.0f, 0.0f,                0.0f, 1.0f        };        mTextureBuffer.put(t);    }    /**     * 使用着色器程序画画     * @param texture     * @param mtx     */    public void onDrawFrame(int texture,float[] mtx){        //设置窗口 画画的        GLES20.glViewport(0,0,mWidth,mHieght);        //使用着色器画        GLES20.glUseProgram(mProgram);        //将顶点数据传入,并确定形状        mVertexBuffer.position(0);        GLES20.glVertexAttribPointer(vPosition,2,GLES20.GL_FLOAT,false,0,mVertexBuffer);        //传了数据之后 激活        GLES20.glEnableVertexAttribArray(vPosition);        mVertexBuffer.position(0);        GLES20.glVertexAttribPointer(vCoord,2,GLES20.GL_FLOAT,false,0,mVertexBuffer);        GLES20.glEnableVertexAttribArray(vCoord);        //3、变换矩阵        GLES20.glUniformMatrix4fv(vMatrix,1,false,mtx,0);        //片元的 vTexture 绑定图像数据到采样器        GLES20.glActiveTexture(GLES20.GL_TEXTURE0);        //激活图层        GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,texture);        //需要和纹理对应        GLES20.glUniform1f(vTexture,0);        //参数传完之后通知openGL 画画        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP,0,4);    }    public void onReady(int i, int i1) {        mWidth = i;        mHieght = i1;    }}

   float[] v = {-1.0f, -1.0f,
                1.0f, -1.0f,
                -1.0f, 1.0f,
                1.0f, 1.0f};

这个代码openGL的世界左边点从左边底部-到右边底部到左边上部到右边上部ByteBuffer.allocateDirect(4 * 2 * 4).order(ByteOrder.nativeOrder()) 4*2代表有四个顶点 每个顶点的2个值x,y float类型 4个字节的意思

工具类如下:

package com.note.opengl.util;import android.graphics.ImageFormat;import android.graphics.SurfaceTexture;import android.hardware.Camera;import java.io.IOException;/** * Created by m.wang on 2018/11/6. */public class CameraHelper implements Camera.PreviewCallback{    private static final String TAG = "CameraHelper";    public static final int WIDTH = 640;    public static final int HEIGHT = 480;    private int mCameraId;    private Camera mCamera;    private byte[] buffer;    private Camera.PreviewCallback mPreviewCallback;    private SurfaceTexture msufaceTexttrue;    public int getmCameraId() {        return mCameraId;    }    public void setmCameraId(int mCameraId) {        this.mCameraId = mCameraId;    }    public CameraHelper(int mCameraId){        this.mCameraId = mCameraId;    }    public void switchCamera(){        if (mCameraId == Camera.CameraInfo.CAMERA_FACING_BACK){            mCameraId = Camera.CameraInfo.CAMERA_FACING_FRONT;        }else {            mCameraId = Camera.CameraInfo.CAMERA_FACING_BACK;        }        stopPreview();        starPreview(msufaceTexttrue);    }    public void starPreview(SurfaceTexture surfaceTexture) {        msufaceTexttrue = surfaceTexture;        try {            //获得camera对象            mCamera = Camera.open(mCameraId);            //配置camera的属性            Camera.Parameters parameters = mCamera.getParameters();            //设置预览格式为nv21            parameters.setPictureFormat(ImageFormat.NV21);            //这是摄像头宽高            parameters.setPreviewSize(WIDTH , HEIGHT);            //设置摄像头方向角度            mCamera.setParameters(parameters);            buffer = new byte[WIDTH * HEIGHT * 3 / 2];            //数据缓存区            mCamera.addCallbackBuffer(buffer);            mCamera.setPreviewCallbackWithBuffer(this);            //设置预览画面            mCamera.setPreviewTexture(msufaceTexttrue);            mCamera.startPreview();        } catch (Exception e) {            e.printStackTrace();        }    }    public void stopPreview(){        if (mCamera != null){            //预览数据回调接口            mCamera.setPreviewCallback(null);            //停止预览            mCamera.stopPreview();            mCamera.release();            mCamera = null;        }    }    @Override    public void onPreviewFrame(byte[] bytes, Camera camera) {        if (null != mPreviewCallback) {            mPreviewCallback.onPreviewFrame(bytes, camera);        }        camera.addCallbackBuffer(buffer);    }}

 mCameraId = Camera.CameraInfo.CAMERA_FACING_BACK;后置摄像头

文件读出来string接收工具类

package com.note.opengl.util;import android.content.Context;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;/** * Created by m.wang on 2018/11/6. */public class OpenUtils {    public static String readRawTextFile(Context context, int rawId) {        InputStream is = context.getResources().openRawResource(rawId);        BufferedReader br = new BufferedReader(new InputStreamReader(is));        String line;        StringBuilder sb = new StringBuilder();        try {            while ((line = br.readLine()) != null) {                sb.append(line);                sb.append("\n");            }        } catch (Exception e) {            e.printStackTrace();        }        try {            br.close();        } catch (IOException e) {            e.printStackTrace();        }        return sb.toString();    }}

demo地址:https://download.csdn.net/download/qq_23213991/10771044

更多相关文章

  1. Android中的Sqlite数据库的简单使用
  2. Android之Intent传递数据的方式
  3. 解决 Android(安卓)中使用ListView和CheckBox批量操作时若干问题
  4. Android中SharedPreferences的使用(登陆,记住密码)
  5. android -- 小问题 Android(安卓)WebView缓存分析
  6. 【Android】Handler的应用(一):从服务器端加载JSON数据
  7. Android的进阶学习(一)--Activity异常退出
  8. Android:Intent 显示和隐式 学习
  9. Android开发中如何使用绘制图表

随机推荐

  1. 实现<table>标签的动态新增和后台接受<ta
  2. javascript去掉前后空格
  3. 在java中如何计算从1970年1月1日零时零分
  4. 1563: 高精度加法
  5. 跪求一个java抽奖中奖算法的实现,在线等,急
  6. Cxf 集成spring完整示例
  7. leetcode解题之242# Valid Anagram Java
  8. 自定义视图无法工作,直到我触摸屏幕
  9. RabbitMQ四种Exchange类型之Headers(Java
  10. 将字符串拆分为字符串数组。