一般來說,學繪圖的HelloWorld應該是要來劃一個三角形(Triangle),下面我綜合參考了
Jayway Team Blog:OpenGL ES Tutorial for Android –Part II– Building a polygon
3D Graphics using OpenGL ES (Including Nehe's Port)Example 2
來完成建立多邊形這個教學!
在開始建立程式前,先補充說明在建立3D模型時,需要用到的一些子元素
(頂點、邊、表面和多邊形),他們都能獨立的分別被實做出來。
頂點是構成3D模型的最小建物,他是由兩個或兩個以上的邊交界而成的點。一個頂點可以在所有相關聯的邊、面和多邊形中共用。頂點也可以是照相機或光源位置的表示。在Android中,我們浮點數陣列來定義它,同時我們將它放在byte buffer中以獲取較佳的效能。
private float vertices[] = {
-1.0f, 1.0f, 0.0f, // 0, Top Left
-1.0f, -1.0f, 0.0f, // 1, Bottom Left
1.0f, -1.0f, 0.0f, // 2, Bottom Right
1.0f, 1.0f, 0.0f, // 3, Top Right
};
// a float is 4 bytes, therefore we multiply the number if vertices with 4.
ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4);
vbb.order(ByteOrder.nativeOrder());
FloatBuffer vertexBuffer = vbb.asFloatBuffer();
vertexBuffer.put(vertices);
vertexBuffer.position(0);
要注意的一個浮點數是4個位元組,將它和頂點數相乘,才可以正確的配置buffer大小。
邊是在兩個頂點之間的線段。它們是表面和多邊形的邊緣線。在3D模型中,便可以在 兩個鄰近表面或多邊形之間共用。轉換一條邊,影響所有相連接的頂點,面和多邊形 。在OpenGL ES中,我們不能定義邊,你只能通過給定的頂點定義面,這將至少構建三條邊。如果你想要修改一條邊,你應該改變產生這條邊的兩個頂點。
面是一個三角形,面就是這三個頂點和三個邊所圍成的表面,變換一個面影響所有關聯 的頂點,邊和多邊形。對於這些元素的介紹先到這裡,Jayway還有一些細部的介紹,都還蠻有價值的,但我相信大家沒看到code就很難過,我們就先來畫畫三角形吧!
Triangle.java
com.hanshuo.opengl.tutorial;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import javax.microedition.khronos.opengles.GL10;
/*
* A triangle with 3 vertices.
*/
public class Triangle {
private FloatBuffer vertexBuffer; // 頂點陣列的緩衝
private ByteBuffer indexBuffer; // 索引緩衝
private float[] vertices = { // 三角形的頂點們
0.0f, 1.0f, 0.0f, // 0. 頂
-1.0f, -1.0f, 0.0f, // 1. 左下
1.0f, -1.0f, 0.0f // 2. 右下
};
private byte[] indices = { 0, 1, 2 }; // 連結這些點的順序
// 建構子 – 建立資料陣列的緩衝
public Triangle() {
// 建立頂點陣列緩衝. 頂點是浮點數要乘4個byte.
ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4);
vbb.order(ByteOrder.nativeOrder()); // 使用原生順序
vertexBuffer = vbb.asFloatBuffer(); // 轉換位元組緩衝為浮點數
vertexBuffer.put(vertices); // 將資料複製到緩衝
vertexBuffer.position(0); // 倒轉歸零
//建立頂點索引陣列緩衝
indexBuffer = ByteBuffer.allocateDirect(indices.length);
indexBuffer.put(indices);
indexBuffer.position(0);
}
// 渲染這個圖形
public void draw(GL10 gl) {
// Enable vertex-array and define the buffers
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
// int size, int type, int stride, Buffer pointer
// size: 頂點的座標數 (只有2,3,4).
// type: 頂點座標的資料型態, GL_BYTE, GL_SHORT, GL_FIXED, or GL_FLOAT
// stride: 連續頂點可以有幾個byte的offset. 0是緊密的包裝?
// 透過index-array繪製元素
gl.glDrawElements(GL10.GL_TRIANGLES, indices.length, GL10.GL_UNSIGNED_BYTE, indexBuffer);
// int mode, int count, int type, Buffer indices)
// mode: GL_POINTS, GL_LINE_STRIP, GL_LINE_LOOP, GL_LINES, GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN, or GL_TRIANGLES
// count: 有幾個元素將要被渲染
// type:頂點的資料型態 (must be GL_UNSIGNED_BYTE or GL_UNSIGNED_SHORT).
// indices:index array的指標
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
}
}
TutorialPartI.java (藍色是新的程式碼)
package com.hanshuo.opengl.tutorial;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import android.content.Context;
import android.opengl.GLU;
import android.opengl.GLSurfaceView.Renderer;
public class OpenGLRenderer implements Renderer {
Triangle triangle;
public OpenGLRenderer() {
// Set up the data-array buffers for these shapes (多了這裡)
triangle = new Triangle();
//
(多了這裡)
}
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
// 將背景設成紅色 (rgba).
gl.glClearColor(1.0f, 0.0f, 0.0f, 0.0f);
// 允許陰影平滑, 預設也可以,不是必須的
gl.glShadeModel(GL10.GL_SMOOTH);
// 深度緩衝設置
gl.glClearDepthf(1.0f);
// 允許深度測試
gl.glEnable(GL10.GL_DEPTH_TEST);
// 深度檢測類型
gl.glDepthFunc(GL10.GL_LEQUAL);
// 精細度設置
gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST);
}
public void onDrawFrame(GL10 gl) {
// 清除螢幕和深度緩衝
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
gl.glLoadIdentity();
// Reset model-view matrix
(多了這裡)
gl.glTranslatef(-1.5f, 0.0f, -6.0f);
// Translate left and into the screen
(多了這裡)
triangle.draw(gl);
// Draw triangle
(多了這裡)
}
執行結果:
有沒有很簡單捏~