Android 音视频开发(五) : OpenGL ES API,了解 OpenGL 开发的基本流程,使用 OpenGL 绘制一个三角形,正方形,圆

1.OpenGL ES简介

OpenGL Es学习,首先要了解Android的基本架构,如下图:

 

在Android的第三层的Libraries里面就有OpenGL  ES库。OpenGL ES是一个跨平台的图形API,给3D图形处理硬件指定了一个标准的软件接口。

2.OpenGL ES在Android的使用

Android提供了两个类:GLSufaceView和GLSurfaceView.Renderer.

2.1GLSurfaceView

GlSurfaceView就是一个surfaceView ,只是增加了Render,用OpenGL来显示渲染。

2.2GLSurfaceView.Renderer

使用GLSurfaceView.setRenderer()将其附加到GLSurfaceView实例。

GLSurfaceView.Renderer要求实现以下方法:

  • onSurfaceCreated():创建GLSurfaceView时,系统调用一次该方法。使用此方法执行只需要执行一次的操作,例如设置OpenGL环境参数或初始化OpenGL图形对象。
  • onDrawFrame():系统在每次重画GLSurfaceView时调用这个方法。使用此方法作为绘制(和重新绘制)图形对象的主要执行方法。
  • onSurfaceChanged():当GLSurfaceView的发生变化时,系统调用此方法,这些变化包括GLSurfaceView的大小或设备屏幕方向的变化。例如:设备从纵向变为横向时,系统调用此方法。我们应该使用此方法来响应GLSurfaceView容器的改变。

使用GlSurfaceView步骤:

  1. 创建一个GlSurfaceView。
  2. 设置渲染
  3. 在GlSurfaceView.renderder中绘制处理显示数据

3.OpenGL ES绘制图形

在Android使用OpenGL ES的步骤:

  1. 在Manifest中声明OpenGL ES使用,我使用OpenGL ES2.0的API
    <uses-feature android:glEsVersion="0x00020000" android:required="true" />

    如果要使用问了要是添加

    <supports-gl-texture android:name="GL_OES_compressed_ETC1_RGB8_texture" />
    <supports-gl-texture android:name="GL_OES_compressed_paletted_texture" />

     

  2. 设置相关的渲染Renderer,Renderer有三个方法:
  • onSurfaceCreated() - 在View的OpenGL环境被创建的时候调用。
  • onDrawFrame() - 每一次View的重绘都会调用
  • onSurfaceChanged() - 如果视图的几何形状发生变化(例如,当设备的屏幕方向改变时),则调用此方法。

绘制图形

示例代码:

public class GlSurfaceViewActivity extends AppCompatActivity {
private GLSurfaceView gLsurfaceview;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_gl_surface_view);
        gLsurfaceview = findViewById(R.id.gLsurfaceview);
        gLsurfaceview.setEGLContextClientVersion(2);
       // gLsurfaceview.setRenderer(new Trianglerenderer());//三角形
        //gLsurfaceview.setRenderer(new SquareRenderer());//正方形
        gLsurfaceview.setRenderer(new CircleRenderer());//圆
        gLsurfaceview.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
    }

    @Override
    protected void onResume() {
        super.onResume(); gLsurfaceview.onResume();
    }

    @Override
    protected void onPause() {
        super.onPause();
        gLsurfaceview.onPause();
    }
}

三角形的Renderer:

public class Trianglerenderer extends BackgroundRender {
    private int mProgram;
    private FloatBuffer vertexBuffer;

    private final String vertexShaderCode =
            "attribute vec4 vPosition;" +
                    "void main() {" +
                    "  gl_Position = vPosition;" +
                    "}";

    private final String fragmentShaderCode =
            "precision mediump float;" +
                    "uniform vec4 vColor;" +
                    "void main() {" +
                    "  gl_FragColor = vColor;" +
                    "}";

