傳送門 ☞ 輪子的專欄 ☞ 轉載請註明 ☞ http://blog.csdn.net/leverage_1229
在定義好待繪製的形狀之後,就要開始繪製它們了。使用OpenGL ES 2.0繪製形狀可能比你想象的要複雜一些,因爲它的API中提供了大量控制渲染管道的行爲。
這一節將介紹如何使用OpenGL ES 2.0的API繪製上一節你已經定義好的那些形狀。
1初始化形狀
在做任何繪製之前,你必須初始化形狀並加載它。除非形狀的結構(原始座標)在程序執行過程中發生了改變,都應該在你的Renderer類的onSurfaceCreated()方法中進行初始化內存和處理效率。public void onSurfaceCreated(GL10 unused, EGLConfig config) {
...
// 初始化一個三角形
mTriangle = new Triangle();
// 初始化一個正方形
mSquare = new Square();
}
2繪製一個形狀
使用OpenGL ES 2.0繪製一個定義好的形狀需要大量的代碼,因爲必須提供給圖形渲染管道很多細節信息。具體定義如下:2.1VertexShader:用於呈現形狀頂點的OpenGL ES圖形代碼。
2.2FragmentShader:用於呈現形狀外觀(顏色或紋理)的OpenGL ES代碼。
2.3Program:一個OpenGL ES對象,包含了你想要用來繪製一個或多個形狀的shader。
你至少需要一個vertex shader來繪製一個形狀和一個fragment shader來爲形狀着色。這些shader必須被編譯,然後將它們添加到一個OpenGL ES program中,接着使用program繪製形狀。這裏有一個例子,演示瞭如何定義基本的shader來繪製一個形狀:
private final String vertexShaderCode =
"attribute vec4 vPosition;" +
"void main() {" +
" gl_Position = vPosition;" +
"}";
private final String fragmentShaderCode =
"precision mediump float;" +
"uniform vec4 vColor;" +
"void main() {" +
" gl_FragColor = vColor;" +
"}";
Shader包含OpenGL Shading Language(GLSL)代碼,必須在OpenGL ES環境下先編譯再使用。想要編譯這些代碼,需要在你的Renderer類中創建一個工具類方法:
public static int loadShader(int type, String shaderCode){
// 創建一個vertex shader類型(GLES20.GL_VERTEX_SHADER)
// 或一個fragment shader類型(GLES20.GL_FRAGMENT_SHADER)
int shader = GLES20.glCreateShader(type);
// 將源碼添加到shader並編譯它
GLES20.glShaderSource(shader, shaderCode);
GLES20.glCompileShader(shader);
return shader;
}
爲了繪製形狀,必須編譯shader代碼,接着將它們添加到一個OpenGL ES program 對象中,然後鏈接這個program。可以在你的renderer對象的構造器中做這些事情,因爲只需要執行一次。
注:編譯OpenGL ES shader和鏈接program是很耗CPU的,所以你應該儘量避免多次執行它們。如果在運行時還不知道shader的內容,那麼就應該只創建一次代碼,然後緩存起來以備後用。
public Triangle() {
...
int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode);
int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);
mProgram = GLES20.glCreateProgram(); // 創建空的OpenGL ES Program
GLES20.glAttachShader(mProgram, vertexShader); // 將vertex shader添加到program
GLES20.glAttachShader(mProgram, fragmentShader); // 將fragment shader添加到program
GLES20.glLinkProgram(mProgram); // 創建可執行的 OpenGL ES program
}
此時,應該可以添加真正的繪製調用了。你需要提供一些參數給渲染管道,告訴它想要繪製什麼以及如何繪製。因爲繪製操作是因形狀而異的,讓形狀類包含特定的繪製邏輯是一個不錯的設計。
創建一個draw()方法負責繪製形狀。下面的代碼將展示向形狀的vertex shader和fragment shader設置位置和顏色值,然後執行繪製操作。
public void draw() {
// 添加program到OpenGL ES環境中
GLES20.glUseProgram(mProgram);
// 獲取指向vertex shader的成員vPosition的handle
mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
// 啓用一個指向三角形的頂點數組的handle
GLES20.glEnableVertexAttribArray(mPositionHandle);
// 準備三角形的座標數據
GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX,
GLES20.GL_FLOAT, false,
vertexStride, vertexBuffer);
// 獲取指向fragment shader的成員vColor的handle
mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");
// 設置三角形的顏色
GLES20.glUniform4fv(mColorHandle, 1, color, 0);
// 繪製三角形
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount);
// 禁用指向三角形的頂點數組
GLES20.glDisableVertexAttribArray(mPositionHandle);
}
一旦你完成了這些代碼,繪製這個對象只需要在Renderer類的onDrawFrame()方法中調用draw()方法。當你運行應用程序時,它看起來應該是這樣的:
此示例中的代碼還存在很多問題。首先,它不會給人留下深刻印象。其次,當你改變設備屏幕的方向時,三角形會被壓扁和改變形狀。原因是它的各個頂點無法根據屏幕的寬高比例進行修正。可以使用投影和相機視圖來解決這個問題。不過那是下一節的內容了。
最後,三角形是靜止不動的,這樣看起來有點無聊。在後續內容中,我們還將介紹如何使用OpenGL ES圖形管道讓形狀旋轉起來,以及更多有趣的用法。