3D圖形Texture(紋理貼圖)

“`
package com.example.tyxiong.myapplication;

import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLSurfaceView;
import android.opengl.GLUtils;
import android.os.Bundle;
import android.view.View;

import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
/*OpenGL與3D開發.

*2句概述:
* OpenGL是跨平臺,跨語言的開放圖形庫接口. 主要是用於3D圖形開發.
* Android系統內置了OpenGL ES支持. OpenGL ES是OpenGL的子集.–只支持繪製三角形
* 對於2D(平面)的三角形而言,由三個點構成,每個點的座標由(x,y)值構成.三個頂處理同一平面上.只需要提供每個頂點的座標值即可
* 對於3D(立體)的三棱錐而言,由4個頂點構成,每個頂點的座標由(x,y,x)值構成,各頂點不在同一平面,需要提供2方面數據:1 3D圖形每個頂點的座標值. 2 3D圖形每個平面由哪些頂點組成.
*
* 三維座標系:與數學裏座標系相同(屏幕中心點爲座標原點)
*
* Android5.0支持OpenGL ES3.1 android有opengl包, 3工具類:GLSurfaceView GLU GLUtils 功能強大.
*
* OpenGL ES繪製2D圖形:
* GLSurfaceView組件用於顯示3D圖形,其中GLSurfaceView.Renderer來完成繪製SurfaceView中的3D圖形. 使用分3步:
* 1 創建GLSurfaceView組件,並用Activity顯示.
* 2 創建GLSurfaceView.Renderer接口的子類實例–實現3個方法(方法中有GL10參數 表示畫筆)
* 2-1 onSurfaceCreate()–Surface被創建時回調,方法內常進行初始化GL10參數.
* 2-2 onSurfaceChanged()–Surface被改變回調,常進行3D場景的設置.
* 2-3 onDrawFrame()–代表繪製的當前幀,繪製3D圖形.
* 3 調用GLSurfaceView的setRenderer()方法來指定Renderer對象.
*
* 調用GL10繪製2D(平面)圖形的步驟 6步: 只需要提供所有頂點的座標值.glDrawArrays(mode,first,count)
* 1 glEnableClientState(GL10.GL_VERTEX_ARRAY)啓用頂點數組.
* 2 glEnableClientState(GL10.GL_COLOR_ARRAY)啓動頂點顏色數組
* 3 glVertexPointer(size,type,stride,pointer)設置頂點座標值. 每個頂點的值組成元素個數3 值類型int/fix float 步幅0 座標值數據(一維形如x1,y1,z1)
* 4 glColorPointer(size,type,stride,pointer) 設置頂點顏色值.(rgbn)4
* 5 glDrawArrays(mode,first,count)繪製2D圖形(平面) GL10.GL_TRIANGLES三角形/GL10.GL_TRIANGLE_STRIP多三角形. 開始頂點 頂點總數.
* 6 glFinish()結束繪製,glDisableClientState(int)停用頂點座標和顏色數據.
*
*
* 繪製3D圖形,(立方體)用到方法 glDrawElements(mode,count,type,indices) indices包裝了一個長度爲3N(N爲三角形數 3個頂點指定一個三角形)的數組
*
* 前面說了需要提供2方面數據:1 所有頂點的座標值(x,y,z). 2 需要指定3D圖形的每個平面由哪三個頂點組成.
* 1 所有頂點的座標值.
* 2 需要建 indices數組來指定每個三角形由哪三個頂點組成.
* glDrawElements(mode,count,type,indices)//繪製3D圖形,多個三角形 頂點總數(3*三角形數) 頂點indices裏的元素類型 buffer
*
* 其它相同的操作..
* 下面用的三棱錐例子,比較簡單,無須考慮頂點的排列方式(四面形,由多個三個角形組成頂點排列方式 當然可以用3Dmax軟件自動生成 頂點座標, 平面頂點組成)
*
*
* 爲3D圖形表面加上皮膚呢(紋理貼圖)
* 1 在onSurfaceCreated方法中,加上gl.glEnable(GL10.GL_TEXTURE_2D)//啓用2在紋理貼圖
* 2 選擇資源圖片生成紋理.loadTexture()方法實現過程.
* 3 onDrawFrame()方法中啓用貼圖座標數組數據 glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
* 設置貼圖座標數據 glTextCoordPointer()//這個彈性很大,可以用3dmax來實現紋理座標.
* 執行紋理貼圖 glBindTexture();
*
*
*
*
* */

public class MainActivity extends Activity {

GLSurfaceView surfaceView;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    surfaceView = new GLSurfaceView(this);
    final MyRenderer myRenderer = new MyRenderer(this);

    surfaceView.setRenderer(myRenderer);
    surfaceView.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);//繪製靜圖,無須刷新需要重繪時requestRenderer()節省cpu
    setContentView(surfaceView);
    surfaceView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            surfaceView.requestRender();//請求執行onDrawFrame()
        }
    });

}

}

class MyRenderer implements GLSurfaceView.Renderer {
private Context context;
private int texture;
private FloatBuffer pointerTexure;

public MyRenderer(Context context) {
    this.context = context;
}

float[] rectData = new float[]//三棱錐,4面(4個三角形 )4個頂點 上\左\右\裏
        {
                0f, 1f, 0f,
                -1f, -1f, 0f,
                1f, -1f, 0f,
                0f, 0f, -1f

        };
int[] rectColor = new int[]//rgbn頂點的顏色值(3*4頂點顏色值重複了不必要)
        {
                65535, 0, 0, 0,
                0, 65535, 0, 0,
                0, 0, 65535, 0,
                0, 65535, 65535, 0

        };
float[] rectTexture=new float[]//圖片左上角爲(0f,0f)
        {
                0f,0f,
                0f,1f,
                1f,1f,
                1f,0f,

        };


byte[] indices = new byte[]//4個三角形的3*4頂點
        {

                0, 1, 2,
                0, 1, 3,
                0, 2, 3,
                1, 2, 3
        };

private float angle = 0f;

public FloatBuffer floatUtils(float[] floatArr) {//繪製方法要求數據爲Buffer類型   float[]-->FloatBuffer[]
    ByteBuffer byteBuffer = ByteBuffer.allocateDirect(floatArr.length * 4);//要求用allocateDirect()方法,只有ByteBuffer有該方法,so
    byteBuffer.order(ByteOrder.nativeOrder());          //要求nativeOrder  Java 是大端字節序(BigEdian),
    // 而 OpenGL 所需要的數據是小端字節序(LittleEdian)
    FloatBuffer floatBuffer = byteBuffer.asFloatBuffer();
    floatBuffer.put(floatArr);
    floatBuffer.flip();
    return floatBuffer;
}

public IntBuffer intUtils(int[] intArr) {

    ByteBuffer byteBuffer = ByteBuffer.allocateDirect(intArr.length * 4);
    byteBuffer.order(ByteOrder.nativeOrder());
    IntBuffer intBuffer = byteBuffer.asIntBuffer();
    intBuffer.put(intArr);
    intBuffer.flip();
    return intBuffer;
}


@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {//對GL設置參數 關閉抗抖動 設置透視修正模式
    // 清屏黑色 平滑 開啓深度測試 深度測試類型. 啓用2D紋理貼圖
    gl.glEnable(GL10.GL_TEXTURE_2D);//1
    gl.glDisable(GL10.GL_DITHER);
    gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST);
    gl.glClearColor(0, 0, 0, 0);
    gl.glShadeModel(GL10.GL_SMOOTH);
    gl.glEnable(GL10.GL_DEPTH_TEST);
    gl.glDepthFunc(GL10.GL_LEQUAL);
    loadTexture(gl);//4
}

@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {//3D視窗場景 視窗大小位置 投影矩陣
    // 重置繪製座標原點 透視視窗寬高比 透視視窗空間大小
    gl.glViewport(0, 0, width, height);
    gl.glMatrixMode(GL10.GL_PROJECTION);//距離越遠,小  映射座標系設置爲"投影矩陣"
    gl.glLoadIdentity();
    float ratio = (float) width / height;
    gl.glFrustumf(-ratio, ratio, -1f, 1f, 1f, 10f);//三維座標系的值不是直接取屏幕像素,是根據該方法
    // 設置空間大小範圍內可見最後2個參數爲絕對值.
}

@Override
public void onDrawFrame(GL10 gl) {//繪製當圖形 清除屏幕緩存深度緩存 開啓頂點數據 頂點顏色 設置頂點數據
    // 顏色數據 繪製2D圖形 繪製完成 關閉頂點&&顏色數據
    gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
    gl.glMatrixMode(GL10.GL_MODELVIEW);//需要繪圖時設置爲"模型視圖"
    gl.glLoadIdentity();
    gl.glTranslatef(0f, 0f, -2f);//改變繪圖座標原點
    gl.glRotatef(angle++, 0f, 0.5f, 0f);//y軸旋轉
    gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
    gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
    gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
    FloatBuffer pointerData = floatUtils(rectData);
    IntBuffer pointColor = intUtils(rectColor);
    pointerTexure = floatUtils(rectTexture);

    gl.glVertexPointer(3, GL10.GL_FLOAT, 0, pointerData);
    gl.glColorPointer(4, GL10.GL_FIXED, 0, pointColor);
    gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, pointerTexure);//5
    gl.glBindTexture(GL10.GL_TEXTURE_2D, texture);

    gl.glDrawElements(GL10.GL_TRIANGLE_STRIP, 12, GL10.GL_UNSIGNED_BYTE, ByteBuffer.wrap(indices));//Byte[]類型可直接包裝成Buffer
    //  gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);
    gl.glFinish();
    gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
    gl.glDisableClientState(GL10.GL_COLOR_ARRAY);


}

public void loadTexture(GL10 gl) {//3 圖片資源生成紋理貼圖... 生成1個紋理存放textures數組中,0元素開始存放紋理代號
    //將紋理綁定到目標中,設置紋理放大/縮小 濾波方式 平鋪 加載位圖生成紋理.
    Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.icon6);
    int[] textures = new int[1];
    texture = textures[0];
    gl.glGenTextures(1, textures, 0);
    gl.glBindTexture(GL10.GL_TEXTURE_2D, texture);
    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);
    gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_REPEAT);
    gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_REPEAT);
    GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);

}

}

源圖

紋理貼圖效果

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章