android 3D系列之紋理篇

來源:互聯網
上載者:User

                                               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

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.