提取创建 Program 对象的工具类
-
对外唯一接口
ShaderUtils.createProgram(this.getResources() , vertexCodePath , fragmentCodePath)
实例代码
package com.example.openglstudy.utils;
import android.content.res.Resources;
import android.opengl.GLES20;
import android.util.Log;
import java.io.IOException;
import java.io.InputStream;
public class ShaderUtils {
public static int createProgram(Resources res , String vertexPath ,String fragmentPath){
String vertexCodeString = compilerSourceToString(res , vertexPath);
String fragmentCodeString = compilerSourceToString(res , fragmentPath);
int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER , vertexCodeString);
int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER , fragmentCodeString);
int program = GLES20.glCreateProgram();
if (program == 0){
glError("create program failed");
return 0;
}
GLES20.glAttachShader(program , vertexShader);
GLES20.glAttachShader(program , fragmentShader);
GLES20.glLinkProgram(program);
//check program status;
int[] programStatus = new int[1];
GLES20.glGetProgramiv(program , GLES20.GL_LINK_STATUS ,programStatus , 0 );
if (programStatus[0] == 0){
glError("link program failed");
glError("link program failed :" + GLES20.glGetProgramInfoLog(program));
GLES20.glDeleteProgram(program);
program = 0;
}
return program;
}
private static int loadShader(int type , String sourceCode){
int shader = GLES20.glCreateShader(type);
if (shader == 0){
glError("create shader failed" + type);
return 0;
}
GLES20.glShaderSource(shader , sourceCode);
GLES20.glCompileShader(shader);
int[] compilerStatus = new int[1];
GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS,compilerStatus,0);
if (compilerStatus[0] == 0){
//编译失败.
glError("compiler code failed : " + type);
glError("compiler code failed : " + GLES20.glGetShaderInfoLog(shader) );
GLES20.glDeleteShader(shader);
shader = 0;
}
return shader;
}
private static String compilerSourceToString(Resources res , String path){
StringBuffer sb = null;
InputStream is = null;
try {
sb = new StringBuffer();
is = res.getAssets().open(path);
int len;
byte[] buffer = new byte[1024];
while(-1 != (len = is.read(buffer))){
sb.append(new String(buffer , 0 , len));
}
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
if (is!= null){
is.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return sb.toString().replaceAll("\\r\\n" , "\n");
}
private static void glError(String error){
Log.e("ShanderUtils" , error);
}
}
代码解析
- 加载 glsl 文件生成 shaderID 值
加载glsl 一共使用了3 个函数: 创建 ---> 加载源码 --> 编译.
int shader = GLES20.glCreateShader(type);
函数的type一共有两个:
GLES20.GL_VERTEX_SHADER
GLES20.GL_FRAGMENT_SHADER
GLES20.glShaderSource(shader , sourceCode);
GLES20.glCompileShader(shader)
检测错误位置:
创建shader时.判断shader 是否创建成功. 当shader 为0 时,创建失败. 创建失败有几种情况, 包含type不对, 还有就是创建shader时,当前的上下文不在 draw() 过程中.
编译之后, 检测编译是否成功. 在检测到编译失败后, 使用 glGetShaderInfoLog(shader) 函数获取错误信息, 并将信息直接String 返回出来. 并开始清理环境, 将当前错误的 shader 删除. 直接调用 glDeleteShader(shader) 即可, 这个函数也可以在绘制图形完毕后调用.
int[] compilerStatus = new int[1]; GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS,compilerStatus,0);
private static int loadShader(int type , String sourceCode){
int shader = GLES20.glCreateShader(type);
if (shader == 0){
glError("create shader failed" + type);
return 0;
}
GLES20.glShaderSource(shader , sourceCode);
GLES20.glCompileShader(shader);
int[] compilerStatus = new int[1];
GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS,compilerStatus,0);
if (compilerStatus[0] == 0){
//编译失败.
glError("compiler code failed : " + type);
glError("compiler code failed : " + GLES20.glGetShaderInfoLog(shader) );
GLES20.glDeleteShader(shader);
shader = 0;
}
return shader;
}
-
加载 glsl 文件为String
private static String compilerSourceToString(Resources res , String path){ StringBuffer sb = null; InputStream is = null; try { sb = new StringBuffer(); is = res.getAssets().open(path); int len; byte[] buffer = new byte[1024]; while(-1 != (len = is.read(buffer))){ sb.append(new String(buffer , 0 , len)); } } catch (IOException e) { e.printStackTrace(); }finally { try { if (is!= null){ is.close(); } } catch (IOException e) { e.printStackTrace(); } } return sb.toString().replaceAll("\\r\\n" , "\n"); } private static void glError(String error){ Log.e("ShanderUtils" , error); }
-
创建程序. 附着shader
int program = GLES20.glCreateProgram(); if (program == 0){ glError("create program failed"); return 0; } GLES20.glAttachShader(program , vertexShader); GLES20.glAttachShader(program , fragmentShader); GLES20.glLinkProgram(program); //check program status; int[] programStatus = new int[1]; GLES20.glGetProgramiv(program , GLES20.GL_LINK_STATUS ,programStatus , 0 ); if (programStatus[0] == 0){ glError("link program failed"); glError("link program failed :" + GLES20.glGetProgramInfoLog(program)); GLES20.glDeleteProgram(program); program = 0; } return program;