本文來自 翻譯: Draw shapes
繪製圖形
定義圖形之後,你可能想去繪製他們.使用OpenGL ES 2.0繪製圖形需要的代碼會比你想象的多一點,因爲API提供了大量對圖形渲染管線的控制.
這一課講解如何使用OpenGL ES 2.0的API繪製前一課定義的形狀.
初始化圖形
在繪製之前,你必須初始化和加載你要繪製的圖形,除非在運行過程中,圖形結構發生改變,爲了高效利用內存和處理效率,你應該在renderer的OnSurfaceCreated()中初始化他們.
public class MyGLRenderer implements GLSurfaceView.Renderer {
...
private Triangle mTriangle;
private Square mSquare;
public void onSurfaceCreated(GL10 unused, EGLConfig config) {
...
// initialize a triangle
mTriangle = new Triangle();
// initialize a square
mSquare = new Square();
}
...
}
繪製圖形
使用OpenGL ES 2.0繪製定義好的圖形需要大量代碼,你要有心裏準備,之所以需要大量代碼,是因爲你必須爲渲染管線提供詳細的信息,通常,你必須按照如下來定義:
Vertex Shader - OpenGL ES 渲染圖形頂點的頂點着色器.
Fragment Shader - OpenGL ES 使用文理或者顏色渲染圖形表面的片段着色器.
Program - An OpenGL ES 包含一個或者多個用來繪製圖形的頂點着色器的OpenGL ES 對象.
你至少需要一個繪製圖形的頂點着色器和一個用來給圖形表面着色的片段着色器.這些着色器必須要編譯後放入OpenGL ES 程序中,然後就可以用來繪製圖形.下面是在三角形中定義的能用來繪製圖形的着色器一個示例:
public class Triangle {
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;" +
"}";
...
}
着色器包含OpenGL着色語言(GLSL)代碼,必須在使用前預編譯.爲了編譯這段代碼,在你的renderer類中創建一個公共的方法:
public static int loadShader(int type, String shaderCode){
// create a vertex shader type (GLES20.GL_VERTEX_SHADER)
// or a fragment shader type (GLES20.GL_FRAGMENT_SHADER)
int shader = GLES20.glCreateShader(type);
// add the source code to the shader and compile it
GLES20.glShaderSource(shader, shaderCode);
GLES20.glCompileShader(shader);
return shader;
}
爲了繪製圖形,必須變異着色器代碼並把他們加到OpenGL ES程序對象中,然後建立鏈接.在繪製圖形的構造方法中執行,只需要依次操作就可以了.
注意:
編譯OpenGL ES 着色器並與程序鏈接對CPU週期和處理時間而言,是非常耗時的,所以儘量避免操作次數超過一次.如果你不知道着色器在運行時的內容,你就應該像那樣只創建依次然後緩存起來以便後續使用.
public class Triangle() {
...
private final int mProgram;
public Triangle() {
...
int vertexShader = MyGLRenderer.loadShader(GLES20.GL_VERTEX_SHADER,
vertexShaderCode);
int fragmentShader = MyGLRenderer.loadShader(GLES20.GL_FRAGMENT_SHADER,
fragmentShaderCode);
// create empty OpenGL ES Program
mProgram = GLES20.glCreateProgram();
// add the vertex shader to program
GLES20.glAttachShader(mProgram, vertexShader);
// add the fragment shader to program
GLES20.glAttachShader(mProgram, fragmentShader);
// creates OpenGL ES program executables
GLES20.glLinkProgram(mProgram);
}
}
現在,你已經準備好了即將使用真正的調用來繪製你的圖形.使用OpenGL ES 繪製圖形要求你提供幾個參數來告訴渲染管線,你想要繪製什麼以及如何繪製他們.由於繪製選項可能因圖形不同而不同,因此最好讓圖形包含自己的繪製邏輯.
爲繪製圖形創建一個draw()方法,這段代碼給頂點着色器設置了繪製起點,給片段着色器設置了顏色,然後執行繪製方法:
public void draw() {
// Add program to OpenGL ES environment
GLES20.glUseProgram(mProgram);
// get handle to vertex shader's vPosition member
mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
// Enable a handle to the triangle vertices
GLES20.glEnableVertexAttribArray(mPositionHandle);
// Prepare the triangle coordinate data
GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX,
GLES20.GL_FLOAT, false,
vertexStride, vertexBuffer);
// get handle to fragment shader's vColor member
mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");
// Set color for drawing the triangle
GLES20.glUniform4fv(mColorHandle, 1, color, 0);
// Draw the triangle
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount);
// Disable vertex array
GLES20.glDisableVertexAttribArray(mPositionHandle);
}
只要所有的代碼是正確的,繪製這個圖形只需要在renderer.onDrawFrame()中調用這個圖形對象的 draw()方法
Once you have all this code in place, drawing this object just requires a call to the draw()
method from within your renderer’s onDrawFrame()
method:
public void onDrawFrame(GL10 unused) {
...
mTriangle.draw();
}
然後運行程序,他應該看起來像這樣:
代碼示例中有幾個問題.它不能讓你的朋友感到驚訝.第二,三角形有一點變形而且當你改變設備屏幕方向時,形狀也會發生變化.圖形發生變形的原因是圖形的頂點在屏幕顯示區域中的GLSurfaceView的比例沒有被修正.你可以在下一下課中使用投影和相機視角修復這個問題.
最後,這個三角形是靜止的,沒什麼意思.在下一課(添加運動)中,你能夠用OpenGL ES圖形管線使它旋轉起來,做更多有趣的事!