一、加载shader
包括加载shader、编译shader、连接shader并且产生着色器程序id
1、加载、编译着色器脚本代码loadShader方法
public static int loadShader ( int shaderType, //shader的类型 GLES20.GL_VERTEX_SHADER GLES20.GL_FRAGMENT_SHADER String source //shader的脚本字符串 ) { //创建一个新shader int shader = GLES20.glCreateShader(shaderType); //若创建成功则加载shader if (shader != 0) { //加载shader的源代码 GLES20.glShaderSource(shader, source); //编译shader GLES20.glCompileShader(shader); //存放编译成功shader数量的数组 int[] compiled = new int[1]; //获取Shader的编译情况 GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0); if (compiled[0] == 0) {//若编译失败则显示错误日志并删除此shader Log.e("ES20_ERROR", "Could not compile shader " + shaderType + ":"); Log.e("ES20_ERROR", GLES20.glGetShaderInfoLog(shader)); GLES20.glDeleteShader(shader); shader = 0; } } return shader; }
此方法中主要为三个方法:GLES20.glCreateShader(shaderType)、GLES20.glShaderSource(shader, source)、GLES20.glCompileShader(shader)
❶、GLES20.glCreateShader(shaderType) 创建一个容纳shader的容器,称为shader容器
方法参数:GLES20.GL_VERTEX_SHADER (顶点shader)、GLES20.GL_FRAGMENT_SHADER (片元shader)
如果调用成功的话,函数将返回一个整形的正整数作为shader容器的id。
❷、GLES20.glShaderSource(shader, source) 在创建好的shader容器中添加shader的源代码。
❸、GLES20.glCompileShader(shader) 对shader容器中的源代码进行编译,返回代表shader容器的id。
其它两个调试方法为GLES20.glGetShaderiv 与 GLES20.glGetShaderInfoLog
❶、glGetShaderiv 获取编译情况
方法参数:shader是一个shader的id、pname使用GL_COMPILE_STATUS、params是返回值,如果一切正常返回GL_TRUE,否则返回GL_FALSE。
❷、glGetShaderInfoLog 获取编译错误2、连接shader并且产生着色器程序id
public static int createProgram(String vertexSource, String fragmentSource) { //加载顶点着色器 int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexSource); if (vertexShader == 0) { return 0; } //加载片元着色器 int pixelShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource); if (pixelShader == 0) { return 0; } //创建程序 int program = GLES20.glCreateProgram(); //若程序创建成功则向程序中加入顶点着色器与片元着色器 if (program != 0) { //向程序中加入顶点着色器 GLES20.glAttachShader(program, vertexShader); //向程序中加入片元着色器 GLES20.glAttachShader(program, pixelShader); checkGlError("glAttachShader"); //链接程序 GLES20.glLinkProgram(program); //存放链接成功program数量的数组 int[] linkStatus = new int[1]; //获取program的链接情况 GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0); //若链接失败则报错并删除程序 if (linkStatus[0] != GLES20.GL_TRUE) { Log.e("ES20_ERROR", "Could not link program: "); Log.e("ES20_ERROR", GLES20.glGetProgramInfoLog(program)); GLES20.glDeleteProgram(program); program = 0; } } return program; }
❶、glCreateProgram 在连接shader之前,首先要创建一个容纳程序的容器,称为着色器程序容器如果创建成功将返回一个整形正整数作为着色器程序的id。
❷、glAttachShader 将shader容器添加到程序中
方法参数:program是着色器的id、shader是要添加的顶点或者片元shader容器的id。
❸、glLinkProgram 连接程序
在连接操作执行以后,可以任意修改shader的源代码,对shader重新编译不会影响整个程序。
其它两个调试方法为:glGetProgramiv、glGetProgramInfoLog
❶、glGetProgramiv 获取连接情况
❷、glGetProgramInfoLog 获取连接错误
3、glUseProgram
在连接了程序以后,可以使用glUseProgram函数来加载并使用连接好的程序。
如果将program设置为0,表示使用固定功能管线。如果程序已经在使用的时候,对程序进行重新编译,编译后的程序自动替代以前的那个被调用,这时不需要再次调用这个函数
二、获取指向顶点着色器相应数据的Index
//基于顶点着色器与片元着色器创建程序 mProgram = createProgram(mVertexShader, mFragmentShader); //获取程序中顶点位置属性引用id maPositionHandle = GLES20.glGetAttribLocation(mProgram, "aPosition"); //获取程序中顶点颜色属性引用id maColorHandle= GLES20.glGetAttribLocation(mProgram, "aColor"); //获取程序中总变换矩阵引用id muMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
三、根据Index向顶点着色器中传递数据
//制定使用某套shader程序 GLES20.glUseProgram(mProgram); //将最终变换矩阵传入shader程序 GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, MatrixState.getFinalMatrix(), 0); //为画笔指定顶点位置数据 GLES20.glVertexAttribPointer ( maPositionHandle, 3, GLES20.GL_FLOAT, false, 3*4, mVertexBuffer ); //为画笔指定顶点着色数据 GLES20.glVertexAttribPointer ( maColorHandle, 4, GLES20.GL_FLOAT, false, 4*4, mColorBuffer ); //允许顶点位置数据数组 GLES20.glEnableVertexAttribArray(maPositionHandle); GLES20.glEnableVertexAttribArray(maColorHandle); //绘制立方体 GLES20.glDrawArrays(GLES20.GL_TRIANGLES,0, vCount);
❶、glVertexAttribPointer
函数原型:void glVertexAttribPointer(int indx, int size, boolean normalized, int stride, Buffer ptr)
参数含义:index 指定要修改的顶点着色器中顶点属性的索引值;
size 指定每个顶点属性的组件数量,必须为1、2、3或4。如position是由3个(x, y, z )组成,而颜色由4个(r, g, b, a)组成;
mnormalized 指定当被访问时,固定点数据值是否应该归一化(GL_TRUE),或者直接转换为固定值(GL_FALSE);
stride 指定连接顶点属性之前的偏移量。如果为0,那顶点属性被理解为:它们是紧密排列在一起的。初始值为0。如果normalized被设置为GL_TRUE,意味着整数型的值会被映射至区间[-1,1](有符号整数),或者区间[0,1](无符号整数),反之,这些值会被直接转换为浮点值而不进行归一化处理。
ptr 顶点的缓冲数据。
❷、启用或禁用顶点属性数据
要启用或者禁用顶点属性数组,调用glEnableVertexAttribArray和glDisableVertexAttribArray传入参数Index。如果启用,那么当glDrawArrays或者glDrawElements被调用时,顶点属性数组会被使用
❸、glActiveTexture 选择活动纹理单元