    static float triangleCoords[] = {
            0.0f,  0.6f, 0.0f, // top
            -0.5f, -0.3f, 0.0f, // bottom left
            0.5f, -0.3f, 0.0f  // bottom right
    };

    //设置颜色,依次为红绿蓝和透明通道
    float color[] = { 0.0f, 1.0f, 0.0f, 1.0f ,
            1.0f, 0.0f, 0.0f, 1.0f,
            0.0f, 0.0f, 1.0f, 1.0f };
    static final int COORDS_PER_VERTEX = 3;

    private int mPositionHandle;
    private int mColorHandle;

    //顶点个数
    private final int vertexCount = triangleCoords.length / COORDS_PER_VERTEX;
    //顶点之间的偏移量
    private final int vertexStride = COORDS_PER_VERTEX * 4; // 每个顶点四个字节


    @Override
    public void onSurfaceCreated(GL10 gl10, EGLConfig eglConfig) {
        //将背景设置为灰色
        GLES20.glClearColor(0.5f,0.5f,0.5f,1.0f);
        //申请底层空间
        ByteBuffer bb = ByteBuffer.allocateDirect(triangleCoords.length * 4);
        bb.order(ByteOrder.nativeOrder());
        //将坐标数据转换为FloatBuffer,用以传入OpenGL ES程序
        vertexBuffer = bb.asFloatBuffer();
        vertexBuffer.put(triangleCoords);
        vertexBuffer.position(0);

        int vertexShader =  loadShader(GLES20.GL_VERTEX_SHADER,vertexShaderCode);
        int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER,fragmentShaderCode);

        //创建一个空的OpenGLES程序
        mProgram = GLES20.glCreateProgram();
        //将顶点着色器加入到程序
        GLES20.glAttachShader(mProgram,vertexShader);
        //将片元着色器加入到程序中
        GLES20.glAttachShader(mProgram,fragmentShader);
        //连接到着色器程序
        GLES20.glLinkProgram(mProgram);
    }





    @Override
    public void onSurfaceChanged(GL10 gl10, int width, int height) {
        GLES20.glViewport(0,0,width,height);
    }

    @Override
    public void onDrawFrame(GL10 gl10) {
        //将程序加入到OpenGLES2.0环境
        GLES20.glUseProgram(mProgram);

        //获取顶点着色器的vPosition成员句柄
        mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
        //启用三角形顶点的句柄
        GLES20.glEnableVertexAttribArray(mPositionHandle);
        //准备三角形的坐标数据
        GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX,
                GLES20.GL_FLOAT, false,
                vertexStride, vertexBuffer);
        //获取片元着色器的vColor成员的句柄
        mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");
        //设置绘制三角形的颜色
        GLES20.glUniform4fv(mColorHandle, 1, color, 0);
        //绘制三角形
        GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount);
        //禁止顶点数组的句柄
        GLES20.glDisableVertexAttribArray(mPositionHandle);
    }

}

正方形的Renderer:

public class SquareRenderer extends BackgroundRender implements GLSurfaceView.Renderer {
    private FloatBuffer vertexBuffer;
    private ShortBuffer indexBuffer;
    private final String vertexShaderCode =
            "attribute vec4 vPosition;" +
                    "uniform mat4 vMatrix;" +
                    "void main() {" +
                    "  gl_Position = vMatrix*vPosition;" +
                    "}";

    private final String fragmentShaderCode =
            "precision mediump float;" +
                    "uniform vec4 vColor;" +
                    "void main() {" +
                    "  gl_FragColor = vColor;" +
                    "}";

    private int mProgram;

    static final int COORDS_PER_VERTEX = 3;
    static float triangleCoords[] = {
            -0.5f, 0.5f, 0.0f, // top left
            -0.5f, -0.5f, 0.0f, // bottom left
            0.5f, -0.5f, 0.0f, // bottom right
            0.5f, 0.5f, 0.0f  // top right
    };

    static short index[] = {
            0, 1, 2, 0, 2, 3
    };

