Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> GL_TRIANGLE_STRIP之紋理貼圖

GL_TRIANGLE_STRIP之紋理貼圖

編輯:關於Android編程

一、基礎知識:

GL_TRIANGLE_STRIP比GL_TRIANLGES 快100% ~ 200%。
建議:盡可能地使用GL_TRIANGLE_STRIP替代GL_TRIANGLES。

二、使用方法:

1.首先以框架入手,我們一般在Android上畫一個3D的圖形,需要在MainActivity的OnCreate函數中加入如下代碼,用來進入我們的3D場景界面:

[java]
glView = new GLSurfaceView(this);       // 創建一個GLSurfaceView  
glView.setRenderer(new MyGLRenderer(this)); // 使用定制的渲染器  
 setContentView(glView);                         

       glView = new GLSurfaceView(this);  // 創建一個GLSurfaceView
       glView.setRenderer(new MyGLRenderer(this)); // 使用定制的渲染器
        setContentView(glView);      其中,glView為GLSurfaceView glView的引用對象,在MainActivity中的成員變量中聲明:

[java]
private GLSurfaceView glView;   // 使用GLSurfaceView  

private GLSurfaceView glView; // 使用GLSurfaceView 


2.接下來實現3D場景中的絢爛器(GLSurfaceView.Renderer):

[java]
public class MyGLRenderer implements  GLSurfaceView.Renderer { 
  // 實現代碼  

public class MyGLRenderer implements  GLSurfaceView.Renderer {
  // 實現代碼
}
①構造函數的編寫:

[java]
/ Constructor with global application context  
public MyGLRenderer(Context context) { 
    this.context = context; 
     
    // 設置所用圖形的數據數組緩沖區  
    cube = new TextureCube(); 

 // Constructor with global application context
 public MyGLRenderer(Context context) {
  this.context = context;
  
  // 設置所用圖形的數據數組緩沖區
  cube = new TextureCube();
 }
其中,TextureCube 為我們自己的紋理類,需要自己實現,後面會有實現。context和cube分別為成員變量:

[java]
private Context context;    // 應用的上下文句柄  
 
private TextureCube  cube; 

 private Context context; // 應用的上下文句柄
 
 private TextureCube  cube;

②重載函數onSurfaceCreated,創建絢爛器時需要初始化的部分皆在此:

[java]
// Call back when the surface is first created or re-created  
    @Override 
    public void onSurfaceCreated(GL10 gl, EGLConfig config) 
    { 
        // 啟用陰影平滑  
        gl.glShadeModel(GL10.GL_SMOOTH); 
         
        // 設置背景顏色  
        gl.glClearColor(0.2f, 0.4f, 0.52f, 1.0f); 
         
        // 設置深度緩存  
        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); 
         
        // 禁止抖動以取得更好的性能  
        gl.glDisable(GL10.GL_DITHER); 
         
        // 設置紋理  
        cube.loadTexture(gl, context);      // 加載紋理  
        gl.glEnable(GL10.GL_TEXTURE_2D);    // 紋理使能  
    } 

// Call back when the surface is first created or re-created
 @Override
 public void onSurfaceCreated(GL10 gl, EGLConfig config)
 {
  // 啟用陰影平滑
  gl.glShadeModel(GL10.GL_SMOOTH);
  
  // 設置背景顏色
  gl.glClearColor(0.2f, 0.4f, 0.52f, 1.0f);
  
  // 設置深度緩存
  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);
  
  // 禁止抖動以取得更好的性能
  gl.glDisable(GL10.GL_DITHER);
  
  // 設置紋理
  cube.loadTexture(gl, context);  // 加載紋理
  gl.glEnable(GL10.GL_TEXTURE_2D); // 紋理使能
 }
以上一些功能的打開和聲明,都可以在我博客之前的一些文章中找到,不在詳述。

最重要的一句就是  cube.loadTexture(gl, context); 加載紋理。

③重載函數onSurfaceChanged,當屏幕旋轉(橫屏變為豎屏)時,調用。當然,在初始化的時候也是要調用的:

[java]
// Call back after onSurfaceCreated() or whenever the window's size changes  
@Override 
public void onSurfaceChanged(GL10 gl, int width, int height) 

    if(height == 0) // 防止被零除  
    { 
        height = 1;  
    } 
     
    // 重置當前的視圖區域  
    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(); 

 // Call back after onSurfaceCreated() or whenever the window's size changes
 @Override
 public void onSurfaceChanged(GL10 gl, int width, int height)
 {
  if(height == 0) // 防止被零除
  {
   height = 1; 
  }
  
  // 重置當前的視圖區域
  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();
 }
④重載函數onDrawFrame,此為一個回調函數,用來更新場景中的各個對象:

