android 下 opengles 的绘制图形简单来讲步骤以下:java
浮点型数组,顶点的顺序按逆时针排列。android
android 平台上,app 运行在 jvm 中,内存由 jvm 管理,而 opengles 运行在 native 环境,因此为了式 opengles 可以访问图形顶点数据,须要把顶点拷贝到 native 内存中。git
另外,为了方便操做 native 中的顶点字节,将其映射到 FloatBuffer 中,而后就能够像使用数组同样使用了。github
//顶点,按逆时针顺序排列
private static final float[] vertices = {
0.0f, 0.5f, 0.0f,
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f};
public TriangleRender() {
//将顶点数据拷贝映射到 native 内存中,以便opengl可以访问
verticesBuffer = ByteBuffer
.allocateDirect(vertices.length * BYTES_PER_FLOAT)//直接分配 native 内存,不会被gc
.order(ByteOrder.nativeOrder())//和本地平台保持一致的字节序(大/小头)
.asFloatBuffer();//将底层字节映射到FloatBuffer实例,方便使用
verticesBuffer
.put(vertices)//将顶点拷贝到 native 内存中
.position(0);//每次 put position 都会 + 1,须要在绘制前重置为0
}
复制代码
着色器的源代码能够写到单独的文件中,也能够用字符串拼接(本文使用的方式,为了方便)数组
顶点着色器数据结构
layout (location = 0)
用来指定该 vPosition 的属性位置,后面须要使用该位置将顶点数据匹配到 vPosition 上。简单来讲,该着色器的内容就是:使用 opengles3.0 版本,将图形顶点数据采用4份量向量的数据结构绑定到着色器的第 0 个属性上,属性的名字叫 vPosition,着色器执行时,将 vPosition 的值传给用来表示顶点最终位置的内建变量 gl_Position。app
须要注意的是 layout (location = 0)
不是必需要写,若是不写的话,须要在后面着色器绑定到程序以后,程序链接以前使用 glBindAttribLocation
方法绑定。jvm
//顶点着色器
private static final String vertextShaderSource =
"#version 300 es\n"
+ "layout (location = 0) in vec4 vPosition;\n"
+ "void main()\n"
+ "{\n"
+ " gl_Position = vPosition;\n"
+ "}\n";
复制代码
片断着色器ide
//片断着色器
private static final String fragmentShaderSource =
"#version 300 es \n"
+ "precision mediump float; \n"
+ "out vec4 fragColor; \n"
+ "void main() \n"
+ "{ \n"
+ " fragColor = vec4 ( 1.0, 0.0, 0.0, 1.0 ); \n"
+ "} \n";
复制代码
着色器内容编辑完以后,想要使用还要通过编译。spa
/** * 加载着色器源,并编译 * * @param type 顶点着色器(GL_VERTEX_SHADER)/片断着色器(GL_FRAGMENT_SHADER) * @param shaderSource 着色器源(上面编辑的内容) * @return 着色器 */
private int loadShader(int type, String shaderSource) {
//建立着色器对象
int shader = GLES30.glCreateShader(type);
if (shader == 0) return 0;//建立失败
//加载着色器源
GLES30.glShaderSource(shader, shaderSource);
//编译着色器
GLES30.glCompileShader(shader);
//检查编译状态
int[] compiled = new int[1];
GLES30.glGetShaderiv(shader, GLES30.GL_COMPILE_STATUS, compiled, 0);
if (compiled[0] == 0) {
Log.e(TAG, GLES30.glGetShaderInfoLog(shader));
GLES30.glDeleteShader(shader);
return 0;//编译失败
}
return shader;
}
复制代码
具体的流程下面代码很清楚,须要注意的就是若是着色器中没有指定属性的位置,则须要调用 glBindAttribLocation
进行指定。
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
//获取顶点着色器
int vertextShader = loadShader(GLES30.GL_VERTEX_SHADER, vertextShaderSource);
//获取片断着色器
int fragmentShader =loadShader(GLES30.GL_FRAGMENT_SHADER, fragmentShaderSource);
//建立程序
int tmpProgram = GLES30.glCreateProgram();
if (tmpProgram == 0) return;//建立失败
//绑定着色器到程序
GLES30.glAttachShader(tmpProgram, vertextShader);
GLES30.glAttachShader(tmpProgram, fragmentShader);
//绑定属性位置 vPosition :0 着色器中没有设定属性位置时使用
// GLES30.glBindAttribLocation(tmpProgram, 0, "vPosition");
//链接程序
GLES30.glLinkProgram(tmpProgram);
//检查链接状态
int[] linked = new int[1];
GLES30.glGetProgramiv(tmpProgram,GLES30.GL_LINK_STATUS, linked, 0);
if (linked[0] == 0){
Log.e(TAG, "tmpProgram linked error");
Log.e(TAG, GLES30.glGetProgramInfoLog(tmpProgram));
GLES30.glDeleteProgram(tmpProgram);
return;//链接失败
}
//保存程序,后面使用
program = tmpProgram;
//设置清除渲染时的颜色
GLES30.glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
}
复制代码
@Override
public void onDrawFrame(GL10 gl) {
//擦除屏幕
GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT);
//使用程序
GLES30.glUseProgram(program);
//获取 vPosition 属性的位置
int vposition = GLES30.glGetAttribLocation(program, "vPosition");
//加载顶点数据到 vPosition 属性位置
GLES30.glVertexAttribPointer(vposition,3,GLES30.GL_FLOAT,false,0,verticesBuffer);
GLES30.glEnableVertexAttribArray(vposition);
//绘制
GLES30.glDrawArrays(GLES30.GL_TRIANGLES,0,3);
}
复制代码
本文经过绘制一个三角形,梳理了 opengles 绘制图形的流程,着色器、程序的使用方法。