注意一下:
1、在OpenGL里面,只会绘制点,直线和三角形。
2、OpenGL作为本地系统库,是直接运行到硬件上的,没有虚拟机,垃圾回收和内存压缩。所有的 android.opengl.GLES2.0包中的方法,实际上都是使用 JNI 调用的本地方法库。
3、由于2的因素,所以openGL绘制需要的数据,都需要做一层转换,从java内存中转到 本地 内存中(我理解的就是 native)
// 因为上面 3 中 所描述的所以,数据的传输,我们采用的是 ByteBuffer
FloatBuffer vertexData;
// 2 个 三角形
float tableVerticesWithTriangles[] = {
-0.5f,-0.5f,
0.5f,0.5f,
-0.5f,0.5f,
-0.5f,-0.5f,
0.5f,-0.5f,
0.5f,0.5f,
-0.5f,0f,
0.5f,0f,
0f,-0.25f,
0f,0.25f};
ByteBuffer.allocateDirect(tableVerticesWithTriangles.length * BYTES_PER_FLOAT)
.order(ByteOrder.nativeOrder())
.asFloatBuffer();
// allocateDirect 方法是 C++ 中申请内存的方法,什么类型,每个类型多少字节
// 把数据 放到 FloatBuffer 的实例中
vertexData.put(tableVerticesWithTriangles);
上面是java中的数据往 native 中作一个迁移吧。下面需要介绍着色器了,这个很重要。
OpenGL 中的着色器分为 顶点着色器 和 片元着色器
1、着色器是用来描述 openGL 需要绘制的内容的 代码,专门告诉GPU的
2、顶点着色器描述顶点的位置,属性(颜色,大小,渐变色等)
3、片元着色器描述点、线、三角形的颜色,渐变色,大小
// 给顶点增加 颜色属性
private static String vertex_shader_step3 = "attribute vec4 a_Position; \n" +
// a_Color 记录顶点的 颜色
"attribute vec4 a_Color; \n" +
// 正交投影 的 矩阵 数据 (位置 a_Position * u_Matrix 得到一个新的位置 投影位置)
"uniform mat4 u_Matrix; \n" + // mat4 代表一个 4 X 4 的矩阵
// varying 表明颜色是在变化的
"varying vec4 v_Color; \n" +
"void main()\n" +
"{\n" +
// gl_Position是OpenGL中提供的变量,装载顶点坐标
" gl_Position = a_Position * u_Matrix;\n" +
" v_Color = a_Color; \n"+
// 指定 绘制 的 点的 大小
" gl_PointSize = 10.0;\n" +
"}";
gl_Position gl_PointSize 都是一些固定的属性 attribute 、uniform和varying 是具有特殊意义的修饰词
attribute 声明一个属性数据 vec4 类型的数据,存放位置数据
varying 声明 渐变的颜色数据
// 片元着色器,主要还是 声明颜色的
public static final String fragment_shader_step3 = "precision mediump float;\n" +
"varying vec4 v_Color; \n" +
"void main() {\n" +
// gl_FragColor 装载 当前片段的最终颜色
// 这里使用的是 v_Color 也就是 varying的属性,说明该片元的颜色根据两个顶点计算之后使用
" gl_FragColor=v_Color;\n" +
"}";
着色器的创建
/**
* 创建 着色器 对象
* type : GLES20.GL_VERTEX_SHADER / GLES20.GL_FRAGMENT_SHADER
* shaderCode: 着色器 代码
*/
public static int createShader(int type, String shaderCode) {
// 1、创建一个 着色器 对象,并检查是否创建成功
//TODO glCreateShader 在 native 中创建了 一个 着色器对象,并返回了这个 着色器的 id
int shaderObjectId = GLES20.glCreateShader(type);
if (shaderObjectId == 0) {
System.out.println("majie " + TAG + " Could not create new shader");
return 0;
}
// 2、上传 着色器 源码 到 着色器 对象里
// TODO shaderObjectId 代表着色器对象, shaderCode 是我们定义的 顶点着色器源码
GLES20.glShaderSource(shaderObjectId, shaderCode);
// 3、告诉 openGL 编译 第二步 上传的源码(字符串)
GLES20.glCompileShader(shaderObjectId);
// 4、获取 openGL 的编译结果
int compileStatue[] = new int[1];
// TODO openGL 的通用写法 --> 将 shaderObjectId 的编译结果 写到 compileStatue 中的第一个元素中
GLES20.glGetShaderiv(shaderObjectId, GLES20.GL_COMPILE_STATUS, compileStatue, 0);
// TODO 额外信息,可以获取 着色器 的编译日志
System.out.println("majie " + TAG + " Results of compiling source: " + compileStatue[0]
+ " \n:" + GLES20.glGetShaderInfoLog(shaderObjectId));
// 5、验证 编译状态 ,并 返回着色器的对象 ID TODO:TMD就是最开始生成的那个 ID
if (compileStatue[0] == 0) {
// 如果失败,就删除 shader 对象
GLES20.glDeleteShader(shaderObjectId);
}
return shaderObjectId;
}
这里要理解一个点,就是