[java]
// Call back to draw the current frame.  
    @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); // 向屏幕裡移動5個單位  
        gl.glScalef(0.8f, 0.8f, 0.8f);  // 縮小80%  
        // 繞X軸旋轉立方體   
        gl.glRotatef(xrot, 1.0f, 0.0f, 0.0f); 
        // 繞Y軸旋轉立方體  
        gl.glRotatef(yrot, 0.0f, 1.0f, 0.0f); 
        // 繞Z軸旋轉立方體  
        gl.glRotatef(zrot, 0.0f, 0.0f, 1.0f); 
         
         // 正方體  
        cube.draw(gl); 
         
        // 每次刷新之後更新旋轉角度  
        xrot += 0.3f; 
        yrot += 0.2f; 
        zrot += 0.4f; 
    } 

// Call back to draw the current frame.
 @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); // 向屏幕裡移動5個單位
  gl.glScalef(0.8f, 0.8f, 0.8f); // 縮小80%
  // 繞X軸旋轉立方體
  gl.glRotatef(xrot, 1.0f, 0.0f, 0.0f);
  // 繞Y軸旋轉立方體
  gl.glRotatef(yrot, 0.0f, 1.0f, 0.0f);
  // 繞Z軸旋轉立方體
  gl.glRotatef(zrot, 0.0f, 0.0f, 1.0f);
  
      // 正方體
  cube.draw(gl);
  
  // 每次刷新之後更新旋轉角度
  xrot += 0.3f;
  yrot += 0.2f;
  zrot += 0.4f;
 }

3.接下來實現3D場景中絢爛器的紋理類(TextureCube):

[java]
// 生成一個帶紋理的立方體  
// 這裡指定義一個面的頂點,立方體的其他面通過平移和旋轉這個面來渲染  
public class TextureCube { 
// 實現代碼  

// 生成一個帶紋理的立方體
// 這裡指定義一個面的頂點,立方體的其他面通過平移和旋轉這個面來渲染
public class TextureCube {
// 實現代碼
}

①構造函數的編寫:

[java]
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. 右-頂-前  
}; 
 
float[] texCoords = { // 定義上面的面的紋理坐標  
       0.0f, 1.0f,  // A. 左-下  
       1.0f, 1.0f,  // B. 右-下   
       0.0f, 0.0f,  // C. 左-上   
       1.0f, 0.0f   // D. 右-上  
   }; 
 
int[] textureIDs = new int[1]; // 紋理-ID數組  
 
// 構造函數,設置緩沖區  
public TextureCube() 

    // 設置頂點數組,頂點數據為浮點數據類型。一個浮點類型的數據長度為四個字節  
    ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4); 
    vbb.order(ByteOrder.nativeOrder()); // 使用原生字節順序  
    vertexBuffer = vbb.asFloatBuffer(); // 將字節類型緩沖區轉換成浮點類型  
    vertexBuffer.put(vertices);         // 將數據復制進緩沖區  
    vertexBuffer.position(0);           // 定位到初始位置  
  
    // 設置紋理坐標數組緩沖區,數據類型為浮點數據  
    ByteBuffer tbb = ByteBuffer.allocateDirect(texCoords.length * 4); 
    tbb.order(ByteOrder.nativeOrder()); 
    texBuffer = tbb.asFloatBuffer(); 
    texBuffer.put(texCoords); 
    texBuffer.position(0); 

 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. 右-頂-前
 };
 
 float[] texCoords = { // 定義上面的面的紋理坐標
        0.0f, 1.0f,  // A. 左-下
        1.0f, 1.0f,  // B. 右-下
        0.0f, 0.0f,  // C. 左-上
        1.0f, 0.0f   // D. 右-上
    };

 int[] textureIDs = new int[1]; // 紋理-ID數組
 
 // 構造函數,設置緩沖區
 public TextureCube()
 {
  // 設置頂點數組,頂點數據為浮點數據類型。一個浮點類型的數據長度為四個字節
     ByteBuffer vbb = ByteBuffer.allocateDirect(vertices.length * 4);
     vbb.order(ByteOrder.nativeOrder()); // 使用原生字節順序
     vertexBuffer = vbb.asFloatBuffer(); // 將字節類型緩沖區轉換成浮點類型
     vertexBuffer.put(vertices);         // 將數據復制進緩沖區
     vertexBuffer.position(0);           // 定位到初始位置
 
     // 設置紋理坐標數組緩沖區,數據類型為浮點數據
     ByteBuffer tbb = ByteBuffer.allocateDirect(texCoords.length * 4);
     tbb.order(ByteOrder.nativeOrder());
     texBuffer = tbb.asFloatBuffer();
     texBuffer.put(texCoords);
     texBuffer.position(0);
 }
②加載圖像函數的實現(loadTexture):

[java]
// 加載一個圖像到GL紋理  
    public void loadTexture(GL10 gl, Context context) { 
        gl.glGenTextures(1, textureIDs, 0); // 生成紋理ID數組  
         
        gl.glBindTexture(GL10.GL_TEXTURE_2D, textureIDs[0]);    // 綁定到紋理ID  
        // 設置紋理過濾方式  
        gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST); 
        gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR); 
         
        // 構造一個輸入流來加載紋理文件"res/drawable/nehe.bmp"  
        InputStream ins = context.getResources().openRawResource(R.drawable.nehe); 
        Bitmap bmp; 
        try { 
            // 讀取並將輸入流解碼成位圖  
            bmp = BitmapFactory.decodeStream(ins); 
        } finally { 
            try { 
                ins.close(); 
            }catch(IOException e) {} 
        } 
         
        // 根據加載的位圖為當前綁定的紋理ID建立紋理  
        GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bmp, 0); 
    } 

