By 何明桂(http://blog.csdn.net/hmg25)
轉載請註明出處
之前的例子都是純色的3D模型。今天我們就開始給這些模型貼上華麗麗的紋理,讓他們看起來更加接近我們印象中的真實物體。
功能啟動
為使用紋理,我們需要開啟OpenGL的一些開關以啟動我們需要的一些功能:
gl.glEnable(GL10.GL_TEXTURE_2D);
。這個調用是必不可缺的;如果你沒有開啟此功能,那麼你就無法將影像地圖到多邊形上。它可以在需要時開啟和關閉,通常在初始化時開啟。
建立紋理
產生紋理
OpenGL 中的紋理通過一個唯一號引用,通過函數 glBindTexture() 實現。你 可以自己指定這個唯一號,或者通過調用 glGenTextures () 函數產生一個唯一 號。
int[] tmp_tex = new int[1];//儘管只有一個紋理,但使用一個元素的數組
//glGenTextures(申請個數,存放數組,位移值)
gl.glGenTextures(1, tmp_tex, 0); //向系統申請可用的,用於標示紋理的ID
int texture = tmp_tex[0];
紋理綁定
在為紋理產生名稱後,在為紋理提供映像資料之前,我們必須綁定紋理。綁定使得指定紋理處於活動狀態。一次只能啟用一個紋理。活動的或“被綁定”的紋理是繪製多邊形時使用的紋理,也是新紋理資料將載入其上紋理,所以在提供映像資料前必須綁定紋理。
gl.glBindTexture(GL10.GL_TEXTURE_2D, texture);
綁定紋理資料,傳入指定圖片
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bmp, 0);
紋理限制
用於紋理的映像寬和高必須為乘方,比如 2, 4, 8, 16, 32, 64, 128, 256, 512, 或 1024。例像可能為 64×128 或 512×512。
紋理座標
當紋理映射啟動後繪圖時,你必須為OpenGL ES提供其他資料,即頂點數組中各頂點的 紋理座標。紋理座標定義了映像的哪一部分將被映射到多邊形。它的工作方式有點奇怪。與我們頂點座標方向不一致,假設你有一個正方形或長方形的紋理,其左下角為二維平面的原點,高和寬的單位為一。像這樣:
這就是我們的“紋理座標系統”,不使用x 和 y 來代表二維空間,我們使用 s 和 t 作為紋理座標軸,但原理上是一樣的。
除了 s 和 t 軸外,被映射的紋理在多邊形同樣有兩個軸,它們稱為 u 和 v軸。這是源於許多3D映像程式中的UV 映射 的術語。
好,我們明白了紋理座標系統,我們現在討論怎樣使用這些紋理座標。當我們指定頂點數組中的頂點時,我們需要在另一個數組中提供紋理座標,它稱為紋理座標數組。 每個頂點,我們使用float 來指定頂點在所示座標系統的位置。讓我們看看一個可能是最為簡單的例子,將整個影像地圖到一個由三角形條組成的正方形上。首先,我們建立一個由四個頂點組成的頂點數組:
現在將兩個框圖疊在一起,所使用的座標數組的值變得很明顯:
將其轉化為座標數組:
float texCoords[] = new float[]{ 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f };
紋理座標組應紋理在物體上的圖片位置和方向。我們還需要傳遞紋理座標給系統gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, texBuff); gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY); //開啟紋理座標數組我們今天執行個體的效果:代碼:
public class CubeRenderer implements Renderer {Bitmap bmp; float box[] = new float[] {// FRONT-0.5f, -0.5f, 0.5f, 0.5f, -0.5f, 0.5f,-0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f,// BACK-0.5f, -0.5f, -0.5f,-0.5f, 0.5f, -0.5f, 0.5f, -0.5f, -0.5f, 0.5f, 0.5f, -0.5f,// LEFT-0.5f, -0.5f, 0.5f,-0.5f, 0.5f, 0.5f,-0.5f, -0.5f, -0.5f,-0.5f, 0.5f, -0.5f,// RIGHT 0.5f, -0.5f, -0.5f, 0.5f, 0.5f, -0.5f, 0.5f, -0.5f, 0.5f, 0.5f, 0.5f, 0.5f,// TOP-0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, -0.5f, 0.5f, -0.5f, 0.5f, 0.5f, -0.5f,// BOTTOM-0.5f, -0.5f, 0.5f,-0.5f, -0.5f, -0.5f, 0.5f, -0.5f, 0.5f, 0.5f, -0.5f, -0.5f,};float lightAmbient[] = new float[] { 0.5f, 0.5f, 0.6f, 1.0f }; //環境光線float lightDiffuse[] = new float[] { 0.6f, 0.6f, 0.6f, 1.0f };//漫反射光float[] lightPos = new float[] {0,0,3,1}; //光源位置/* * 因為進行光照處理,你必須告知系統你定義的模型各個面的方向,以便系統計算光影情況,方向的描述是通過向量點來描述的 */float norms[] = new float[] { //法向量數組,用於描述個頂點的方向,以此說明各個面的方向// FRONT0f, 0f, 1f, //方向為(0,0,0)至(0,0,1)即Z軸正方向0f, 0f, 1f,0f, 0f, 1f,0f, 0f, 1f,// BACK0f, 0f, -1f,0f, 0f, -1f,0f, 0f, -1f,0f, 0f, -1f,// LEFT-1f, 0f, 0f,-1f, 0f, 0f,-1f, 0f, 0f,-1f, 0f, 0f,// RIGHT1f, 0f, 0f,1f, 0f, 0f,1f, 0f, 0f,1f, 0f, 0f,// TOP0f, 1f, 0f,0f, 1f, 0f,0f, 1f, 0f,0f, 1f, 0f,// BOTTOM0f, -1f, 0f,0f, -1f, 0f,0f, -1f, 0f,0f, -1f, 0f};float texCoords[] = new float[] { //紋理座標組應數組// FRONT 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,// BACK 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,// LEFT 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,// RIGHT 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,// TOP 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,// BOTTOM 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f};FloatBuffer cubeBuff;FloatBuffer normBuff;FloatBuffer texBuff;float xrot = 0.0f;float yrot = 0.0f;/** * 將float數群組轉換儲存在位元組緩衝數組 * @param arr * @return */public FloatBuffer makeFloatBuffer(float[] arr) {ByteBuffer bb = ByteBuffer.allocateDirect(arr.length * 4);//分配緩衝空間,一個float佔4個位元組bb.order(ByteOrder.nativeOrder()); //設定位元組順序, 其中ByteOrder.nativeOrder()是擷取本機位元組順序FloatBuffer fb = bb.asFloatBuffer(); //轉換為float型fb.put(arr); //添加資料fb.position(0); //設定數組的起始位置return fb;}public CubeRenderer(Context c) {// TODO Auto-generated constructor stubcubeBuff = makeFloatBuffer(box);//轉換float數組normBuff = makeFloatBuffer(norms);texBuff = makeFloatBuffer(texCoords);bmp = BitmapFactory.decodeResource(c.getResources(), R.drawable.face);}protected void init(GL10 gl) {gl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);//設定清屏時背景的顏色,R,G,B,Agl.glEnable(GL10.GL_LIGHTING); //啟用光照gl.glEnable(GL10.GL_LIGHT0); //開啟光源0//設定光照參數,也可以使用預設的,不設定gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_AMBIENT, lightAmbient,0);gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_DIFFUSE, lightDiffuse,0);gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_POSITION, lightPos, 0);gl.glNormalPointer(GL10.GL_FLOAT, 0, normBuff);gl.glEnableClientState(GL10.GL_NORMAL_ARRAY);//使用紋理步驟:// 1.開啟貼圖gl.glEnable(GL10.GL_TEXTURE_2D);// 2.產生紋理IDint[] tmp_tex = new int[1];//儘管只有一個紋理,但使用一個元素的數組//glGenTextures(申請個數,存放數組,位移值)gl.glGenTextures(1, tmp_tex, 0); //向系統申請可用的,用於標示紋理的IDint texture = tmp_tex[0];//3.綁定紋理,使得指定紋理處於活動狀態。一次只能啟用一個紋理gl.glBindTexture(GL10.GL_TEXTURE_2D, texture);//4.綁定紋理資料,傳入指定圖片 GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bmp, 0); //5.傳遞各個頂點對應的紋理座標 gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, texBuff);gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY); //開啟紋理座標數組 //6.設定紋理參數 (可選) /*下面的兩行參數告訴OpenGL在顯示映像時,當它比放大得原始的紋理大 *( GL_TEXTURE_MAG_FILTER )或縮小得比原始得紋理小( GL_TEXTURE_MIN_FILTER ) *時OpenGL採用的濾波方式。通常這兩種情況下我都採用 GL_LINEAR 。這使得紋理從很遠處 *到離螢幕很近時都平滑顯示。使用 GL_LINEAR 需要CPU和顯卡做更多的運算。如果您的機器很慢, *您也許應該採用 GL_NEAREST 。過濾的紋理在放大的時候,看起來馬賽克的很。您也可以結合這 *兩種濾波方式。在近處時使用 GL_LINEAR ,遠處時 GL_NEAREST 。 **/ gl.glTexParameterx(GL10.GL_TEXTURE_2D,GL10.GL_TEXTURE_MAG_FILTER,GL10.GL_LINEAR); gl.glTexParameterx(GL10.GL_TEXTURE_2D,GL10.GL_TEXTURE_MIN_FILTER,GL10.GL_LINEAR); gl.glEnable(GL10.GL_DEPTH_TEST); //啟用深度緩衝gl.glEnable(GL10.GL_CULL_FACE); //啟用背面剪裁gl.glClearDepthf(1.0f); // 設定深度緩衝值gl.glDepthFunc(GL10.GL_LEQUAL); // 設定深度緩衝比較函數,GL_LEQUAL表示新的像素的深度緩衝值小於等於當前像素的深度緩衝值(通過gl.glClearDepthf(1.0f)設定)時通過深度測試gl.glShadeModel(GL10.GL_SMOOTH);// 設定陰影模式GL_SMOOTH}@Overridepublic void onSurfaceCreated(GL10 gl, EGLConfig config) {// TODO Auto-generated method stubinit(gl);}@Overridepublic void onSurfaceChanged(GL10 gl, int w, int h) {// TODO Auto-generated method stubgl.glViewport(0, 0, w, h); //設定視窗gl.glMatrixMode(GL10.GL_PROJECTION); // 設定投影矩陣gl.glLoadIdentity(); //設定矩陣為單位矩陣,相當於重設矩陣GLU.gluPerspective(gl, 45.0f, ((float) w) / h, 0.1f, 10f);//設定透視範圍}@Overridepublic void onDrawFrame(GL10 gl) {// TODO Auto-generated method stubgl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);// 清除螢幕和深度緩衝gl.glMatrixMode(GL10.GL_MODELVIEW); //切換至模型觀察矩陣gl.glLoadIdentity();// 重設當前的模型觀察矩陣GLU.gluLookAt(gl, 0, 0, 3, 0, 0, 0, 0, 1, 0);//設定視點和模型中心位置gl.glVertexPointer(3, GL10.GL_FLOAT, 0, cubeBuff);//設定頂點資料gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);gl.glRotatef(xrot, 1, 0, 0); //繞著(0,0,0)與(1,0,0)即x軸旋轉gl.glRotatef(yrot, 0, 1, 0);gl.glColor4f(1.0f, 0, 0, 1.0f); //設定顏色,紅色gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4); //繪製正方型FRONT面gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 4, 4);gl.glColor4f(0, 1.0f, 0, 1.0f);gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 8, 4);gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 12, 4);gl.glColor4f(0, 0, 1.0f, 1.0f);gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 16, 4);gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 20, 4);xrot += 0.5f;yrot += 0.5f;}}
工程源碼地址:http://download.csdn.net/source/3567174