OpenGL ES基礎教程
阿新 • • 發佈:2019-01-22
一、設定OpenGL ES檢視
設定OpenGL檢視並不難,Android上也較簡單。我們一般只需要2個步驟。
GLSurfaceView
我們要為GLSurfaceView提供一個專門用於渲染的介面
public void setRenderer(GLSurfaceView.Renderer renderer)
GLSurfaceView.Renderer
GLSurfaceView.Renderer是一個通用渲染介面。我們必須實現下面的三個抽象方法:
// 畫面建立
public void onSurfaceCreated(GL10 gl, EGLConfig config)
// 畫面繪製
public void onDrawFrame(GL10 gl)
// 畫面改變
public void onSurfaceChanged(GL10 gl, int width, int height)
onSurfaceCreated
在這裡我們主要進行一些初始化工作,比如對透視進行修正、設定清屏所用顏色等。
onDrawFrame
繪製當前畫面
onSurfaceChanged
當裝置水平或者垂直變化時呼叫此方法,設定新的顯示比例
案例程式碼:
- public class OpenGLDemo extends Activity {
- @Override
- public void onCreate(Bundle savedInstanceState) {
- GLSurfaceView view = new GLSurfaceView(this);
- view.setRenderer(new OpenGLRenderer());
- setContentView(view);
- }
- }
- public void onSurfaceCreated(GL10 gl, EGLConfig config) {
- // 黑色背景
- gl.glClearColor(0.0f, 0.0f, 0.0f, 0.5f);
- // 啟用陰影平滑(不是必須的)
- 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);
- }
- public void onSurfaceChanged(GL10 gl, int width, int height) {
- // 設定畫面的大小
- gl.glViewport(0, 0, width, height);
- // 設定投影矩陣
- gl.glMatrixMode(GL10.GL_PROJECTION);
- // 重置投影矩陣
- gl.glLoadIdentity();
- // 設定畫面比例
- GLU.gluPerspective(gl, 45.0f, (float) width / (float) height, 0.1f,100.0f);
- // 選擇模型觀察矩陣
- gl.glMatrixMode(GL10.GL_MODELVIEW);
- // 重置模型觀察矩陣
- gl.glLoadIdentity();
- }
- }
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
設定完檢視後,即可編譯執行,可以看到一個“漂亮”的黑屏 = =!
二、繪製多邊形前面的教程都是關於設定GLSurfaceView.的,接下來的教程將教我們渲染出一個多邊形。3D模型用較小的元素建立(點,邊,面),他們可以被分別操作。
頂點
在Android中,我們通過float陣列定義頂點,並將它放到位元組型緩衝區內來獲取更好的效能。下例的程式碼即為上圖所示頂點。OpenGL ES的很多功能都必須手動的開啟和關閉。
- gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
- // 設定頂點資料,3代表XYZ座標系
- gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
- // 關閉頂點設定
- gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
面
計算多邊形面的時候,一定要注意正確的方向.。因為這將決定哪一面為正面哪一面為背面。 所以我們儘量保證整個專案都使用相同的環繞。gl.glFrontFace(GL10.GL_CCW);控制多邊形的正面是如何決定的。在預設情況下,mode是GL_CCW。mode的值為: GL_CCW 表示視窗座標上投影多邊形的頂點順序為逆時針方向的表面為正面。 GL_CW 表示頂點順序為順時針方向的表面為正面。頂點的方向又稱為環繞。gl.glEnable(GL10.GL_CULL_FACE);gl.glCullFace(GL10.GL_BACK);剔除多邊形的背面,禁用多邊形背面上的光照、陰影和顏色計算及操作。gl.glDisable(GL10.GL_CULL_FACE);
多邊形
到了繪製面的時候了, 我們使用預設的逆時針環繞。下例程式碼將繪製上圖多邊形。
- // 將座標陣列放入位元組快取中
- // (1) 分配快取,一個short為2個位元組,所以要乘以2
- ByteBuffer ibb = ByteBuffer.allocateDirect(indices.length * 2);
- // (2) 設定位元組處理規則
- ibb.order(ByteOrder.nativeOrder());
- // (3) 轉換為short型字元
- ShortBuffer indexBuffer = ibb.asShortBuffer();
- // (4) 放入座標陣列
- indexBuffer.put(indices);
- // (5) 復位
- indexBuffer.position(0);
Mode:GL_POINTS繪製獨立的點到螢幕
GL_LINE_STRIP連續的連線,第n個頂點與第n-1個頂點繪製一條直線
GL_LINE_LOOP和上面相同,但首尾相連
GL_LINES各對獨立的線段
GL_TRIANGLES各個獨立的三角形
GL_TRIANGLE_STRIP
繪製一系列的三角形,先是頂點 v0, v1, v2, 然後是 v2, v1, v3 (注意規律), 然後v2, v3, v4等。該規律確保所有的三角形都以相同的方向繪製。
GL_TRIANGLE_FAN和GL_TRIANGLE_STRIP類似, 但其先繪製 v0, v1, v2, 再是 v0, v2, v3, 然後 v0, v3, v4等。
我認為GL_TRIANGLES是使用最方便的,所以我們將先使用它。
- public class Square {
- // 頂點座標陣列
- private float vertices[] = { -1.0f, 1.0f, 0.0f, // 0, 左上
- -1.0f, -1.0f, 0.0f, // 1, 左下
- 1.0f, -1.0f, 0.0f, // 2, 右下
- 1.0f, 1.0f, 0.0f, // 3, 右上
- };
- // 連線規則
- private short[] indices = { 0, 1, 2, 0, 2, 3 };
- // 頂點快取
- private FloatBuffer vertexBuffer;
- // 索引快取
- private ShortBuffer indexBuffer;
- public Square() {
- // 一個float為4 bytes, 因此要乘以4
- ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4);
- vbb.order(ByteOrder.nativeOrder());
- vertexBuffer = vbb.asFloatBuffer();
- vertexBuffer.put(vertices);
- vertexBuffer.position(0);
- // short型別同理
- ByteBuffer ibb = ByteBuffer.allocateDirect(indices.length * 2);
- ibb.order(ByteOrder.nativeOrder());
- indexBuffer = ibb.asShortBuffer();
- indexBuffer.put(indices);
- indexBuffer.position(0);
- }
- /**
- * 繪製正方形到螢幕
- *
- * @param gl
- */
- public void draw(GL10 gl) {
- // 逆時針環繞
- gl.glFrontFace(GL10.GL_CCW);
- // 開啟剔除功能
- gl.glEnable(GL10.GL_CULL_FACE);
- // 剔除背面
- gl.glCullFace(GL10.GL_BACK);
- // 開啟頂點快取寫入功能
- gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
- // 設定頂點
- // size:每個頂點有幾個數指描述。
- // type:陣列中每個頂點的座標型別。
- // stride:陣列中每個頂點間的間隔,步長(位元組位移)。
- // pointer:儲存著每個頂點的座標值。初始值為0
- gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
- gl.glDrawElements(GL10.GL_TRIANGLES, indices.length,
- GL10.GL_UNSIGNED_SHORT, indexBuffer);
- // 關閉各個功能
- gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
- gl.glDisable(GL10.GL_CULL_FACE);
- }
- }
- square = new Square();<!--EndFragment-->
- public void onDrawFrame(GL10 gl) {
- // 清除螢幕和深度快取
- gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
- // 繪製正方形
- square.draw(gl);
- }
- gl.glTranslatef(0, 0, -4); <!--EndFragment-->
- // 重置當前的模型觀察矩陣
- gl.glLoadIdentity();<!--EndFragment-->
OpenGLDemo02.rar (64.87 KB, 下載次數: 460)