Android 音视频开发(五) : OpenGL ES API,了解 OpenGL 开发的基本流程,使用 OpenGL 绘制一个三角形,正方形,圆
16lz
2021-01-23
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步骤:
- 创建一个GlSurfaceView。
- 设置渲染
- 在GlSurfaceView.renderder中绘制处理显示数据
3.OpenGL ES绘制图形
在Android使用OpenGL ES的步骤:
- 在Manifest中声明OpenGL ES使用,我使用OpenGL ES2.0的API
如果要使用问了要是添加
- 设置相关的渲染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 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
项目地址:https://github.com/ChloeDimen/AudioAndVideo
更多相关文章
- c语言如何求三角形的面积
- 手把手教你在C语言中如何打印倒三角形
- 图解两数之和的变形题之「有效三角形的个数」
- 如何为每个JQuery UI滑块句柄使用不同的图像
- 从“顶点小说”下载完整小说——python爬虫
- Python能不能方便的画三角形?
- python输出斐波那契数列三角形
- java三角形的画法