OpenGL編程

OpenGL作爲強大的圖形接口,可以畫出豐富且動感十足的動畫,但因涉及到很多理論東西和數學知識,所以往往看書能看死一片人,來直接看看源代碼吧,裏面包含了詳細的註解:當然,我們還是先看看效果圖:


首先我們需要實現GLSurfaceView.Renderer這樣一個內部接口來爲我們繪製圖形,看源碼AbstractRenderer文件:

public abstract class AbstractRenderer implements GLSurfaceView.Renderer {

	//	GL10接口包含了java(TM)程序語言爲OpenGL綁定的核心功能
	public void onDrawFrame(GL10 gl) {
		
		// glDisable()方法是關閉某些功能,下面這句是關閉抗抖動
		gl.glDisable(GL10.GL_DITHER);
		
		// glClear()方法時擦除繪圖表面
		// GL_COLOR_BUFFER_BIT --- 顏色緩衝區
		// GL_DEPTH_BUFFER_BIT --- 深度緩衝區
		// GL_STENCIL_BUFFER_BIT --- 模型緩衝區
		gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
		
		// glMatrixMode指明那個矩陣是當前矩陣
		// GL_MODELVIEW --- 應用視圖矩陣堆的後續矩陣操作
		// GL_PROJECTION --- 應用投射矩陣堆的後續矩陣操作
		// GL_TEXTURE --- 應用文理矩陣堆的後續矩陣操作
		// GL_MATRIX_PALETTE_OES --- 啓用矩陣調色板堆棧擴展,並應用矩陣調色板堆棧後續操作 
		gl.glMatrixMode(GL10.GL_MODELVIEW);
		
		// 使用特徵矩陣代替當前矩陣
		gl.glLoadIdentity();
		
		// 輔助函數,提供一個更直觀的方法來設置modelview變換矩陣,也就是控制照相機的方向
		// 前三個浮點參數: 指定觀測點的空間座標
		// 中間三個浮點參數:指定被觀測者物體的參考點的座標
		// 後面三個浮點參數: 指定觀測點方向爲“上”的向量
		// 注:這些座標都是採用世界座標
		GLU.gluLookAt(gl, 0, 0, -5, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
		
		// 啓動客戶端的某項功能
		gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
		
		// 開始繪畫,叫給子類完成
		draw (gl);
	}

	public void onSurfaceChanged(GL10 gl, int width, int height) {
		
		// 控制屏幕大小或者相機“膠片”的尺寸
		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);
	}

	public void onSurfaceCreated(GL10 gl, EGLConfig config) {
		gl.glDisable(GL10.GL_DITHER);
		
		// 當擁有解釋的空間時,GL某些方面的行爲可以由hints控制
		gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST);
		gl.glClearColor(.5f, .5f, .5f, 1);
		gl.glShadeModel(GL10.GL_SMOOTH);
		gl.glEnable(GL10.GL_DEPTH_TEST);
	}
	
	protected abstract void draw (GL10 gl);
	
}



這樣我們在自定義一個實現類,來繪製我們自己的圖形,SimpleTriangleRender文件:

public class SimpleTriangleRender extends AbstractRenderer {

	// 三角形的三個點
	private final static int VERTS = 3;

	private FloatBuffer mFVertexBuffer;
	private ShortBuffer mIndexBuffer;

	public SimpleTriangleRender(Context context) {

		// 創建一個字節緩衝區,每個點有3個浮點值,因爲它有三個座標,每個浮點值佔用4字節,所以需要3 * 4,而一個三角
		// 行有3個頂點,故需要3 * 3 * 4個字節空間來存放
		ByteBuffer vbb = ByteBuffer.allocateDirect(VERTS * 3 * 4);

		// 使用本機字節順序對緩衝字節進行排序
		vbb.order(ByteOrder.nativeOrder());

		// 收集緩衝字節到本地緩衝區中
		mFVertexBuffer = vbb.asFloatBuffer();

		ByteBuffer ibb = ByteBuffer.allocateDirect(VERTS * 2);
		ibb.order(ByteOrder.nativeOrder());
		mIndexBuffer = ibb.asShortBuffer();

		// 一次放入數據,下同
		float[] coords = { -0.5f, -0.5f, 0, 0.5f, -0.5f, 0, 0.0f, 0.5f, 0 };
		for (int i = 0; i < VERTS; i++) {
			for (int j = 0; j < 3; j++) {
				mFVertexBuffer.put(coords[i * 3 + j]);
			}
		}
		short[] myIndecesArray = { 0, 1, 2 };
		for (int i = 0; i < 3; i++) {
			mIndexBuffer.put(myIndecesArray[i]);
		}
		mFVertexBuffer.position(0);
		mIndexBuffer.position(0);
	}

