定义顶点数据
顶点数据描述了OpenGL世界中元素的位置,下面定义了绘制一个三角形所需要的顶点数据,x,y,z对应三角形的每个顶点坐标,其中z代表深度,x1,y1对应着色器的颜色代码。
float vertices[] = {
// x y z x1 y1
0.0f, 1.0f, 0.0f, 0.3f, 1.0f,
-0.8f, -0.8f, 0f, 0.0f, 0.0f,
0.8f, -0.8f, 0.0f, 0.6f, 0.0f,
};
顶点数据转换
java的数据结构在opengl中无法直接使用,我们需要转成OpenGL能识别的buffer格式,我们将上面创建的顶点数据转换成了ByteBuffer类型。
ByteBuffer verticesByteBuffer = ByteBuffer.allocateDirect(vertices.length * 4).order(ByteOrder.nativeOrder());
verticesFloatBuffer = verticesByteBuffer.asFloatBuffer().put(vertices);
verticesFloatBuffer.position(0);
编写顶点和片段着色器
顶点着色器定义了vec3类型的位置属性aPosition,它的长度为3,与上面的顶点数组中的x,y,z相对应。aTexCoord代表纹理坐标,它与顶点数组中的x1,y1列相对应。
private final String mVertexShader =
"varying vec2 texCoord;\n" +
"attribute vec3 aPosition;\n" +
"attribute vec2 aTexCoord;\n" +
"void main() {\n" +
" gl_Position = vec4(aPosition,1);\n" +
" texCoord = aTexCoord;\n" +
"}\n";
private final String mFragmentShader =
"varying vec2 texCoord;\n" +
"uniform sampler2D sTexture;\n" +
"void main() {\n" +
" gl_FragColor = texture2D(sTexture,texCoord);\n" +
"}\n";
创建顶点&着色器Shader
这个过程是将编写的顶点脚本和着色器脚本函数进行编译,编译完后将返回对应shader的句柄id
int vertexShader = createMyShader(GL_VERTEX_SHADER, mVertexShader);
int fragmentShader = createMyShader(GL_FRAGMENT_SHADER, mFragmentShader);
private int createMyShader(int type, String textCode) {
int shader = glCreateShader(type);
glShaderSource(shader, textCode);
glCompileShader(shader);
//<editor-fold desc="检查是否错误">
int[] compiled = new int[1];
glGetShaderiv(shader, GL_COMPILE_STATUS, compiled, 0);
checkGlError("createMyShader");
if (compiled[0] == 0) {
glDeleteShader(shader);
shader = 0;
}
//</editor-fold>
return shader;
}
创建GLProgram
创建gl程序的最核心的部分其实是将顶点shader和着色器shader与program进行关联,从progam中获取maPositionHandle和maTexCoordHandle的目的是为了方便后面进行顶点属性说明是用到。
int program = createMyProgram(vertexShader, fragmentShader);
private int createMyProgram(int vertexShader, int fragmentShader) {
int program = glCreateProgram();
if (program != 0) {
GLES20.glAttachShader(program, vertexShader);
checkGlError("glAttachShader");
GLES20.glAttachShader(program, fragmentShader);
checkGlError("glAttachShader");
GLES20.glLinkProgram(program);
int[] linkStatus = new int[1];
GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0);
if (linkStatus[0] != GLES20.GL_TRUE) {
Log.e("TEST", "Could not link program: ");
Log.e("TEST", GLES20.glGetProgramInfoLog(program));
GLES20.glDeleteProgram(program);
program = 0;
}
}
return program;
}
int maPositionHandle = glGetAttribLocation(program, "aPosition");
int maTexCoordHandle = glGetAttribLocation(program, "aTexCoord");
创建和绑定纹理
int[] textures = new int[1];
GLES20.glGenTextures(1, textures, 0);
mTextureID = textures[0];
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureID);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_REPEAT);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_REPEAT);
InputStream is = getResources()
.openRawResource(R.raw.ab);
Bitmap bitmap;
try {
bitmap = BitmapFactory.decodeStream(is);
} finally {
try {
is.close();
} catch (IOException e) {
// Ignore.
}
}
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
bitmap.recycle();
//激活纹理
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
//绑定纹理
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureID);
顶点属性说明
/**
*指定maPositionHandle对应3个大小float,20代表整个数据段的长
*度,最后一个参数代表offset值(表示读取的偏移量)。
*整体可理解为:整个数据段长度为20字节,正好是我们定义的顶点数据的一行的长度(5个浮点型坐标),maPositionHandle需要12字节长度(3个浮点型坐标),读取的偏移量是0,所以取的数据正好是前面的x,y,z坐标。
**/
glVertexAttribPointer(maPositionHandle, 3, GL_FLOAT, false, 20, 0);
//启用顶点属性数组
glEnableVertexAttribArray(maPositionHandle);
glVertexAttribPointer(maTexCoordHandle, 2, GL_FLOAT, false, 20, 12);
//启用顶点属性数组
glEnableVertexAttribArray(maTexCoordHandle);
绘制元素
GLES20.glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
GLES20.glUseProgram(program);
glDrawArrays(GL_TRIANGLES, 0, 5);
GLES20.glUseProgram(0);