1.OpenGL ES 2.0 主要是用于嵌入式设备(主要就是手机及平板),与OpenGL 1.X的区别在于:1.X 使用的是固定渲染管线,而2.0使用的是可编程渲染管线,大大提高了渲染能力。
2.关于ShaderUtil的工具类:作用是将着色器(Shader)脚本加载进显卡并编译。
1>首先先从着色器sh 脚本中加载着色器内容的loadFromAssetsFile()以及检查每一步的是否有错误的checkGLError();
//检查每一步操作是否有错误的方法
public static void checkGlError(String op)
{
int error;
while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR)
{
Log.e("ES20_ERROR", op + ": glError " + error);
throw new RuntimeException(op + ": glError " + error);
}
}
//从sh脚本中加载shader内容的方法
public static String loadFromAssetsFile(String fname,Resources r)
{
String result=null;
try
{
InputStream in=r.getAssets().open(fname);
int ch=0;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
while((ch=in.read())!=-1)
{
baos.write(ch);
}
byte[] buff=baos.toByteArray();
baos.close();
in.close();
result=new String(buff,"UTF-8");
result=result.replaceAll("\\r\\n","\n");
}
catch(Exception e)
{
e.printStackTrace();
}
return result;
}
2>加载shader,因为有两种shader(一个是顶点,一个是片元)。
//加载制定shader的方法
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;
}
3>创建Program的方法。
//创建shader程序的方法
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);
checkGlError("glAttachShader");
//向程序中加入片元着色器
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;
}
4>附上两个着色器:放在assets文件夹中
frag.sh
precision mediump float;
varying vec4 vColor; //接收从顶点着色器过来的参数
void main()
{
gl_FragColor = vColor;//给此片元颜色值
}
vertex.sh
3.方法执行流程:<MyTDView是继承于GLSurfaceView>
uniform mat4 uMVPMatrix; //总变换矩阵
attribute vec3 aPosition; //顶点位置
attribute vec4 aColor; //顶点颜色
varying vec4 vColor; //用于传递给片元着色器的变量
void main()
{
gl_Position = uMVPMatrix * vec4(aPosition,1); //根据总变换矩阵计算此次绘制此顶点位置
vColor = aColor;//将接收的颜色传递给片元着色器
}
//初始化shader
public void initShader(MyTDView mv){
//加载顶点着色器的脚本内容
String mVertexShader=ShaderUtil.loadFromAssetsFile("vertex.sh", mv.getResources());
//加载片元着色器的脚本内容
String mFragmentShader=ShaderUtil.loadFromAssetsFile("frag.sh", mv.getResources());
//基于顶点着色器与片元着色器创建程序
int mProgram = ShaderUtil.createProgram(mVertexShader, mFragmentShader);
//获取程序中顶点位置属性引用id
int maPositionHandle = GLES20.glGetAttribLocation(mProgram, "aPosition");
//获取程序中顶点颜色属性引用id
int maColorHandle= GLES20.glGetAttribLocation(mProgram, "aColor");
//获取程序中总变换矩阵引用id
int muMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");}