// 加載一個圖像到GL紋理
 public void loadTexture(GL10 gl, Context context) {
  gl.glGenTextures(1, textureIDs, 0); // 生成紋理ID數組
  
  gl.glBindTexture(GL10.GL_TEXTURE_2D, textureIDs[0]); // 綁定到紋理ID
  // 設置紋理過濾方式
  gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST);
  gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
  
  // 構造一個輸入流來加載紋理文件"res/drawable/nehe.bmp"
  InputStream ins = context.getResources().openRawResource(R.drawable.nehe);
  Bitmap bmp;
  try {
   // 讀取並將輸入流解碼成位圖
   bmp = BitmapFactory.decodeStream(ins);
  } finally {
   try {
    ins.close();
   }catch(IOException e) {}
  }
  
  // 根據加載的位圖為當前綁定的紋理ID建立紋理
  GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bmp, 0);
 }
③繪圖函數的實現(draw):

[java]
// 繪圖  
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); 
    gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer); 
    gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);  // 使能紋理坐標數組  
    gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, texBuffer); // 定義紋理坐標數組緩沖區  
     
    // 前  
    gl.glPushMatrix(); 
    gl.glTranslatef(0.0f, 0.0f, 1.0f); 
    gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4); 
    gl.glPopMatrix(); 
     
    // 左  
    gl.glPushMatrix(); 
    gl.glRotatef(270.0f, 0.0f, 1.0f, 0.0f); 
    gl.glTranslatef(0.0f, 0.0f, 1.0f); 
    gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4); 
    gl.glPopMatrix(); 
     
    // 後  
    gl.glPushMatrix(); 
    gl.glRotatef(180.0f, 0.0f, 1.0f, 0.0f); 
    gl.glTranslatef(0.0f, 0.0f, 1.0f); 
    gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4); 
    gl.glPopMatrix(); 
 
    // 右  
    gl.glPushMatrix(); 
    gl.glRotatef(90.0f, 0.0f, 1.0f, 0.0f); 
    gl.glTranslatef(0.0f, 0.0f, 1.0f); 
    gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4); 
    gl.glPopMatrix(); 
 
    // 頂  
    gl.glPushMatrix(); 
    gl.glRotatef(270.0f, 1.0f, 0.0f, 0.0f); 
    gl.glTranslatef(0.0f, 0.0f, 1.0f); 
    gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4); 
    gl.glPopMatrix(); 
 
    // 底  
    gl.glPushMatrix(); 
    gl.glRotatef(90.0f, 1.0f, 0.0f, 0.0f); 
    gl.glTranslatef(0.0f, 0.0f, 1.0f); 
    gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4); 
    gl.glPopMatrix(); 
     
    // 恢復原來的狀態  
    gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);  
    gl.glDisableClientState(GL10.GL_VERTEX_ARRAY); 
    gl.glDisable(GL10.GL_CULL_FACE); 

 // 繪圖
 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);
     gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
     gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);  // 使能紋理坐標數組
     gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, texBuffer); // 定義紋理坐標數組緩沖區
    
     // 前
     gl.glPushMatrix();
     gl.glTranslatef(0.0f, 0.0f, 1.0f);
     gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);
     gl.glPopMatrix();
    
     // 左
     gl.glPushMatrix();
     gl.glRotatef(270.0f, 0.0f, 1.0f, 0.0f);
     gl.glTranslatef(0.0f, 0.0f, 1.0f);
     gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);
     gl.glPopMatrix();
    
     // 後
     gl.glPushMatrix();
     gl.glRotatef(180.0f, 0.0f, 1.0f, 0.0f);
     gl.glTranslatef(0.0f, 0.0f, 1.0f);
     gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);
     gl.glPopMatrix();

     // 右
     gl.glPushMatrix();
     gl.glRotatef(90.0f, 0.0f, 1.0f, 0.0f);
     gl.glTranslatef(0.0f, 0.0f, 1.0f);
     gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);
     gl.glPopMatrix();

     // 頂
     gl.glPushMatrix();
     gl.glRotatef(270.0f, 1.0f, 0.0f, 0.0f);
     gl.glTranslatef(0.0f, 0.0f, 1.0f);
     gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);
     gl.glPopMatrix();

     // 底
     gl.glPushMatrix();
     gl.glRotatef(90.0f, 1.0f, 0.0f, 0.0f);
     gl.glTranslatef(0.0f, 0.0f, 1.0f);
     gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);
     gl.glPopMatrix();
    
     // 恢復原來的狀態
     gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
     gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
     gl.glDisable(GL10.GL_CULL_FACE);
 }

備注說明:

在紋理映射的時候,特別要注意頂點數組和圖像紋理數組的數值和順序,如果順序不對的話,很可能出現畫出來的是個三角形,或者圖像是很怪的那種。


 

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved