定義三角形
OpenGL 允許我們使用三維座標來定義物體。在繪製三角形前,我們需要定義它各個點的座標。我們一般使用數組來儲存各個頂點的座標。
OpenGL ES 預設 [0,0,0] (X,Y,Z) 在GLSurfaceView的中心,[1,1,0]在右上方,[-1,-1,0]在左下角。
繪製三角形
在繪製三角形之前,我們必須告訴OpenGL我們正在使用頂點數組。然後我們才使用繪製函數畫出三角形。
實驗步驟:
1. 添加新的類Triangle
代碼如下:
[java] <span style="font-size:16px;">public class Triangle {
public Triangle()
{
float triangleCoords[] = {
// X, Y, Z 這是一個等邊三角形
-0.5f, -0.25f, 0,
0.5f, -0.25f, 0,
0.0f, 0.559016994f, 0
};
// 初始化三角形的頂點緩衝
ByteBuffer vbb = ByteBuffer.allocateDirect(
// (# of coordinate values * 4 bytes per float)
triangleCoords.length * 4);
vbb.order(ByteOrder.nativeOrder());// 使用裝置硬體本身的位元組序
triangleVB = vbb.asFloatBuffer(); // 從ByteBuffer中建立一個浮點緩衝
triangleVB.put(triangleCoords); // 向浮點緩衝中添加頂點座標
triangleVB.position(0); // 使緩衝讀第一個座標
}
public void draw(GL10 gl)
{
gl.glColor4f(0.63671875f, 0.76953125f, 0.22265625f, 0.0f); //設定使用中色彩
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, triangleVB);//設定頂點
gl.glDrawArrays(GL10.GL_TRIANGLES, 0, 3);//繪製三角形
}
private FloatBuffer triangleVB;
}
</span>
<span style="font-size:16px;">public class Triangle {
public Triangle()
{
float triangleCoords[] = {
// X, Y, Z 這是一個等邊三角形
-0.5f, -0.25f, 0,
0.5f, -0.25f, 0,
0.0f, 0.559016994f, 0
};
// 初始化三角形的頂點緩衝
ByteBuffer vbb = ByteBuffer.allocateDirect(
// (# of coordinate values * 4 bytes per float)
triangleCoords.length * 4);
vbb.order(ByteOrder.nativeOrder());// 使用裝置硬體本身的位元組序
triangleVB = vbb.asFloatBuffer(); // 從ByteBuffer中建立一個浮點緩衝
triangleVB.put(triangleCoords); // 向浮點緩衝中添加頂點座標
triangleVB.position(0); // 使緩衝讀第一個座標
}
public void draw(GL10 gl)
{
gl.glColor4f(0.63671875f, 0.76953125f, 0.22265625f, 0.0f); //設定使用中色彩
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, triangleVB);//設定頂點
gl.glDrawArrays(GL10.GL_TRIANGLES, 0, 3);//繪製三角形
}
private FloatBuffer triangleVB;
}
</span>
2. 在myGLRenderer類中新增成員privateTriangle mTriangle並在建構函式中初始化。
代碼如下:
[java] <span style="font-size:16px;">public myGLRenderer()
{
mTriangle = new Triangle();
}
</span>
<span style="font-size:16px;">public myGLRenderer()
{
mTriangle = new Triangle();
}
</span>
3. 在myGLRenderer類的onSurfaceCreated()函數最後添加glEnableClientState()方法來啟用頂點數組。
代碼如下:
[java] <span style="font-size:16px;">@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
// TODO Auto-generated method stub
gl.glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
}
</span>
<span style="font-size:16px;">@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
// TODO Auto-generated method stub
gl.glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
}
</span>
4. 在myGLRenderer類的onDrawFrame()函數最後添加三角形繪製方法。
代碼如下:
[java] <span style="font-size:16px;">@Override
public void onDrawFrame(GL10 gl) {
// TODO Auto-generated method stub
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
mTriangle.draw(gl);
}
</span>
<span style="font-size:16px;">@Override
public void onDrawFrame(GL10 gl) {
// TODO Auto-generated method stub
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
mTriangle.draw(gl);
}
</span>
這樣,我們便完成了一個平面三角形的繪製。但我們發現這個三角形並不像我們定義的那樣是一個等邊三角形,這是由於OpenGL總假設我們的螢幕是一個正方形,這樣在繪製的時候最終圖形會隨著螢幕長寬比例的不同而被展開。為了得到正確的顯示,我們需要將圖形投影到正確的位置。這一功能我們在下一節進行實現。
Android裝置螢幕通常不是正方形的,而OpenGL總是預設地將正方形座標系投影到這一裝置上,這就導致圖形無法按真實比例顯示。要解決這一問題,我們可以使用OpenGL 的投影模式和相機視圖將圖形的座標進行轉換以適應不同的裝置顯示。
實驗步驟:
1. 修改myGLRenderer類的onSurfaceCreated()函數來啟用GL10.GL_PROJECTION模式,計算螢幕的長寬比並使用這一比例來轉換物體的座標。
代碼如下:
[python] @Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
// TODO Auto-generated method stub
gl.glViewport(0, 0, width, height);
float ratio = (float) width / height;
gl.glMatrixMode(GL10.GL_PROJECTION); // 設定當前矩陣為投影矩陣
gl.glLoadIdentity(); // 重設矩陣為初始值
gl.glFrustumf(-ratio, ratio, -1, 1, 3, 7); // 根據長寬比設定投影矩陣
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
// TODO Auto-generated method stub
gl.glViewport(0, 0, width, height);
float ratio = (float) width / height;
gl.glMatrixMode(GL10.GL_PROJECTION); // 設定當前矩陣為投影矩陣
gl.glLoadIdentity(); // 重設矩陣為初始值
gl.glFrustumf(-ratio, ratio, -1, 1, 3, 7); // 根據長寬比設定投影矩陣
}
2. 修改myGLRenderer的onDrawFrame()方法,啟用MODELVIEW模式,並使用GLU.gluLookAt()來設定視點。
代碼如下:
[java] @Override
public void onDrawFrame(GL10 gl) {
// TODO Auto-generated method stub
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
// 設定當前矩陣為模型視圖模式
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity(); // reset the matrix to its default state
// 設定視點
GLU.gluLookAt(gl, 0, 0, -5, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
mTriangle.draw(gl);
}
@Override
public void onDrawFrame(GL10 gl) {
// TODO Auto-generated method stub
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
// 設定當前矩陣為模型視圖模式
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity(); // reset the matrix to its default state
// 設定視點
GLU.gluLookAt(gl, 0, 0, -5, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
mTriangle.draw(gl);
}
這樣,我們繪製的圖形比例就總是正確的,不再受裝置的影響而被展開變形了。
摘自 北京大學-Google Android實驗室