	protected void draw(GL10 gl) {

		// 設置當前顏色, R,G,B,alpha
		gl.glColor4f(1.0f, 0, 0, 0.5f);

		// 定義一個頂點座標矩陣
		// 第一個參數是維數,二維則爲2,三維則爲3
		// 第二個參數表示座標需要解釋爲浮點數
		// 第三個參數表示每個點分開的字節數
		// 第四個參數是指向緩衝區的指針
		gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mFVertexBuffer);

		// 按照OpenGL ES所支持的一種原始形狀來繪製這些點
		// 第一個參數:繪製的幾何圖形
		// 第二個參數:指明被渲染的元素個數
		// 第三個參數:指向索引指的類型
		// 第四個參數:指向索引緩衝區
		gl.glDrawElements(GL10.GL_TRIANGLES, VERTS, GL10.GL_UNSIGNED_SHORT,
				mIndexBuffer);
	}

}

最後我們在Activity中呈現我們所畫出的東西出來,OpenGLTestHarnessActivity文件:

public class OpenGLTestHarnessActivity extends Activity {

	//***************************************
	//	GLSurfaceView類提供如下功能:
	//	* 在OpenGL ES和view系統之間建立聯繫
	//	* 使得OpenGL ES可以工作在Activity生命週期中
	//	* 可以選擇合適的frame buffer像素格式
	//	* 創建並管理一個單獨的渲染線程,可以實現平滑的動畫
	//	* 提供debugging工具和API
	//***************************************
	private GLSurfaceView mTestHarness = null;

	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		// setContentView(R.layout.activity_main);
		mTestHarness = new GLSurfaceView(this);
		
		//If no setEGLConfigChooser method is called, then by default the view will choose an RGB_565 
		//surface with a depth buffer depth of at least 16 bits.
		//	無需特殊的EGL配置選擇程序,採用默認的配置即可
		mTestHarness.setEGLConfigChooser(false);	
		
		//	GLSurfaceView.Renderer接口支持使用派生類進行繪製。它允許GLSurfaceView在表面發生改變時調用它來進行繪製,
		//  這是程序員通常使用的主要接口
		mTestHarness.setRenderer(new SimpleTriangleRender (this));
		
		// 渲染模式	1、GLSurfaceView.RENDERMODE_WHEN_DIRTY --- 通知渲染;一般是等待用戶交互時進行渲染
		//			2、GLSurfaceView.RENDERMODE_CONTINUOUSLY --- 持續渲染;大多數3D遊戲都是進行持續渲染的
		mTestHarness.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
		
		setContentView(mTestHarness);
	}

	protected void onPause() {
		super.onPause();
		mTestHarness.onPause();
	}

	protected void onResume() {
		super.onResume();
		mTestHarness.onResume();
	}
	
	

}


到此基本上就結束了,你可以將OpenGLTestHarnessActivity設置爲主Activity,也可以在主Activity中通過Intent來啓動這個Activity,最後看到了結果。

我們總結一下使用OpenGL ES畫圖的基本步驟吧:

 * 1、實現Renderer接口
 * 2、在呈現器的實現中提供繪圖所必需的Camera設置
 * 3、在實現的onDrawFrame方法中提供繪圖代碼
 * 4、構造GLSurfaceView
 * 5、設置在GLSurfaceView中實現的呈現器
 * 6、指定是否需要將GLSurfaceView製作成動畫
 * 7、在Activity中將GLSurfaceView設置爲內容視圖(也可以在使用常規視圖的地方使用此視圖)

發佈了22 篇原創文章 · 獲贊 19 · 訪問量 23萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章