OpenGL ES
視頻課:https://edu.csdn.net/course/play/7621?
學習內容
?OpenGL ES的基本概念
?Android下3D開發的基本知識
?利用OpenGL ES進行2D圖形的開發
?利用OpenGL ES進行3D圖形的開發?
能力目標
?了解OpenGL ES的基本概念
?了解Android下3D開發的基本知識
?掌握如何利用OpenGL ES進行2D圖形的開發
掌握如何利用OpenGL ES進行3D圖形的開發
本章簡介
游戲在Android中一個非常重要的開發方向,也是可以預料到的未來Android開發中最賺錢的。從最初單機2D游戲到現在的網絡3D游戲,無論是顯示效果,還是娛樂性上都有了顯著的提高。這其中最重要的功臣就是扮演著重要角色的3D圖形庫。目前在PC領域,一直有兩種標準的3D API進行在競爭:OpenGL?和?DirectX。一般主流的游戲和顯卡都支持這兩種渲染方式,DirectX在Windows平臺上有很大的優勢,但是?OpenGL?具有更好的跨平臺性。在移動平臺上使用到的最多的3D圖形庫就是本章中將要講到的OpenGL ES,我們Android系統的3D?引擎采用的是OpenGL ES圖形庫。
核心技能部分?
3.1?3D開發基本知識
OpenGL(Open Graphics Library)是個定義了一個跨編程語言、跨平臺的編程接口,它用于二維或三維圖象繪制。OpenGL是個專業的圖形程序接口,是一個功能強大,調用方便的底層圖形庫。
OpenGL ES(Open Graphics Library for Embedded System)是一套為手持和嵌入式系統設計的2D/3D輕量圖形庫,它是基于OpenGL API設計的,是OpenGL三維圖形API的一個子集。OpenGL ES是從OpenGL裁剪定制而來的,它去除了OpenGL中很多特性,并針對移動設備改善了圖形顯示效果,大大降低了內存消耗。
OpenGL ES由Khronos公司推廣維護,Khronos是一個圖形軟硬件行業協會,該協會主要關注圖形和多媒體方面的開放標準。OpenGL ES的官方主頁是http:www.khronos.org/opengles
Android系統使用?OpenGL?ES的標準接口來支持3D圖形功能,android 3D?圖形系統也分為?java?框架和本地代碼兩部分。本地代碼主要是實現的?OpenGL?接口的庫,在?Java?框架層,javax.microedition.khronos.opengles?是?java?標準的?OpenGL?包,android.opengl包提供了?OpenGL?系統和?Android GUI?系統之間的聯系。
OpenGL ES不僅可以繪制3D圖形,還可以繪制2D圖形。OpenGL ES只能繪制三角形,但這并不影響多邊形的繪制,因為任何模型形都可以拆分成三角形。
OpenGL ES的坐標系是三維的,其中坐標系原點是手機的中心。如下圖3.1.1所示:
?
圖3.1.1 OpenGL ES坐標系?
3.2?繪制2D圖形
在3D桌球之類的游戲中,華麗的界面、流暢的體驗一定給大家留下了深刻的印象。相信大家一定會希望自己也能開發出屬于自己的3D游戲。其實所謂的3D其實也比較簡單,它是由大量的平面圖形按一定的方式組合而成的,比如如下圖3.1.2中的桌球游戲的界面,就可以簡單的認為是由一些矩形、球形組合而成。在接下來的兩節中,我們就分別從2D及3D的角度來講解Android中如何利用OpenGL ES繪制圖形。
?
圖3.1.2 3D桌球
像第一章Android中的繪圖一樣,為了方便程序的編寫,我們也先搭建一個程序框架,以后的程序就在這個框架的基礎之上進行編寫。
搭建OpenGL ES開發框架,需要以下兩步:
(1)提供一個實現了Renderer接口的回調類,并實現這個接口的相關方法。
(2)在Activity類中顯示第一步中的Renderer。
示例2.1
搭建OpenGL ES的基本開發框架。
首先定義Renderer接口的實現類,代碼如下:
public?class?MyRenderer implements?Renderer {
@Override
public?void?onDrawFrame(GL10 gl) {
//可以在這個方法中繪制2D或3D圖形
}
?
@Override
public?void?onSurfaceChanged(GL10 gl, int?width, int?height) {
//可以在這個方法中設置場景的大小
}
?
@Override
public?void?onSurfaceCreated(GL10 gl, EGLConfig config) {
//可以在這個方法中做一些初始化工作,比如設置背景顏色、啟動平滑模型等
}
?
}
上述代碼中的onSurfaceCreated()方法在創建或重建OpenGL ES繪制窗口時會被調用到。可以在這個方法中做一些初始化的操作,比如設置背景顏色、啟動平滑模型等。onSurfaceChanged()在窗口尺寸發生變化時被調用,不管窗口的大小是否發生改變,該方法在程序啟動時至少執行一次,可以在這個方法中設置場景的大小。onDrawFrame(?)在繪制每一幀時被調用,類似于View中的onDraw()方法,一般在這個方法中繪制2D或3D圖形。注意,在繪圖之前一般需要將屏幕清除成指定的顏色、清除深度緩存并重置場景。
上面3個方法的第一個參數的類型都是GL1.0,這是OpenGL ES 1.0的接口,我們就是利用它業完成2D/3D圖形的繪制及渲染的。
再提供一個Activity類,用來顯示我們在上面Renderer類中繪制的圖形,具體的代碼如下:
public?class?Frame3DActivity extends?Activity {
?
@Override
protected?void?onCreate(Bundle?savedInstanceState) {
super.onCreate(savedInstanceState);
GLSurfaceView glView = new?GLSurfaceView(this);
MyRenderer renderer = new?MyRenderer();
glView.setRenderer(renderer);
setContentView(glView);
}
}
接下來,我們在這個程序框架上繪制2D圖形。
示例2.2:
在手機屏幕上繪制一個三角形和一個四邊形,要求三角形沿X軸旋轉、四邊開沿Y軸旋轉。
我們只需要修改示例2.1中的MyRenderer類,為其增加圖形繪制的功能,具體代碼如下:
public?class?MyRenderer?implements?Renderer {
int?one?= 0x10000;
?
private?float?triRotate;
private?float?quaterRotate;
// 三角形三個頂點:上頂點、左下點、右下點
private?IntBuffer triBuffer?= IntBuffer.wrap(new?int[] { 0, one, 0, -one, -one, 0, one, -one, 0, });
private?IntBuffer quaterBuffer?= IntBuffer.wrap(new?int[] { one, one, 0, -one, one, 0, one, -one, 0, -one, -one, 0 });
?
// 三角形的頂點顏色值(r,g,b,a)
private?IntBuffer colorBuffer?= IntBuffer.wrap(new?int[] { one, 0, 0, one, 0, one, 0, one, 0, 0, one, one});
?
@Override
public?void?onDrawFrame(GL10 gl) {
gl.glClear(GL10.GL_COLOR_BUFFER_BIT?| GL10.GL_DEPTH_BUFFER_BIT);// 清除屏幕和深度緩存
?
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);// 允許設置頂點
gl.glEnableClientState(GL10.GL_COLOR_ARRAY);//設置顏色數組,開啟顏色渲染功能
gl.glColorPointer(4, GL10.GL_FIXED, 0, colorBuffer);
gl.glLoadIdentity();// 重置當前的模型觀察矩陣
gl.glTranslatef(-1.5f, 0.0f, -6.0f);// 左移 1.5 單位,并移入屏幕 6.0
gl.glRotatef(triRotate, 0.0f, 1.0f, 0.0f); //設置旋轉,應該在坐標確定后再旋轉
gl.glVertexPointer(3, GL10.GL_FIXED, 0, triBuffer);// 設置三角形
gl.glDrawArrays(GL10.GL_TRIANGLES, 0, 3);// 繪制三角形
gl.glDisableClientState(GL10.GL_COLOR_ARRAY);
gl.glColor4f(1.0f, 0.0f, 0.5f, 1.0f);
gl.glLoadIdentity();// 重置當前的模型觀察矩陣
gl.glTranslatef(1.5f, 0.0f, -6.0f);
gl.glRotatef(quaterRotate, 1.0f, 0.0f, 0.0f); //設置旋轉
gl.glVertexPointer(3, GL10.GL_FIXED, 0, quaterBuffer);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);
?
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);// 取消頂點設置
//改變旋轉角度
triRotate?+= 0.5f;
quaterRotate?-= 0.5f;
}
?
@Override
public?void?onSurfaceChanged(GL10 gl, int?width, int?height) {
float?ratio = (float) width / height;
gl.glViewport(0, 0, width, height);// 設置OpenGL場景的大小
gl.glMatrixMode(GL10.GL_PROJECTION);// 設置投影矩陣
gl.glLoadIdentity();// 重置投影矩陣
gl.glFrustumf(-ratio, ratio, -1, 1, 1, 10);// 設置視口的大小
gl.glMatrixMode(GL10.GL_MODELVIEW);// 選擇模型觀察矩陣
gl.glLoadIdentity();// 重置模型觀察矩陣
}
?
@Override
public?void?onSurfaceCreated(GL10 gl, EGLConfig config) {
gl.glShadeModel(GL10.GL_SMOOTH);// 啟用陰影平滑
gl.glClearColor(0, 0.5f, 0.5f, 0.5f);// 黑色背景
gl.glClearDepthf(1.0f);// 設置深度緩存
gl.glEnable(GL10.GL_DEPTH_TEST);// 啟用深度測試
gl.glDepthFunc(GL10.GL_LEQUAL);// 所作深度測試的類型
gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST);// 告訴系統對透視進行修正
}
?
}
在本示例中我們用到了GL10的大量的方法,現列舉如下:
??void glClear(int mask)
清理緩沖區,也就是glClearColor或者glClearDepth等函數所指定的值來清除指定的緩沖區。參數表明哪個緩沖區需要清理,取值如下表3-1-1所示:
表3-1-1 mask取值及含義
參數mask取值 | 說明 |
GL_COLOR_BUFFER_BIT | 表明顏色緩沖區 |
GL_DEPTH_BUFFER_BIT | 表明深度緩沖區 |
GL_STENCIL_BUFFER_BIT | 表明模型緩沖區 |
?
??void glEnableClientState(int array)
開啟指定功能。默認的所有客戶端功能都是禁用。在OpenGL中使用glEnableClientState之后都要使用glDisableClientState來關閉或取消對應的功能。參數取值如下表3-1-2所示。
給3-1-2 array取值及含義
參數array取值 | 說明 |
GL_COLOR_ARRAY | 如果啟用,顏色矩陣可以用來寫入以及調用glDrawArrays方法或者glDrawElements方法時進行渲染 |
GL_NORMAL_ARRAY | 如果啟用,法線矩陣可以用來寫入以及調用glDrawArrays方法或者glDrawElements方法時進行渲染 |
GL_TEXTURE_COORD_ARRAY | 如果啟用,紋理坐標矩陣可以用來寫入以及調用glDrawArrays方法或者glDrawElements方法時進行渲染 |
GL_VERTEX_ARRAY | 如果啟用,頂點矩陣可以用來寫入以及調用glDrawArrays方法或者glDrawElements方法時進行渲染 |
GL_POINT_SIZE_ARRAY_OES | 如果啟用,點大小矩陣控制大小以渲染點和點sprites。這時由glPointSize定義的點大小將被忽略,由點大小矩陣提供的大小將被用來渲染點和點sprites |
??void glDisableClientState(int array)
關閉指定功能。參數取值參看glEnableClientState()方法的array參數講解。
??void glColorPointer(int size, int type, int stride, Buffer?pointer)
指明渲染時使用的顏色矩陣。其中size指明每個顏色的元素數量,必須為4;type指明每個顏色元素的數據類型,允許的符號常量有GL_UNSIGNED_BYTE, GL_FIXED和GL_FLOAT,初始值為GL_FLOAT;stride指明連續的點之間的位偏移,如果stride為0時,顏色被緊密擠入矩陣,初始值為0;pointer指明包含顏色的緩沖區,如果pointer為null,則為設置緩沖區。
??void glLoadIdentity()
將所選的矩陣狀態恢復成原始狀態,即將當前點移到了屏幕中心。
??void glTranslatef(float x, float y, float z)
將光標移動到指定的位置。其中x指明平移向量的x坐標,y指明平移向量的y坐標,z指明平移向量的z坐標,z必須得在zNear和zFar之間,否則我們看不到圖形的效果。
??void glRotatef(float angle, float x, float y, float z)
將物體沿指定的軸旋轉。其中angle指明旋轉的角度,單位為度,x指明旋轉向量的x坐標,y指明旋轉向量的y坐標,z指明旋轉向量的z坐標
??void glVertexPointer(int size, int type, int stride, Buffer?pointer)
用來設置頂點緩存。其中size用于描述頂點的尺寸,當使用xyz坐標系時,值取3;type頂點的類型,GL10.GL_FIXED表示固定的頂點;stride表示步長;pointer表示頂點緩存。
??void glDrawArrays(int mode, int first, int count)
繪制頂點。其中first表示開始位置,count表示要繪制的頂點數,mode表示繪制的模式,它的具體取值參看下表3-1-3所示 。
表3-1-3:mode取值及含義
mode取值 | 說明 |
GL10.GL_TRIANGLES | 畫三角形 |
GL10.GL_TRIANGLE_STRIP | 畫四邊形,取點順序如下圖3.1.3中左圖所示 |
GL10.GL_TRIANGLE_FAN | 畫四邊開,取點順序如下圖3.1.3中右圖所示 |
?
圖3.1.3 四邊形取點順序
??void ?glColor4f(float red, float green, float blue, float alpha)
設置當前所使用的顏色,之后繪制的所有內容都會使用這個顏色,即使在完全采用紋理貼圖的時候,仍然可以用來調節紋理的色調。利用此方法不需要開啟渲染功能。
??void ?glViewport(int x, int y, int width, int height)
設置OpenGL的場景。其中x指明場景矩形的左下角x坐標,初始值為0;y指明場景矩形的左下角y坐標,初始值為0;width指明場景的寬,如果GL上下文首次附于一個surface則寬、高為這個surface大小;height指明視口的高,如果GL上下文首次附于一個surface則寬、高為這個surface大小。
??void glMatrixMode(int mode)
設置當前矩陣的模式,mode允許的值參看表3-1-4所示。
表3-1-4:mode取值及含義
mode的取值 | 說明 |
GL_MODELVIEW | 應用視圖矩陣堆的后續矩陣操作 |
GL_PROJECTION | 應用投射矩陣堆的后續矩陣操作 |
GL_TEXTURE | 應用紋理矩陣堆的后續矩陣操作 |
GL_MATRIX_PALETTE_OES | 啟用矩陣調色板堆棧擴展,并應用矩陣調色板堆棧 |
?void glFrustumf(float left, float right, float bottom, float top, float zNear, float zFar)
設置窗口的大小。其中前四個參數用于確定窗口的大小,zNear和zFar分別代表所能繪制深度的起點和終點。
?void glShadeModel(int mode)
設置明暗處理模式。所謂明暗處理指的是用單一的顏色或許多不同的顏色來勾畫(或填充)。其中參數mod指明一個符號常量來代表要使用的著色技術。允許的值有GL_FLAT 和GL_SMOOTH,初始值為GL_SMOOTH。
?void glClearColor(float red, float green, float blue, float alpha)
設置清除屏幕時所使用的顏色。色彩范圍從0.0f~1.0f,0.0f最黑,1.0f最亮。
void glClearDepthf(float depth)
指明深度緩沖區的清理值。
void glEnable(int cap)
啟用服務器端GL功能。當參數取值為GL_DEPTH_TEST時表示如果啟用,做深度比較和更新深度緩存。
整個程序的運行效果如下圖3.1.4所示。
?
圖3.1.4 ?繪制的2D圖形效果
在本示例中,我們不僅講到了基本圖形(三角形、矩形)的繪制,還講到了顏色的填充、以及圖形的旋轉的知識,屬于一個比較綜合的案例,也是我們下面繪制3D圖形的基礎。
3.3?繪制3D圖形
我們可以通過這些2D圖形構建簡單的諸如“超級馬里奧”等常見橫版游戲,但隨著手機配置的提高,越來越多的3D游戲已經可以在手機上流暢運行,這也推動著越來越多的程序開發者加入到手機3D游戲的開發中來,那么在Android系統中,我們又如何繪制漂亮的3D圖形呢?
其實繪制2D圖形對于OpenGL ES來說是很簡單的,OpenGL ES的主要功能還是在于繪制3D圖形,它從繪制簡單的立體圖形到設置不同的紋理、以及光照、混合等效果,可謂無所不能。在本節中我們就學習如所利用OpenGL ES來繪制3D圖形
示例3.3
在屏幕上繪制一個三棱錐和一個立方體,然后給這兩個圖形填充上顏色,最后設置三棱錐沿Y軸旋轉,立方體沿X軸旋轉。整個程序的運行效果如下圖3.1.5所示。
?
圖3.1.5 簡單3D圖形效果
修改示例3.1中的MyRenderer類,修改后的代碼如下圖所示:
public?class?GLRenderer3D implements?Renderer {
float?rotateTri, rotateCube;
int?one?= 0x10000;
//定義六面體顏色
private?IntBuffer colorBufferForCube?= IntBuffer.wrap(new?int[]{
?0,one,0,one,
?0,one,0,one,
?0,one,0,one,
?0,one,0,one,
?
?one, one/2, 0, one,
?one, one/2, 0, one,
?one, one/2, 0, one,
?one, one/2, 0, one,
?
?one,0,0,one,
?one,0,0,one,
?one,0,0,one,
?one,0,0,one,
?
?one,one,0,one,
?one,one,0,one,
?one,one,0,one,
?one,one,0,one,
?
?0,0,one,one,
?0,0,one,one,
?0,0,one,one,
?0,0,one,one,
?
?one,0,one,one,
?one,0,one,one,
?one,0,one,one,
?one,0,one,one,
});
//四棱錐顏色
?private?IntBuffer colorBufferForPyramid?= IntBuffer.wrap(new?int[]{
?one,0,0,one,
?0,one,0,one,
?0,0,one,one,
?
?one,0,0,one,
?0,one,0,one,
?0,0,one,one,
?
?one,0,0,one,
?0,one,0,one,
?0,0,one,one,
?
?one,0,0,one,
?0,one,0,one,
?0,0,one,one,
?});
?
?
?private?IntBuffer PyramidBuffer?= IntBuffer.wrap(new?int[]{//四棱錐坐標
0,one,0,
-one,-one,0,
one,-one,one,
0,one,0,
one,-one,one,
one,-one,-one,
0,one,0,
one,-one,-one,
-one,-one,-one,
0,one,0,
-one,-one,-one,
-one,-one,one
?
?});
?private?IntBuffer cubeBuffer?= IntBuffer.wrap(new?int[]{//六面體坐標
one,one,-one,
-one,one,-one,
one,one,one,
-one,one,one,
one,-one,one,
-one,-one,one,
one,-one,-one,
-one,-one,-one,
one,one,one,
-one,one,one,
one,-one,one,
-one,-one,one,
one,-one,-one,
-one,-one,-one,
one,one,-one,
-one,one,-one,
-one,one,one,
-one,one,-one,
-one,-one,one,
-one,-one,-one,
one, one, -one,
one, one, one,
one, -one, -one,
one, -one, one,
?});
@Override
public?void?onDrawFrame(GL10 gl) {
// 清除屏幕和深度緩存
gl.glClear(GL10.GL_COLOR_BUFFER_BIT?| GL10.GL_DEPTH_BUFFER_BIT);
// 重置當前的模型觀察矩陣
gl.glLoadIdentity();
// 左移 1.5 單位,并移入屏幕 6.0
gl.glTranslatef(-1.5f, 0.0f, -6.0f);
// 設置旋轉
gl.glRotatef(rotateTri, 0.0f, 1.0f, 0.0f);
// 設置定點數組
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
// 設置顏色數組
gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
gl.glColorPointer(4, GL10.GL_FIXED, 0, colorBufferForPyramid);
// 設置三角形頂點
gl.glVertexPointer(3, GL10.GL_FIXED, 0, PyramidBuffer);
// 繪制三角錐
for?(int?i = 0; i < 4; i++) {
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, i * 3, 3);
}
/* 渲染正方體 */
// 重置當前的模型觀察矩陣
gl.glLoadIdentity();
// 左移 1.5 單位,并移入屏幕 6.0
gl.glTranslatef(1.5f, 0.0f, -6.0f);
// 設置旋轉
gl.glRotatef(rotateCube, 1.0f, 0.0f, 0.0f);
// 設置和繪制正方形
gl.glColorPointer(4, GL10.GL_FIXED, 0, colorBufferForCube);
gl.glVertexPointer(3, GL10.GL_FIXED, 0, cubeBuffer);
for?(int?i = 0; i < 6; i++) {
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, i * 4, 4);
}
// 繪制正方形結束
gl.glFinish();
// 取消頂點數組
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
gl.glDisableClientState(GL10.GL_COLOR_ARRAY);
// 改變旋轉的角度
rotateTri?+= 0.5f;
rotateCube?-= 0.5f;
}
?
@Override
public?void?onSurfaceChanged(GL10 gl, int?width, int?height) {
float?ratio = (float) width / height;
gl.glViewport(0, 0, width, height);// 設置OpenGL場景的大小
gl.glMatrixMode(GL10.GL_PROJECTION);// 設置投影矩陣
gl.glLoadIdentity();// 重置投影矩陣
gl.glFrustumf(-ratio, ratio, -1, 1, 1, 10);// 設置視口的大小
gl.glMatrixMode(GL10.GL_MODELVIEW);// 選擇模型觀察矩陣
gl.glLoadIdentity();// 重置模型觀察矩陣
}
?
@Override
public?void?onSurfaceCreated(GL10 gl, EGLConfig config) {
gl.glShadeModel(GL10.GL_SMOOTH);// 啟用陰影平滑
gl.glClearColor(0, 0.5f, 0.5f, 0.5f);// 黑色背景
gl.glClearDepthf(1.0f);// 設置深度緩存
gl.glEnable(GL10.GL_DEPTH_TEST);// 啟用深度測試
gl.glDepthFunc(GL10.GL_LEQUAL);// 所作深度測試的類型
gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST);// 告訴系統對透視進行修正
}
}
在本示例中我們用到的GL10的方法如下:
??void glHint(int target, int mode)
用來對視圖進行修正。
target用來來表明被控制的行為,當取值為GL_PERSPECTIVE_CORRECTION_HINT時用來指定顏色和紋理坐標的插值質量。
mode用來表明想要執行的行為,取值如下表3-1-5所示。
表3-1-5 mode取值及含義
mode取值 | 說明 |
GL_FASTEST | 使用速度最快的模式 |
GL_NICEST | 使用質量最好的模式. |
GL_DONT_CAR | 由驅動設備來決定 |
??void glDepthFunc(int func)
設置所做深度測試的類型。?
任務實訓部分?
1:繪制一個帶紋理的旋轉的立方體
訓練技能點
??基本3D圖形的繪制
??紋理的使用
??3D圖形的旋轉控制
需求說明
3D游戲相較于普通2D游戲的優點就在于可以讓玩家不斷變換視角,可以360度查看游戲角色,這里我們用一個立方體模擬一個3D游戲角色,使之不斷旋轉來模擬查看其各個方位不同的狀態。程序最終運行效果如下圖3.2.1所示。
?
圖3.2.1 旋轉的立方體
實現思路:
?
核心代碼如下
public?class?GLRotateCubeRender implements?Renderer
{
float?xrot, yrot, zrot;
int?texture?= -1;
int?one?= 0x10000;
IntBuffer vertices?= IntBuffer.wrap(new?int[]{
-one,-one,one,
one,-one,one,
one,one,one,
-one,one,one,
-one,-one,-one,
-one,one,-one,
one,one,-one,
one,-one,-one,
-one,one,-one,
-one,one,one,
one,one,one,
one,one,-one,
-one,-one,-one,
one,-one,-one,
one,-one,one,
-one,-one,one,
one,-one,-one,
one,one,-one,
one,one,one,
one,-one,one,
-one,-one,-one,
-one,-one,one,
-one,one,one,
-one,one,-one,
});
//對立方體的每一個面所設置的紋理映射數據
IntBuffer texCoords?= IntBuffer.wrap(new?int[]{
one,0,0,0,0,one,one,one,
0,0,0,one,one,one,one,0,
one,one,one,0,0,0,0,one,
0,one,one,one,one,0,0,0,
0,0,0,one,one,one,one,0,
one,0,0,0,0,one,one,one,
});
ByteBuffer indices?= ByteBuffer.wrap(new?byte[]{
0,1,3,2,
4,5,7,6,
8,9,11,10,
12,13,15,14,
16,17,19,18,
20,21,23,22,
});
@Override
public?void?onDrawFrame(GL10 gl)
{
// 清除屏幕和深度緩存
gl.glClear(GL10.GL_COLOR_BUFFER_BIT?| GL10.GL_DEPTH_BUFFER_BIT);
// 重置當前的模型觀察矩陣
gl.glLoadIdentity();
gl.glTranslatef(0.0f, 0.0f, -5.0f);
//設置3個方向的旋轉
gl.glRotatef(xrot, 1.0f, 0.0f, 0.0f);
gl.glRotatef(yrot, 0.0f, 1.0f, 0.0f);
gl.glRotatef(zrot, 0.0f, 0.0f, 1.0f);
?
// 綁定紋理
gl.glBindTexture(GL10.GL_TEXTURE_2D, texture);
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
//紋理和四邊形對應的頂點
gl.glVertexPointer(3, GL10.GL_FIXED, 0, vertices);
gl.glTexCoordPointer(2, GL10.GL_FIXED, 0, texCoords);
?
//繪制
gl.glDrawElements(GL10.GL_TRIANGLE_STRIP, 24, ?GL10.GL_UNSIGNED_BYTE, indices);
?
????gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
????gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
????
????xrot+=0.5f;
????yrot+=0.6f;
????zrot+=0.3f;
}
?
@Override
public?void?onSurfaceChanged(GL10 gl, int?width, int?height)
{
float?ratio = (float) width / height;
//設置OpenGL場景的大小
gl.glViewport(0, 0, width, height);
//設置投影矩陣
gl.glMatrixMode(GL10.GL_PROJECTION);
//重置投影矩陣
gl.glLoadIdentity();
// 設置視口的大小
gl.glFrustumf(-ratio, ratio, -1, 1, 1, 10);
// 選擇模型觀察矩陣
gl.glMatrixMode(GL10.GL_MODELVIEW);
// 重置模型觀察矩陣
gl.glLoadIdentity();
}
?
@Override
public?void?onSurfaceCreated(GL10 gl, EGLConfig config)
{
// 黑色背景
gl.glClearColor(0, 0, 0, 0);
gl.glEnable(GL10.GL_CULL_FACE);
// 啟用陰影平滑
gl.glShadeModel(GL10.GL_SMOOTH);
// 啟用深度測試
gl.glEnable(GL10.GL_DEPTH_TEST);
//啟用紋理映射
gl.glClearDepthf(1.0f);
//深度測試的類型
gl.glDepthFunc(GL10.GL_LEQUAL);
//精細的透視修正
gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST);
//允許2D貼圖,紋理
gl.glEnable(GL10.GL_TEXTURE_2D);
IntBuffer intBuffer = IntBuffer.allocate(1);
// 創建紋理
gl.glGenTextures(1, intBuffer);
texture?= intBuffer.get();
// 設置要使用的紋理
gl.glBindTexture(GL10.GL_TEXTURE_2D, texture);
//生成紋理
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, GLImage.mBitmap, 0);
// 線形濾波
gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR);
gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
}
?
}
?
class?GLImage
{
public?static?Bitmap mBitmap;
public?static?void?load(Resources resources)
{
mBitmap?= BitmapFactory.decodeResource(resources, R.drawable.img);
}
}
?
提示:
本例中用到兩個紋理處理的方法,語法及解釋如下:
??void glGenTextures(int n, IntBuffer?textures)
創建紋理,用于通知OpenGL我們所要生成的紋理的名字。其中參數n表示要載入的紋理的個數,textures表示紋理的名字。
??void glBindTexture(int target, int texture)
設置要使用的紋理,綁定紋理操作必須在繪圖之前完成。用于通知OpenGL將紋理名字texture綁定到紋理目標上。其中參數target描述了要綁定的紋理的類型,texture表示紋理的名字。
鞏固練習
一、簡答題
1.?簡述OpenGL與OpenGL ES的關系及區別。?
2.?簡述在Android中使用OpenGL ES的基本步驟。?
二、上機練習
利用基本圖形組合的形式,采用OpenGL ES的知識繪制一個簡單的機器人,然后為機器人添加走動的功能(此步選做)。?
總結
- 上一篇: Android中的动画
- 下一篇: 多媒体开发