1、前言
選擇繪制三角形作為OpenGL ES的第一個實例,是因為點、線、三角形是OpenGL ES世界的圖形基礎(chǔ),無論多么復(fù)雜的幾何物體,在OpenGL ES的世界里都可以用三角形拼成
2、步驟
依照官方文檔中的說明,Android中利用OpenGL ES 2.0繪制三角形的步驟為:
2.1在AndroidManifest.xml文件中設(shè)置使用的OpenGL ES的版本:
<uses-feature android:glEsVersion="0x00020000" android:required="true" />
GLSurfaceView glv = findViewById(R.id.glv);
//必須代碼設(shè)置版本
glv.setEGLContextClientVersion(2);
2.2毫無疑問的,顯示三角形,需要一個載體。創(chuàng)建顯示三角形的Activity,利用GLSurfaceView作為顯示三角形的View,圖形的具體渲染工作都是在Render中完成的。
3. 實現(xiàn)GLSurfaceView的Render,在Render中完成三角形的繪制,具體行為有:
1、加載頂點和片元著色器
2、確定需要繪制圖形的坐標(biāo)和顏色數(shù)據(jù)
3、創(chuàng)建program對象,連接頂點和片元著色器,鏈接program對象。
4、設(shè)置視圖窗口(viewport)。
5、將坐標(biāo)數(shù)據(jù)顏色數(shù)據(jù)傳入OpenGL ES程序中
6、使顏色緩沖區(qū)的內(nèi)容顯示到屏幕上。
3、具體實現(xiàn)
我們設(shè)置好OpenGL ES版本、創(chuàng)建入口Activity并設(shè)置好GLSurfaceView做為顯示載體后,就進入了我們最主要的工作了。
3.1 第一步
首先,我們需要編寫一個簡單的頂點著色器和一個簡單的片元著色器:
頂點著色器:
private final String vertextShaderCode =
"attribute vec4 vPosition;"+
"void main() {"+
" gl_Position = vPosition;"+
"}";
片元著色器:
private final String fragmentShaderCode =
"precision mediump float;"+
"uniform vec4 vColor;"+
"void main() {"+
" gl_FragColor = vColor;"+
"}";
gl_Position和gl_FragColor都是Shader的內(nèi)置變量,分別為定點位置和片元顏色。
3.2 第二步
然后,我們確定要繪制的圖形的頂點坐標(biāo)和顏色:
我們現(xiàn)在需要繪制的是在一個三維空間中繪制一個三角形,三角形當(dāng)然是三個頂點了。因為我們?nèi)切沃皇且粋€平面圖形。為了方便,我們現(xiàn)在在不設(shè)置相機(相機在后面講)的情況下,三角形正對我們來呈現(xiàn)。所以我們打三個頂點的Z坐標(biāo)都設(shè)置為0。OpenGL ES坐標(biāo)映射到屏幕上,從屏幕中心垂直到上下左右邊緣距離都是1.0,所以(-1.0,0,0)和(0,1.0,0)到原點的距離在屏幕上呈現(xiàn)出來的結(jié)果是不一樣的,圖解如下(左邊是理想狀態(tài),右邊是實際狀態(tài)):

所以,為了不超出屏幕,我們的坐標(biāo)數(shù)據(jù)設(shè)置為:
private float triangleCoors[] = {
0.5f , 0.5f , 0.0f,
-0.5f , -0.5f , 0.0f,
0.5f , -0.5f , 0.0f
};
顏色數(shù)據(jù),我們設(shè)置為單一顏色:
private float color[] = {
1.0f , 1.0f , 1.0f , 1.0f
};
3.3 第三步
接著我們開始在Render中實現(xiàn)我們的三角形繪制了。Render接口有三個方法,分別為
onSurfaceCreated
onSurfaceChanged
onDrawFrame
在onSurfaceCreated方法中,我們來創(chuàng)建program對象,連接頂點和片元著色器,鏈接program對象。
//設(shè)置背景顏色
GLES20.glClearColor(0.5f,0.5f,0.5f,0.5f);
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
//申請底層空間
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(triangleCoors.length * 4);
byteBuffer.order(ByteOrder.nativeOrder());
//將坐標(biāo)數(shù)據(jù)轉(zhuǎn)換為FloatBuffer,用以傳入給OpenGL ES程序
vertexBuffer = byteBuffer.asFloatBuffer();
//將三角形坐標(biāo)傳入FloatBuffer
vertexBuffer.put(triangleCoors);
vertexBuffer.position(0);
//創(chuàng)建頂點著色器程序
int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertextShaderCode);
//創(chuàng)建片元著色器程序
int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);
if (vertexShader == 0 || fragmentShader == 0)
{
return;
}
//創(chuàng)建一個空的OpenGL ES程序
program = GLES20.glCreateProgram();
//將頂點著色器加入程序
GLES20.glAttachShader(program, vertexShader);
//將片元著色器加入程序
GLES20.glAttachShader(program, fragmentShader);
//連接到著色器程序中
GLES20.glLinkProgram(program);
//將程序加入到OpenGLES2.0環(huán)境
GLES20.glUseProgram(program);
public int loadShader(int type , String shaderCode)
{
//創(chuàng)建空的著色器
int shader = GLES20.glCreateShader(type);
//將著色器程序加到著色器中
GLES20.glShaderSource(shader,shaderCode);
//編譯色器程序
GLES20.glCompileShader(shader);
return shader;
}
3.4 第四步
在onSurfaceChanged中設(shè)置視圖窗口:
GLES20.glViewport(0,0,width,height);
3.5 第五步
最后在onDrawFrame中繪制
if(program == 0)
return;
//獲取頂點著色器的vPosition成員句柄
int vPosition = GLES20.glGetAttribLocation(program, "vPosition");
//啟用vPosition句柄
GLES20.glEnableVertexAttribArray(vPosition);
//傳入但僥幸的坐標(biāo)數(shù)據(jù)
GLES20.glVertexAttribPointer(vPosition,3,GLES20.GL_FLOAT,false,3*4, vertexBuffer);
//獲取片元著色器的vColor成員句柄
int vColor = GLES20.glGetUniformLocation(program, "vColor");
//設(shè)置繪制三角形的顏色
GLES20.glUniform4fv(vColor,1,color,0);
//繪制三角形
GLES20.glDrawArrays(GLES20.GL_TRIANGLES,0,3);
//禁止頂點數(shù)組的句柄
GLES20.glDisableVertexAttribArray(vPosition);