提取創(chuàng)建 Program 對象的工具類
-
對外唯一接口
ShaderUtils.createProgram(this.getResources() , vertexCodePath , fragmentCodePath)
實(shí)例代碼
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 個函數(shù): 創(chuàng)建 ---> 加載源碼 --> 編譯.
int shader = GLES20.glCreateShader(type);
函數(shù)的type一共有兩個:
GLES20.GL_VERTEX_SHADER
GLES20.GL_FRAGMENT_SHADER
GLES20.glShaderSource(shader , sourceCode);
GLES20.glCompileShader(shader)
檢測錯誤位置:
創(chuàng)建shader時.判斷shader 是否創(chuàng)建成功. 當(dāng)shader 為0 時,創(chuàng)建失敗. 創(chuàng)建失敗有幾種情況, 包含type不對, 還有就是創(chuàng)建shader時,當(dāng)前的上下文不在 draw() 過程中.
編譯之后, 檢測編譯是否成功. 在檢測到編譯失敗后, 使用 glGetShaderInfoLog(shader) 函數(shù)獲取錯誤信息, 并將信息直接String 返回出來. 并開始清理環(huán)境, 將當(dāng)前錯誤的 shader 刪除. 直接調(diào)用 glDeleteShader(shader) 即可, 這個函數(shù)也可以在繪制圖形完畢后調(diào)用.
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); }
?
-
創(chuàng)建程序. 附著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;
?