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
<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" />
- 设置相关的渲染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