    private int mPositionHandle;
    private int mColorHandle;

    private float[] mViewMatrix = new float[16];
    private float[] mProjectMatrix = new float[16];
    private float[] mMVPMatrix = new float[16];

    //顶点个数
    private final int vertexCount = triangleCoords.length / COORDS_PER_VERTEX;
    //顶点之间的偏移量
    private final int vertexStride = COORDS_PER_VERTEX * 4; // 每个顶点四个字节

    private int mMatrixHandler;

    //设置颜色,依次为红绿蓝和透明通道
    float color[] = {0.0f, 1.0f, 0.0f, 1.0f ,
            1.0f, 0.0f, 0.0f, 1.0f,
            0.0f, 0.0f, 1.0f, 1.0f};


    @Override
    public void onSurfaceCreated(GL10 gl10, EGLConfig eglConfig) {
        ByteBuffer bb = ByteBuffer.allocateDirect(
                triangleCoords.length * 4);
        bb.order(ByteOrder.nativeOrder());
        vertexBuffer = bb.asFloatBuffer();
        vertexBuffer.put(triangleCoords);
        vertexBuffer.position(0);

        ByteBuffer cc = ByteBuffer.allocateDirect(index.length * 2);
        cc.order(ByteOrder.nativeOrder());
        indexBuffer = cc.asShortBuffer();
        indexBuffer.put(index);
        indexBuffer.position(0);

        int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER,
                vertexShaderCode);
        int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER,
                fragmentShaderCode);

        //创建一个空的OpenGLES程序
        mProgram = GLES20.glCreateProgram();
        //将顶点着色器加入到程序
        GLES20.glAttachShader(mProgram, vertexShader);
        //将片元着色器加入到程序中
        GLES20.glAttachShader(mProgram, fragmentShader);
        //连接到着色器程序
        GLES20.glLinkProgram(mProgram);
    }

    @Override
    public void onSurfaceChanged(GL10 gl10, int width, int height) {
        //计算宽高比
        float ratio = (float) width / height;
        //设置透视投影
        Matrix.frustumM(mProjectMatrix, 0, -ratio, ratio, -1, 1, 3, 7);
        //设置相机位置
        Matrix.setLookAtM(mViewMatrix, 0, 0, 0, 7.0f, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
        //计算变换矩阵
        Matrix.multiplyMM(mMVPMatrix, 0, mProjectMatrix, 0, mViewMatrix, 0);
    }

    @Override
    public void onDrawFrame(GL10 gl10) {
        //将程序加入到OpenGLES2.0环境
        GLES20.glUseProgram(mProgram);
        //获取变换矩阵vMatrix成员句柄
        mMatrixHandler = GLES20.glGetUniformLocation(mProgram, "vMatrix");
        //指定vMatrix的值
        GLES20.glUniformMatrix4fv(mMatrixHandler, 1, false, mMVPMatrix, 0);
        //获取顶点着色器的vPosition成员句柄
        mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
        //启用三角形顶点的句柄
        GLES20.glEnableVertexAttribArray(mPositionHandle);
        //准备三角形的坐标数据
        GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX,
                GLES20.GL_FLOAT, false,
                vertexStride, vertexBuffer);
        //获取片元着色器的vColor成员的句柄
        mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");
        //设置绘制三角形的颜色
        GLES20.glUniform4fv(mColorHandle, 1, color, 0);
        //绘制三角形
//        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, vertexCount);
        //索引法绘制正方形
        GLES20.glDrawElements(GLES20.GL_TRIANGLES, index.length, GLES20.GL_UNSIGNED_SHORT, indexBuffer);
        //禁止顶点数组的句柄
        GLES20.glDisableVertexAttribArray(mPositionHandle);
    }

}

圆的Renderer:

public class CircleRenderer extends BackgroundRender implements GLSurfaceView.Renderer {
    String vertexShaderCode = "attribute vec4 vPosition;\n" +
            "uniform mat4 vMatrix;\n" +
            "void main() {\n" +
            "  gl_Position = vMatrix*vPosition;\n" +
            "}" ;

