Android OpenGL ES2.0 實現步驟
阿新 • • 發佈:2019-02-18
定義頂點資料
頂點資料描述了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);