    String fragmentShaderCode = "precision mediump float;\n" +
            " uniform vec4 vColor;\n" +
            " void main() {\n" +
            "     gl_FragColor = vColor;\n" +
            " }";
    int mProgram;

    private FloatBuffer vertexBuffer;
    private float[] circlrCoods;
    float color[] = { 1.0f, 1.0f, 1.0f, 1.0f }; //顶点统一白色

    public CircleRenderer() {
        //设置所有坐标
        circlrCoods = createPositions();
        //float[] → FloatBuffer
        ByteBuffer bb = ByteBuffer.allocateDirect(circlrCoods.length * 4);
        bb.order(ByteOrder.nativeOrder());
        vertexBuffer = bb.asFloatBuffer();
        vertexBuffer.put(circlrCoods);
        vertexBuffer.position(0);
    }

    private float[]  createPositions(){
        ArrayList<Float> data=new ArrayList<>();
        data.add(0.0f);             //设置圆心坐标
        data.add(0.0f);
        data.add(0.0f);
        //分成100条边,绘制出来应该很像圆了
        float radius = 0.5f; //半径1
        float angDegSpan=360f/100; //依次递加的角度
        for(float i=0;i<360+angDegSpan;i+=angDegSpan){
            data.add((float)(radius*Math.cos(i*Math.PI/180f))); //x
            data.add((float) (radius*Math.sin(i*Math.PI/180f))); //y
            data.add(0.0f); //z
        }
        float[] f=new float[data.size()];
        for (int i=0;i<f.length;i++){
            f[i]=data.get(i);
        }
        return f;
    }

    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        int vetexShader = loadShader(GLES20.GL_VERTEX_SHADER , vertexShaderCode);
        int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER , fragmentShaderCode);
        //添加着色器
        mProgram = GLES20.glCreateProgram();
        GLES20.glAttachShader(mProgram,vetexShader);
        GLES20.glAttachShader(mProgram,fragmentShader);
        GLES20.glLinkProgram(mProgram);
    }

    private final float[] mMVPMatrix = new float[16];
    private final float[] mProjectMatrix = new float[16];
    private final float[] mViewMatrix = new float[16];
    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
        GLES20.glViewport(0,0,width,height);
        float ratio = (float) width/height;
        //设置矩阵
        Matrix.frustumM(mProjectMatrix,0,-ratio,ratio,-1,1,3,20);
        Matrix.setLookAtM(mViewMatrix,0,0f,0f,7.0f,0f,0f,0f,0f,1.0f,0f);
        Matrix.multiplyMM(mMVPMatrix,0,mProjectMatrix,0,mViewMatrix,0);
    }

    int mMatrixHandler;
    int mPositionHandle;
    int vColorHandle;
    @Override
    public void onDrawFrame(GL10 gl) {
        Log.e("TAG","error");
        GLES20.glUseProgram(mProgram);
        mMatrixHandler = GLES20.glGetUniformLocation(mProgram,"vMatrix");
        GLES20.glUniformMatrix4fv(mMatrixHandler,1,false,mMVPMatrix,0);

        mPositionHandle = GLES20.glGetAttribLocation(mProgram,"vPosition");
        GLES20.glEnableVertexAttribArray(mPositionHandle);
        GLES20.glVertexAttribPointer(
                mPositionHandle,
                3,
                GLES20.GL_FLOAT,
                false,
                12,
                vertexBuffer
        );

        vColorHandle = GLES20.glGetUniformLocation(mProgram,"vColor");
        GLES20.glUniform4fv(vColorHandle,1,color,0);

        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN , 0 , circlrCoods.length/3);
        GLES20.glDisableVertexAttribArray(mPositionHandle);
    }


}


项目地址:https://github.com/ChloeDimen/AudioAndVideo

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值