Android 繪制 2D哗讥、3D 圖形

image.png

繪制 2D 圖形

使用 OpenGL ES 需要三個步驟

  1. 創(chuàng)建 GLSurfaceView 組件嚷那,使用 Activity 來顯示 GLSurfaceView 組件。
  2. GLSurfaceView 組件創(chuàng)建 GLSurfaceView.Renderer 實(shí)例杆煞,實(shí)現(xiàn) GLSurfaceView.Renderer 類時需要實(shí)現(xiàn)該接口里的三個方法魏宽。
  • void onDrawFrame(GL10 gl) Renderer 對象調(diào)用該方法繪制 GLSurfaceView 的當(dāng)前幀
  • void onSurfaceChanged(GL10 gl, int width, int height) 當(dāng) GLSurfaceView 的大小改變時回調(diào)該方法
  • void onSurfaceCreated(GL10 gl, EGLConfig config) 當(dāng) GLSurfaceView 被創(chuàng)建時回調(diào)該方法
  1. 調(diào)用 GLSurfaceView 組件的 setRenderer() 方法指定 Renderer 對象,該 Renderer 對象將會完成 GLSurfaceView 里 3D 圖形的繪制

實(shí)現(xiàn) Renderer 類時需要實(shí)現(xiàn)三個方法决乎,這三個方法都有一個 GL10 形參队询,它就代表了 OpenGL ES 的“繪制畫筆”

當(dāng) SurfaceView 被創(chuàng)建時,系統(tǒng)會回調(diào) Renderer 對象的 onSurfaceCreated() 方法构诚,該方法可以對 OpenGL ES 執(zhí)行一些無須任何改變的初始化蚌斩。

    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {

        // 關(guān)閉抗抖動,可以提高性能
        gl.glDisable(GL10.GL_DITHER);
        // 設(shè)置系統(tǒng)對透視進(jìn)行修正
        gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST);
        // 用黑色“清屏”
        gl.glClearColor(0, 0, 0, 0);
        // 設(shè)置陰影平滑模式
        gl.glShadeModel(GL10.GL_SMOOTH);
        // 啟用深度測試范嘱。所謂深度測試送膳,就是讓 OpenGL ES 負(fù)責(zé)跟蹤每個物體在 Z 軸上的深度,這樣就可避免后面的物體遮擋前面的物體丑蛤。
        gl.glEnable(GL10.GL_DEPTH_TEST);
        // 設(shè)置深度測試的類型
        gl.glDepthFunc(GL10.GL_LEQUAL);
    }
  • glDisable() 用于禁用 OpenGL ES 某個方面的特性
  • glHint() 用于對 OpenGiL ES 某方面進(jìn)行修正
  • glClearColor() 用于設(shè)置 OpenGL ES “清屏”所用的顏色叠聋,4個參數(shù)分別設(shè)置紅、綠受裹、藍(lán)碌补、透明度值——0 為最小值,1 為最大值
  • glShadeModel() 用于設(shè)置 OpenGL ES 的陰影模式
  • glEnable() 該方法與 glDisable() 方法相對棉饶,用于啟用 OpenGL ES 某方面的特性

當(dāng) SurfaceView 組件的大小發(fā)生改變時厦章,系統(tǒng)會回調(diào) Renderer 對象的 onSurfaceChanged() 方法,因此該方法通常用于初始化 3D場景照藻。

    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {

        // 設(shè)置 3D 視窗的大小及位置
        gl.glViewport(0, 0, width, height);
        // 將當(dāng)前矩陣模式設(shè)為投影矩陣
        gl.glMatrixMode(GL10.GL_PROJECTION);
        // 初始化單位矩陣
        gl.glLoadIdentity();
        // 計(jì)算透視視窗的寬度袜啃、高度比
        float ratio = (float) width / height;
        // 調(diào)用此方法設(shè)置透視視窗的空間大小
        gl.glFrustumf(-ratio, ratio, -1, 1, 1, 10);
    }
  • glViewport() 用于設(shè)置 3D 視窗的位置與大小。其中前兩介參數(shù)指定該視窗的位置幸缕;后兩個參數(shù)指定該視窗的寬囊骤、高
  • glMatrixMode() 用于設(shè)置視圖的短陣模型晃择。通常可接受 GL10.GL_PROJECTION(指定將屏幕設(shè)為透視圖(要想看到逼真的三維物體也物,這是必要的)宫屠,這意味著越遠(yuǎn)的東西看起來越小)滑蚯、GL10.GL_MODELVIEW (將當(dāng)前矩陣模式設(shè)為模型視圖矩陣浪蹂,這意味著任何新的變換都會影響該短陣中的所有物體)兩個常量值
  • glLoadIdentity() 相當(dāng)于 reset() 方法,用于初始化單位矩陣
  • glFrustumf() 用于設(shè)置透視投影的空間大小告材。前兩個參數(shù)用干設(shè)置 X 軸上的最小坐標(biāo)值坤次、最大坐標(biāo)值。中間兩個參數(shù)用于設(shè)置 Y 軸上的最小坐標(biāo)值斥赋、最大坐標(biāo)值缰猴。后兩個參數(shù)用于設(shè)置 Z 軸上所能繪制的場景深度的最小值、最大值疤剑。

gl.glFrustumf(-0.8f, 0.8f, -1f, 1f, 1f, 10f);
這意味著如果有一個二維矩形滑绒,它的4個頂點(diǎn)的坐標(biāo)分別為 (-0.8, 1)、(0.8, 1)隘膘、(0.8. -1)疑故、(-0.8, -1),這個矩形將會占滿整個視窗

    @Override
    public void onDrawFrame(GL10 gl) {
        // 清除屏幕緩存和深度緩存
        gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
    }

繪制平面上的多邊形

Renderer

public class MyRenderer implements GLSurfaceView.Renderer {
    float[] triangleData = new float[]{
            0.1f, 0.6f, 0.0f, // 上頂點(diǎn)
            -0.3f, 0.0f, 0.0f, // 左頂點(diǎn)
            0.3f, 0.1f, 0.0f  // 右頂點(diǎn)
    };
    int[] triangleColor = new int[]{
            65535, 0, 0, 0, // 上頂點(diǎn)紅色
            0, 65535, 0, 0, // 左頂點(diǎn)綠色
            0, 0, 65535, 0 // 右頂點(diǎn)藍(lán)色
    };
    float[] rectData = new float[]{
            0.4f, 0.4f, 0.0f, // 右上頂點(diǎn)
            0.4f, -0.4f, 0.0f, // 右下頂點(diǎn)
            -0.4f, 0.4f, 0.0f, // 左上頂點(diǎn)
            -0.4f, -0.4f, 0.0f // 左下頂點(diǎn)
    };
    int[] rectColor = new int[]{
            0, 65535, 0, 0, // 右上頂點(diǎn)綠色
            0, 0, 65535, 0, // 右下頂點(diǎn)藍(lán)色
            65535, 0, 0, 0, // 左上頂點(diǎn)紅色
            65535, 65535, 0, 0 // 左下頂點(diǎn)黃色
    };
    // 依然是正方形的4個頂點(diǎn)弯菊,只是順序交換一下
    float[] rectData2 = new float[]{
            -0.4f, 0.4f, 0.0f, // 左上頂點(diǎn)
            0.4f, 0.4f, 0.0f, // 右上頂點(diǎn)
            0.4f, -0.4f, 0.0f, // 右下頂點(diǎn)
            -0.4f, -0.4f, 0.0f // 左下頂點(diǎn)
    };
    float[] pentacle = new float[]{
            0.4f, 0.4f, 0.0f,
            -0.2f, 0.3f, 0.0f,
            0.5f, 0.0f, 0f,
            -0.4f, 0.0f, 0f,
            -0.1f, -0.3f, 0f
    };
    FloatBuffer triangleDataBuffer;
    IntBuffer triangleColorBuffer;
    FloatBuffer rectDataBuffer;
    IntBuffer rectColorBuffer;
    FloatBuffer rectDataBuffer2;
    FloatBuffer pentacleBuffer;

    public MyRenderer() {
        // 將頂點(diǎn)位置數(shù)據(jù)數(shù)組轉(zhuǎn)換成FloatBuffer
        triangleDataBuffer = floatBufferUtil(triangleData);
        rectDataBuffer = floatBufferUtil(rectData);
        rectDataBuffer2 = floatBufferUtil(rectData2);
        pentacleBuffer = floatBufferUtil(pentacle);
        // 將頂點(diǎn)顏色數(shù)據(jù)數(shù)組轉(zhuǎn)換成IntBuffer
        triangleColorBuffer = intBufferUtil(triangleColor);
        rectColorBuffer = intBufferUtil(rectColor);
    }

    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        // 關(guān)閉抗抖動
        gl.glDisable(GL10.GL_DITHER);
        // 設(shè)置系統(tǒng)對透視進(jìn)行修正
        gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT
                , GL10.GL_FASTEST);
        gl.glClearColor(0, 0, 0, 0);
        // 設(shè)置陰影平滑模式
        gl.glShadeModel(GL10.GL_SMOOTH);
        // 啟用深度測試
        gl.glEnable(GL10.GL_DEPTH_TEST);
        // 設(shè)置深度測試的類型
        gl.glDepthFunc(GL10.GL_LEQUAL);
    }

    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
        // 設(shè)置3D視窗的大小及位置
        gl.glViewport(0, 0, width, height);
        // 將當(dāng)前矩陣模式設(shè)為投影矩陣
        gl.glMatrixMode(GL10.GL_PROJECTION);
        // 初始化單位矩陣
        gl.glLoadIdentity();
        // 計(jì)算透視視窗的寬度纵势、高度比
        float ratio = (float) width / height;
        // 調(diào)用此方法設(shè)置透視視窗的空間大小
        gl.glFrustumf(-ratio, ratio, -1, 1, 1, 10);
    }

    // 繪制圖形的方法
    @Override
    public void onDrawFrame(GL10 gl) {
        // 清除屏幕緩存和深度緩存
        gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
        // 啟用頂點(diǎn)坐標(biāo)數(shù)據(jù)
        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
        // 啟用頂點(diǎn)顏色數(shù)據(jù)
        gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
        // 設(shè)置當(dāng)前矩陣堆棧為模型堆棧
        gl.glMatrixMode(GL10.GL_MODELVIEW);
        // --------------------繪制第一個圖形---------------------
        // 重置當(dāng)前的模型視圖矩陣
        gl.glLoadIdentity();
        gl.glTranslatef(-0.32f, 0.35f, -1.2f);  // ①
        // 設(shè)置頂點(diǎn)的位置數(shù)據(jù)
        gl.glVertexPointer(3, GL10.GL_FLOAT, 0, triangleDataBuffer);
        // 設(shè)置頂點(diǎn)的顏色數(shù)據(jù)
        gl.glColorPointer(4, GL10.GL_FIXED, 0, triangleColorBuffer);
        // 根據(jù)頂點(diǎn)數(shù)據(jù)繪制平面圖形。GL_TRIANGLES:繪制三角形
        gl.glDrawArrays(GL10.GL_TRIANGLES, 0, 3);
        // --------------------繪制第二個圖形---------------------
        // 重置當(dāng)前的模型視圖矩陣
        gl.glLoadIdentity();
        gl.glTranslatef(0.6f, 0.8f, -1.5f);

        /*
         * 設(shè)置頂點(diǎn)的位置數(shù)據(jù)
         * 這個方法中 pointer 參數(shù)用于指定頂點(diǎn)坐標(biāo)值管钳,但這里并未使用三維數(shù)組來指定每個頂點(diǎn) X钦铁、Y、Z 坐標(biāo)的值才漆,pointer 依然是一個一維數(shù)組育瓜,其格式為 (x1, y1, z1, x2, y2, z2, x3, y3, z3, ... xN, yN,zN);也就是該數(shù)組里將會包含 3N 個數(shù)值栽烂,每 3 個值指定一個頂點(diǎn)的 X、Y恋脚、Z 坐標(biāo)值腺办。第一個參數(shù) size 指定多少個元素指定一個頂點(diǎn)位置,該 size 參數(shù)通吃忝瑁總是 3;type 參數(shù)指定頂點(diǎn)坐標(biāo)值的類型船响,如果頂點(diǎn)坐標(biāo)值為 float 類型躬拢,則指定為GL10.GL_FLOAT躲履;如果頂點(diǎn)坐標(biāo)值為整數(shù),則指定為 GL10.GL_FIXED
         * */
        gl.glVertexPointer(3, GL10.GL_FLOAT, 0, rectDataBuffer);
        /*
         * 設(shè)置頂點(diǎn)的顏色數(shù)據(jù)
         * 這個方法中 pointer 參數(shù)用于指定頂點(diǎn)的顏色值聊闯,pointer 依然是一個一維數(shù)組工猜,其格式為 (r1, g1, b1, a1, r2, g2, b2, a2, r3, g3, b3, a3, ... rN, gN, bN, aN);也就是該數(shù)組里將會包含 4N 個數(shù)值菱蔬,每 4 個值指定一個頂點(diǎn)顏色的紅篷帅、綠、藍(lán)拴泌、透明度的值魏身。第一個參數(shù) size 指定多少個元素指定一個頂點(diǎn)位置,該 size 參數(shù)通瞅礁總是 4箭昵;type 參數(shù)指定頂點(diǎn)坐標(biāo)值的類型,如果頂點(diǎn)坐標(biāo)值為 foat 類型回季,則指定為 GL10.GL_FLOAT家制;如果頂點(diǎn)坐標(biāo)值為整數(shù),則指定為 GLI0.GL_FIXED
         * */
        gl.glColorPointer(4, GL10.GL_FIXED, 0, rectColorBuffer);
        /*
         * 根據(jù)頂點(diǎn)數(shù)據(jù)繪制平面圖形
         * 該方法的第一個參數(shù)指定繪制圖形類型茧跋,第二個參數(shù)指定從哪個頂點(diǎn)開始繪制慰丛,第三個參數(shù)指定總共繪制的頂點(diǎn)數(shù)量。
         * GL_TRIANGLE_STRIP:用多個三角形來繪制多邊形
         * */
        gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);
        // --------------------繪制第三個圖形---------------------
        // 重置當(dāng)前的模型視圖矩陣
        gl.glLoadIdentity();
        gl.glTranslatef(-0.4f, -0.5f, -1.5f);
        // 設(shè)置頂點(diǎn)的位置數(shù)據(jù)(依然使用之前的頂點(diǎn)顏色)
        gl.glVertexPointer(3, GL10.GL_FLOAT, 0, rectDataBuffer2);
        // 根據(jù)頂點(diǎn)數(shù)據(jù)繪制平面圖形
        gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);
        // --------------------繪制第四個圖形---------------------
        // 重置當(dāng)前的模型視圖矩陣
        gl.glLoadIdentity();
        gl.glTranslatef(0.4f, -0.5f, -1.5f);
        // 設(shè)置使用純色填充
        gl.glColor4f(1.0f, 0.2f, 0.2f, 0.0f);  // ②
        gl.glDisableClientState(GL10.GL_COLOR_ARRAY);
        // 設(shè)置頂點(diǎn)的位置數(shù)據(jù)
        gl.glVertexPointer(3, GL10.GL_FLOAT, 0, pentacleBuffer);
        // 根據(jù)頂點(diǎn)數(shù)據(jù)繪制平面圖形
        gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 5);
        // 繪制結(jié)束
        gl.glFinish();
        // 停用頂點(diǎn)坐標(biāo)數(shù)據(jù)瘾杭、頂點(diǎn)顏色數(shù)據(jù)
        gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
    }

    // 定義一個工具方法诅病,將int[]數(shù)組轉(zhuǎn)換為OpenGL ES所需的IntBuffer
    private IntBuffer intBufferUtil(int[] arr) {
        IntBuffer mBuffer;
        // 初始化ByteBuffer,長度為arr數(shù)組的長度*4粥烁,因?yàn)橐粋€int占4字節(jié)
        ByteBuffer qbb = ByteBuffer.allocateDirect(arr.length * 4);
        // 數(shù)組排列用nativeOrder
        qbb.order(ByteOrder.nativeOrder());
        mBuffer = qbb.asIntBuffer();
        mBuffer.put(arr);
        mBuffer.position(0);
        return mBuffer;
    }

    // 定義一個工具方法贤笆,將float[]數(shù)組轉(zhuǎn)換為OpenGL ES所需的FloatBuffer
    private FloatBuffer floatBufferUtil(float[] arr) {
        FloatBuffer mBuffer;
        // 初始化ByteBuffer,長度為arr數(shù)組的長度*4讨阻,因?yàn)橐粋€int占4字節(jié)
        ByteBuffer qbb = ByteBuffer.allocateDirect(arr.length * 4);
        // 數(shù)組排列用nativeOrder
        qbb.order(ByteOrder.nativeOrder());
        mBuffer = qbb.asFloatBuffer();
        mBuffer.put(arr);
        mBuffer.position(0);
        return mBuffer;
    }
}

MainActivity

public class MainActivity extends AppCompatActivity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // 創(chuàng)建一個GLSurfaceView芥永,用于顯示OpenGL繪制的圖形
        GLSurfaceView glView = new GLSurfaceView(this);
        // 創(chuàng)建GLSurfaceView的內(nèi)容繪制器
        MyRenderer myRender = new MyRenderer();
        // 為GLSurfaceView設(shè)置繪制器
        glView.setRenderer(myRender);
        setContentView(glView);
    }
}
image.png

旋轉(zhuǎn)

glRotatef() 控制旋轉(zhuǎn)

public class MyRenderer implements GLSurfaceView.Renderer {
    // 省略定義頂點(diǎn)坐標(biāo)的代碼
    float[] triangleData = new float[]{
            0.1f, 0.6f, 0.0f, // 上頂點(diǎn)
            -0.3f, 0.0f, 0.0f, // 左頂點(diǎn)
            0.3f, 0.1f, 0.0f  // 右頂點(diǎn)
    };
    int[] triangleColor = new int[]{
            65535, 0, 0, 0, // 上頂點(diǎn)紅色
            0, 65535, 0, 0, // 左頂點(diǎn)綠色
            0, 0, 65535, 0 // 右頂點(diǎn)藍(lán)色
    };
    float[] rectData = new float[]{
            0.4f, 0.4f, 0.0f, // 右上頂點(diǎn)
            0.4f, -0.4f, 0.0f, // 右下頂點(diǎn)
            -0.4f, 0.4f, 0.0f, // 左上頂點(diǎn)
            -0.4f, -0.4f, 0.0f // 左下頂點(diǎn)
    };
    int[] rectColor = new int[]{
            0, 65535, 0, 0, // 右上頂點(diǎn)綠色
            0, 0, 65535, 0, // 右下頂點(diǎn)藍(lán)色
            65535, 0, 0, 0, // 左上頂點(diǎn)紅色
            65535, 65535, 0, 0 // 左下頂點(diǎn)黃色
    };
    // 依然是正方形的4個頂點(diǎn),只是順序交換了一下
    float[] rectData2 = new float[]{
            -0.4f, 0.4f, 0.0f, // 左上頂點(diǎn)
            0.4f, 0.4f, 0.0f, // 右上頂點(diǎn)
            0.4f, -0.4f, 0.0f, // 右下頂點(diǎn)
            -0.4f, -0.4f, 0.0f // 左下頂點(diǎn)
    };
    float[] pentacle = new float[]{
            0.4f, 0.4f, 0.0f,
            -0.2f, 0.3f, 0.0f,
            0.5f, 0.0f, 0f,
            -0.4f, 0.0f, 0f,
            -0.1f, -0.3f, 0f
    };

    FloatBuffer triangleDataBuffer;
    IntBuffer triangleColorBuffer;
    FloatBuffer rectDataBuffer;
    IntBuffer rectColorBuffer;
    FloatBuffer rectDataBuffer2;
    FloatBuffer pentacleBuffer;
    // 控制旋轉(zhuǎn)的角度
    private float rotate;

    public MyRenderer() {
        // 將頂點(diǎn)位置數(shù)據(jù)數(shù)組包裝成FloatBuffer
        triangleDataBuffer = floatBufferUtil(triangleData);
        rectDataBuffer = floatBufferUtil(rectData);
        rectDataBuffer2 = floatBufferUtil(rectData2);
        pentacleBuffer = floatBufferUtil(pentacle);
        // 將頂點(diǎn)顏色數(shù)據(jù)數(shù)組包裝成IntBuffer
        triangleColorBuffer = intBufferUtil(triangleColor);
        rectColorBuffer = intBufferUtil(rectColor);
    }

    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        // 關(guān)閉抗抖動
        gl.glDisable(GL10.GL_DITHER);
        // 設(shè)置系統(tǒng)對透視進(jìn)行修正
        gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT
                , GL10.GL_FASTEST);
        gl.glClearColor(0, 0, 0, 0);
        // 設(shè)置陰影平滑模式
        gl.glShadeModel(GL10.GL_SMOOTH);
        // 啟用深度測試
        gl.glEnable(GL10.GL_DEPTH_TEST);
        // 設(shè)置深度測試的類型
        gl.glDepthFunc(GL10.GL_LEQUAL);
    }

    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
        // 設(shè)置3D視窗的大小及位置
        gl.glViewport(0, 0, width, height);
        // 將當(dāng)前矩陣模式設(shè)為投影矩陣
        gl.glMatrixMode(GL10.GL_PROJECTION);
        // 初始化單位矩陣
        gl.glLoadIdentity();
        // 計(jì)算透視視窗的寬度钝吮、高度比
        float ratio = (float) width / height;
        // 調(diào)用此方法設(shè)置透視視窗的空間大小
        gl.glFrustumf(-ratio, ratio, -1, 1, 1, 10);
    }

    // 繪制圖形的方法
    @Override
    public void onDrawFrame(GL10 gl) {
        // 清除屏幕緩存和深度緩存
        gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
        // 啟用頂點(diǎn)坐標(biāo)數(shù)據(jù)
        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
        // 啟用頂點(diǎn)顏色數(shù)據(jù)
        gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
        // 設(shè)置當(dāng)前矩陣堆棧為模型堆棧
        gl.glMatrixMode(GL10.GL_MODELVIEW);
        // --------------------繪制第一個圖形---------------------
        // 重置當(dāng)前的模型視圖矩陣
        gl.glLoadIdentity();
        gl.glTranslatef(-0.32f, 0.35f, -1.2f);
        // 設(shè)置頂點(diǎn)的位置數(shù)據(jù)
        gl.glVertexPointer(3, GL10.GL_FLOAT, 0, triangleDataBuffer);
        // 設(shè)置頂點(diǎn)的顏色數(shù)據(jù)
        gl.glColorPointer(4, GL10.GL_FIXED, 0, triangleColorBuffer);

        // 根據(jù)頂點(diǎn)數(shù)據(jù)繪制平面圖形
        gl.glDrawArrays(GL10.GL_TRIANGLES, 0, 3);
        // --------------------繪制第二個圖形---------------------
        // 重置當(dāng)前的模型視圖矩陣
        gl.glLoadIdentity();
        gl.glTranslatef(0.6f, 0.8f, -1.5f);
        gl.glRotatef(rotate, 0f, 0f, 0.1f);
        // 設(shè)置頂點(diǎn)的位置數(shù)據(jù)
        gl.glVertexPointer(3, GL10.GL_FLOAT, 0, rectDataBuffer);
        // 設(shè)置頂點(diǎn)的顏色數(shù)據(jù)
        gl.glColorPointer(4, GL10.GL_FIXED, 0, rectColorBuffer);
        // 根據(jù)頂點(diǎn)數(shù)據(jù)繪制平面圖形
        gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);
        // --------------------繪制第三個圖形---------------------
        // 重置當(dāng)前的模型視圖矩陣
        gl.glLoadIdentity();
        gl.glTranslatef(-0.4f, -0.5f, -1.5f);
        gl.glRotatef(rotate, 0f, 0.2f, 0f);
        // 設(shè)置頂點(diǎn)的位置數(shù)據(jù)(依然使用之前的頂點(diǎn)顏色)
        gl.glVertexPointer(3, GL10.GL_FLOAT, 0, rectDataBuffer2);
        // 根據(jù)頂點(diǎn)數(shù)據(jù)繪制平面圖形
        gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);
        // --------------------繪制第四個圖形---------------------
        // 重置當(dāng)前的模型視圖矩陣
        gl.glLoadIdentity();
        gl.glTranslatef(0.4f, -0.5f, -1.5f);
        // 設(shè)置使用純色填充
        gl.glColor4f(1.0f, 0.2f, 0.2f, 0.0f);
        gl.glDisableClientState(GL10.GL_COLOR_ARRAY);
        // 設(shè)置頂點(diǎn)的位置數(shù)據(jù)
        gl.glVertexPointer(3, GL10.GL_FLOAT, 0, pentacleBuffer);
        // 根據(jù)頂點(diǎn)數(shù)據(jù)繪制平面圖形
        gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 5);
        // 繪制結(jié)束
        gl.glFinish();
        gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
        // 旋轉(zhuǎn)角度增加1
        rotate += 1;
    }
    // 省略intBufferUtil和floatBufferUtil兩個工具方法的代碼

    // 定義一個工具方法埋涧,將int[]數(shù)組轉(zhuǎn)換為OpenGL ES所需的IntBuffer
    private IntBuffer intBufferUtil(int[] arr) {
        IntBuffer mBuffer;
        // 初始化ByteBuffer,長度為arr數(shù)組的長度*4奇瘦,因?yàn)橐粋€int占4個字節(jié)
        ByteBuffer qbb = ByteBuffer.allocateDirect(arr.length * 4);
        // 數(shù)組排列用nativeOrder
        qbb.order(ByteOrder.nativeOrder());
        mBuffer = qbb.asIntBuffer();
        mBuffer.put(arr);
        mBuffer.position(0);
        return mBuffer;
    }

    // 定義一個工具方法棘催,將float[]數(shù)組轉(zhuǎn)換為OpenGL ES所需的FloatBuffer
    private FloatBuffer floatBufferUtil(float[] arr) {
        FloatBuffer mBuffer;
        // 初始化ByteBuffer,長度為arr數(shù)組的長度*4耳标,因?yàn)橐粋€int占4個字節(jié)
        ByteBuffer qbb = ByteBuffer.allocateDirect(arr.length * 4);
        // 數(shù)組排列用nativeOrder
        qbb.order(ByteOrder.nativeOrder());
        mBuffer = qbb.asFloatBuffer();
        mBuffer.put(arr);
        mBuffer.position(0);
        return mBuffer;
    }
}

繪制 3D 圖形

使用 OpenGL ES 繪制 3D 圖形的步驟與繪制 2D 圖形的步驟大致相同醇坝,只是繪制 3D 圖形需要定義更多的頂點(diǎn)數(shù)據(jù),而且 3D 圖形需要繪制更多的三角形次坡。

void glDrawElements(int mode, int count, int type, java.nio.Buffer indices)

根據(jù) indices 指定的索引點(diǎn)來繪制三角形呼猪。該方法的第一個參數(shù)指定繪制的圖形類型画畅,可設(shè)為 GL10.GL_TRIANGLESGL10.GL_TRIANGLE_STRIP;第二個參數(shù)指定一共包含多少個頂點(diǎn)宋距。indices 參數(shù)最重要轴踱,它包裝了一個長度為 3N 的數(shù)組,比如讓該參數(shù)包裝 {0, 2, 3, 1, 4, 5} 數(shù)組乡革,這意味著告訴 OpenGL ES 要繪制兩個三角形寇僧,第一個三角形的三個頂點(diǎn)為 0、2沸版、3 頂點(diǎn)嘁傀,第二個三角形的三個頂點(diǎn)為 1、4视粮、5 頂點(diǎn)细办。

public class MyRenderer implements GLSurfaceView.Renderer {
    // 定義三棱椎的4個頂點(diǎn)
    float[] taperVertices = new float[]{
            0.0f, 0.5f, 0.0f,
            -0.5f, -0.5f, -0.2f,
            0.5f, -0.5f, -0.2f,
            0.0f, -0.2f, 0.2f
    };
    // 定義三棱椎的4個頂點(diǎn)的顏色
    int[] taperColors = new int[]{
            65535, 0, 0, 0,  // 紅色
            0, 65535, 0, 0,     // 綠色
            0, 0, 65535, 0,  // 藍(lán)色
            65535, 65535, 0, 0 //黃色
    };
    // 定義三棱椎的4個三角面
    private byte[] taperFacets = new byte[]{
            0, 1, 2, // 0、1蕾殴、2三個頂點(diǎn)組成一個面
            0, 1, 3, // 0笑撞、1、3三個頂點(diǎn)組成一個面
            1, 2, 3, // 1钓觉、2茴肥、3三個頂點(diǎn)組成一個面
            0, 2, 3 // 0、2荡灾、3三個頂點(diǎn)組成一個面
    };
    // 定義立方體的8個頂點(diǎn)
    float[] cubeVertices = new float[]{
            // 上頂面正方形的4個頂點(diǎn)
            0.5f, 0.5f, 0.5f,
            0.5f, -0.5f, 0.5f,
            -0.5f, -0.5f, 0.5f,
            -0.5f, 0.5f, 0.5f,
            // 下底面正方形的4個頂點(diǎn)
            0.5f, 0.5f, -0.5f,
            0.5f, -0.5f, -0.5f,
            -0.5f, -0.5f, -0.5f,
            -0.5f, 0.5f, -0.5f
    };
    // 定義立方體所需要的6個面(一共是12個三角形所需的頂點(diǎn))
    private byte[] cubeFacets = new byte[]{
            0, 1, 2,
            0, 2, 3,
            2, 3, 7,
            2, 6, 7,
            0, 3, 7,
            0, 4, 7,
            4, 5, 6,
            4, 6, 7,
            0, 1, 4,
            1, 4, 5,
            1, 2, 6,
            1, 5, 6
    };
    // 定義Open GL ES繪制所需要的Buffer對象
    FloatBuffer taperVerticesBuffer;
    IntBuffer taperColorsBuffer;
    ByteBuffer taperFacetsBuffer;
    FloatBuffer cubeVerticesBuffer;
    ByteBuffer cubeFacetsBuffer;
    // 控制旋轉(zhuǎn)的角度
    private float rotate;

    public MyRenderer() {
        // 將三棱椎的頂點(diǎn)位置數(shù)據(jù)數(shù)組包裝成FloatBuffer
        taperVerticesBuffer = floatBufferUtil(taperVertices);
        // 將三棱椎的4個面的數(shù)組包裝成ByteBuffer
        taperFacetsBuffer = ByteBuffer.wrap(taperFacets);
        // 將三棱椎的4個定點(diǎn)的顏色數(shù)組包裝成IntBuffer
        taperColorsBuffer = intBufferUtil(taperColors);
        // 將立方體的頂點(diǎn)位置數(shù)據(jù)數(shù)組包裝成FloatBuffer
        cubeVerticesBuffer = floatBufferUtil(cubeVertices);
        // 將立方體的6個面(12個三角形)的數(shù)組包裝成ByteBuffer
        cubeFacetsBuffer = ByteBuffer.wrap(cubeFacets);
    }

    @Override
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        // 關(guān)閉抗抖動
        gl.glDisable(GL10.GL_DITHER);
        // 設(shè)置系統(tǒng)對透視進(jìn)行修正
        gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST);
        gl.glClearColor(0, 0, 0, 0);
        // 設(shè)置陰影平滑模式
        gl.glShadeModel(GL10.GL_SMOOTH);
        // 啟用深度測試
        gl.glEnable(GL10.GL_DEPTH_TEST);
        // 設(shè)置深度測試的類型
        gl.glDepthFunc(GL10.GL_LEQUAL);
    }

    @Override
    public void onSurfaceChanged(GL10 gl, int width, int height) {
        // 設(shè)置3D視窗的大小及位置
        gl.glViewport(0, 0, width, height);
        // 將當(dāng)前矩陣模式設(shè)為投影矩陣
        gl.glMatrixMode(GL10.GL_PROJECTION);
        // 初始化單位矩陣
        gl.glLoadIdentity();
        // 計(jì)算透視視窗的寬度瓤狐、高度比
        float ratio = (float) width / height;
        // 調(diào)用此方法設(shè)置透視視窗的空間大小。
        gl.glFrustumf(-ratio, ratio, -1, 1, 1, 10);
    }

    // 繪制圖形的方法
    @Override
    public void onDrawFrame(GL10 gl) {
        // 清除屏幕緩存和深度緩存
        gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
        // 啟用頂點(diǎn)坐標(biāo)數(shù)據(jù)
        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
        // 啟用頂點(diǎn)顏色數(shù)據(jù)
        gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
        // 設(shè)置當(dāng)前矩陣模式為模型視圖批幌。
        gl.glMatrixMode(GL10.GL_MODELVIEW);
        // --------------------繪制第一個圖形---------------------
        // 重置當(dāng)前的模型視圖矩陣
        gl.glLoadIdentity();
        gl.glTranslatef(-0.6f, 0.0f, -1.5f);
        // 沿著Y軸旋轉(zhuǎn)
        gl.glRotatef(rotate, 0f, 0.2f, 0f);
        // 設(shè)置頂點(diǎn)的位置數(shù)據(jù)
        gl.glVertexPointer(3, GL10.GL_FLOAT, 0, taperVerticesBuffer);
        // 設(shè)置頂點(diǎn)的顏色數(shù)據(jù)
        gl.glColorPointer(4, GL10.GL_FIXED, 0, taperColorsBuffer);
        // 按taperFacetsBuffer指定的面繪制三角形
        gl.glDrawElements(GL10.GL_TRIANGLE_STRIP
                , taperFacetsBuffer.remaining(),
                GL10.GL_UNSIGNED_BYTE, taperFacetsBuffer);
        // --------------------繪制第二個圖形---------------------
        // 重置當(dāng)前的模型視圖矩陣
        gl.glLoadIdentity();
        gl.glTranslatef(0.7f, 0.0f, -2.2f);
        // 沿著Y軸旋轉(zhuǎn)
        gl.glRotatef(rotate, 0f, 0.2f, 0f);
        // 沿著X軸旋轉(zhuǎn)
        gl.glRotatef(rotate, 1f, 0f, 0f);
        // 設(shè)置頂點(diǎn)的位置數(shù)據(jù)
        gl.glVertexPointer(3, GL10.GL_FLOAT, 0, cubeVerticesBuffer);
        // 不設(shè)置頂點(diǎn)的顏色數(shù)據(jù)础锐,還用以前的顏色數(shù)據(jù)
        // 按cubeFacetsBuffer指定的面繪制三角形
        gl.glDrawElements(GL10.GL_TRIANGLE_STRIP
                , cubeFacetsBuffer.remaining(),
                GL10.GL_UNSIGNED_BYTE, cubeFacetsBuffer);
        // 繪制結(jié)束
        gl.glFinish();
        gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
        // 旋轉(zhuǎn)角度增加1
        rotate += 1;
    }

    // 定義一個工具方法,將int[]數(shù)組轉(zhuǎn)換為OpenGL ES所需的IntBuffer
    private IntBuffer intBufferUtil(int[] arr) {
        IntBuffer mBuffer;
        // 初始化ByteBuffer荧缘,長度為arr數(shù)組的長度*4皆警,因?yàn)橐粋€int占4個字節(jié)
        ByteBuffer qbb = ByteBuffer.allocateDirect(arr.length * 4);
        // 數(shù)組排列用nativeOrder
        qbb.order(ByteOrder.nativeOrder());
        mBuffer = qbb.asIntBuffer();
        mBuffer.put(arr);
        mBuffer.position(0);
        return mBuffer;
    }

    // 定義一個工具方法,將float[]數(shù)組轉(zhuǎn)換為OpenGL ES所需的FloatBuffer
    private FloatBuffer floatBufferUtil(float[] arr) {
        FloatBuffer mBuffer;
        // 初始化ByteBuffer截粗,長度為arr數(shù)組的長度*4信姓,因?yàn)橐粋€int占4個字節(jié)
        ByteBuffer qbb = ByteBuffer.allocateDirect(arr.length * 4);
        // 數(shù)組排列用nativeOrder
        qbb.order(ByteOrder.nativeOrder());
        mBuffer = qbb.asFloatBuffer();
        mBuffer.put(arr);
        mBuffer.position(0);
        return mBuffer;
    }
}
public class MainActivity extends AppCompatActivity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // 創(chuàng)建一個GLSurfaceView,用于顯示OpenGL繪制的圖形
        GLSurfaceView glView = new GLSurfaceView(this);
        // 創(chuàng)建GLSurfaceView的內(nèi)容繪制器
        MyRenderer myRender = new MyRenderer();
        // 為GLSurfaceView設(shè)置繪制器
        glView.setRenderer(myRender);
        setContentView(glView);
    }
}
image.gif

應(yīng)用紋理貼圖

public class MainActivity extends AppCompatActivity implements GestureDetector.OnGestureListener {
    // 定義旋轉(zhuǎn)角度
    private float anglex = 0f;
    private float angley = 0f;
    static final float ROTATE_FACTOR = 60;
    // 定義手勢檢測器實(shí)例
    GestureDetector detector;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // 創(chuàng)建一個GLSurfaceView绸罗,用于顯示OpenGL繪制的圖形
        GLSurfaceView glView = new GLSurfaceView(this);
        // 創(chuàng)建GLSurfaceView的內(nèi)容繪制器
        MyRenderer myRender = new MyRenderer(this);
        // 為GLSurfaceView設(shè)置繪制器
        glView.setRenderer(myRender);
        setContentView(glView);
        // 創(chuàng)建手勢檢測器
        detector = new GestureDetector(this, this);
    }

    @Override
    public boolean onTouchEvent(MotionEvent me) {
        // 將該Activity上的觸碰事件交給GestureDetector處理
        return detector.onTouchEvent(me);
    }

    @Override
    public boolean onFling(MotionEvent event1, MotionEvent event2,
                           float velocityX, float velocityY) {
        velocityX = velocityX > 2000 ? 2000 : velocityX;
        velocityX = velocityX < -2000 ? -2000 : velocityX;
        velocityY = velocityY > 2000 ? 2000 : velocityY;
        velocityY = velocityY < -2000 ? -2000 : velocityY;
        // 根據(jù)橫向上的速度計(jì)算沿Y軸旋轉(zhuǎn)的角度
        angley += velocityX * ROTATE_FACTOR / 4000;
        // 根據(jù)縱向上的速度計(jì)算沿X軸旋轉(zhuǎn)的角度
        anglex += velocityY * ROTATE_FACTOR / 4000;
        return true;
    }

    @Override
    public boolean onDown(MotionEvent arg0) {
        return false;
    }

    @Override
    public void onLongPress(MotionEvent event) {
    }

    @Override
    public boolean onScroll(MotionEvent event1, MotionEvent event2,
                            float distanceX, float distanceY) {
        return false;
    }

    @Override
    public void onShowPress(MotionEvent event) {
    }

    @Override
    public boolean onSingleTapUp(MotionEvent event) {
        return false;
    }

    public class MyRenderer implements GLSurfaceView.Renderer {
        // 立方體的頂點(diǎn)坐標(biāo)(一共是36個頂點(diǎn)意推,組成12個三角形)
        private float[] cubeVertices = {-0.6f, -0.6f, -0.6f, -0.6f, 0.6f,
                -0.6f, 0.6f, 0.6f, -0.6f, 0.6f, 0.6f, -0.6f, 0.6f, -0.6f, -0.6f,
                -0.6f, -0.6f, -0.6f, -0.6f, -0.6f, 0.6f, 0.6f, -0.6f, 0.6f, 0.6f,
                0.6f, 0.6f, 0.6f, 0.6f, 0.6f, -0.6f, 0.6f, 0.6f, -0.6f, -0.6f,
                0.6f, -0.6f, -0.6f, -0.6f, 0.6f, -0.6f, -0.6f, 0.6f, -0.6f, 0.6f,
                0.6f, -0.6f, 0.6f, -0.6f, -0.6f, 0.6f, -0.6f, -0.6f, -0.6f, 0.6f,
                -0.6f, -0.6f, 0.6f, 0.6f, -0.6f, 0.6f, 0.6f, 0.6f, 0.6f, 0.6f,
                0.6f, 0.6f, -0.6f, 0.6f, 0.6f, -0.6f, -0.6f, 0.6f, 0.6f, -0.6f,
                -0.6f, 0.6f, -0.6f, -0.6f, 0.6f, 0.6f, -0.6f, 0.6f, 0.6f, 0.6f,
                0.6f, 0.6f, 0.6f, 0.6f, -0.6f, -0.6f, 0.6f, -0.6f, -0.6f, -0.6f,
                -0.6f, -0.6f, -0.6f, 0.6f, -0.6f, -0.6f, 0.6f, -0.6f, 0.6f, 0.6f,
                -0.6f, 0.6f, -0.6f,};
        // 定義立方體所需要的6個面(一共是12個三角形所需的頂點(diǎn))
        private byte[] cubeFacets = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
                13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
                30, 31, 32, 33, 34, 35,};
        // 定義紋理貼圖的坐標(biāo)數(shù)據(jù)
        private float[] cubeTextures = {1.0000f, 1.0000f, 1.0000f, 0.0000f,
                0.0000f, 0.0000f, 0.0000f, 0.0000f, 0.0000f, 1.0000f, 1.0000f,
                1.0000f, 0.0000f, 1.0000f, 1.0000f, 1.0000f, 1.0000f, 0.0000f,
                1.0000f, 0.0000f, 0.0000f, 0.0000f, 0.0000f, 1.0000f, 0.0000f,
                1.0000f, 1.0000f, 1.0000f, 1.0000f, 0.0000f, 1.0000f, 0.0000f,
                0.0000f, 0.0000f, 0.0000f, 1.0000f, 0.0000f, 1.0000f, 1.0000f,
                1.0000f, 1.0000f, 0.0000f, 1.0000f, 0.0000f, 0.0000f, 0.0000f,
                0.0000f, 1.0000f, 0.0000f, 1.0000f, 1.0000f, 1.0000f, 1.0000f,
                0.0000f, 1.0000f, 0.0000f, 0.0000f, 0.0000f, 0.0000f, 1.0000f,
                0.0000f, 1.0000f, 1.0000f, 1.0000f, 1.0000f, 0.0000f, 1.0000f,
                0.0000f, 0.0000f, 0.0000f, 0.0000f, 1.0000f};
        private Context context;
        private FloatBuffer cubeVerticesBuffer;
        private ByteBuffer cubeFacetsBuffer;
        private FloatBuffer cubeTexturesBuffer;
        // 定義本程序所使用的紋理
        private int texture;

        public MyRenderer(Context main) {
            this.context = main;
            // 將立方體的頂點(diǎn)位置數(shù)據(jù)數(shù)組包裝成FloatBuffer;
            cubeVerticesBuffer = floatBufferUtil(cubeVertices);
            // 將立方體的6個面(12個三角形)的數(shù)組包裝成ByteBuffer
            cubeFacetsBuffer = ByteBuffer.wrap(cubeFacets);
            // 將立方體的紋理貼圖的坐標(biāo)數(shù)據(jù)包裝成FloatBuffer
            cubeTexturesBuffer = floatBufferUtil(cubeTextures);
        }

        @Override
        public void onSurfaceCreated(GL10 gl, EGLConfig config) {
            // 關(guān)閉抗抖動
            gl.glDisable(GL10.GL_DITHER);
            // 設(shè)置系統(tǒng)對透視進(jìn)行修正
            gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST);
            gl.glClearColor(0, 0, 0, 0);
            // 設(shè)置陰影平滑模式
            gl.glShadeModel(GL10.GL_SMOOTH);
            // 啟用深度測試
            gl.glEnable(GL10.GL_DEPTH_TEST);
            // 設(shè)置深度測試的類型
            gl.glDepthFunc(GL10.GL_LEQUAL);
            // 啟用2D紋理貼圖
            gl.glEnable(GL10.GL_TEXTURE_2D);
            // 裝載紋理
            loadTexture(gl);
        }

        @Override
        public void onSurfaceChanged(GL10 gl, int width, int height) {
            // 設(shè)置3D視窗的大小及位置
            gl.glViewport(0, 0, width, height);
            // 將當(dāng)前矩陣模式設(shè)為投影矩陣
            gl.glMatrixMode(GL10.GL_PROJECTION);
            // 初始化單位矩陣
            gl.glLoadIdentity();
            // 計(jì)算透視視窗的寬度、高度比
            float ratio = (float) width / height;
            // 調(diào)用此方法設(shè)置透視視窗的空間大小从诲。
            gl.glFrustumf(-ratio, ratio, -1, 1, 1, 10);
        }

        public void onDrawFrame(GL10 gl) {
            // 清除屏幕緩存和深度緩存
            gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
            // 啟用頂點(diǎn)坐標(biāo)數(shù)據(jù)
            gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
            // 啟用貼圖坐標(biāo)數(shù)組數(shù)據(jù)
            gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);   // ①
            // 設(shè)置當(dāng)前矩陣模式為模型視圖。
            gl.glMatrixMode(GL10.GL_MODELVIEW);
            gl.glLoadIdentity();
            // 把繪圖中心移入屏幕2個單位
            gl.glTranslatef(0f, 0.0f, -2.0f);
            // 旋轉(zhuǎn)圖形
            gl.glRotatef(angley, 0, 1, 0);
            gl.glRotatef(anglex, 1, 0, 0);
            // 設(shè)置頂點(diǎn)的位置數(shù)據(jù)
            gl.glVertexPointer(3, GL10.GL_FLOAT, 0, cubeVerticesBuffer);
            // 設(shè)置貼圖的坐標(biāo)數(shù)據(jù)
            gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, cubeTexturesBuffer);  // ②
            // 執(zhí)行紋理貼圖
            gl.glBindTexture(GL10.GL_TEXTURE_2D, texture);  // ③
            // 按cubeFacetsBuffer指定的面繪制三角形
            gl.glDrawElements(GL10.GL_TRIANGLES, cubeFacetsBuffer.remaining(),
                    GL10.GL_UNSIGNED_BYTE, cubeFacetsBuffer);
            // 繪制結(jié)束
            gl.glFinish();
            // 禁用頂點(diǎn)靡羡、紋理坐標(biāo)數(shù)組
            gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
            gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
            // 遞增角度值以便每次以不同角度繪制
        }

        private void loadTexture(GL10 gl) {
            Bitmap bitmap = null;
            try {
                // 加載位圖
                bitmap = BitmapFactory.decodeResource(context.getResources(),
                        R.drawable.sand);
                int[] textures = new int[1];
                // 指定生成N個紋理(第一個參數(shù)指定生成一個紋理)
                // textures數(shù)組將負(fù)責(zé)存儲所有紋理的代號
                // offset指定從第幾個數(shù)組元素開始存放紋理代號
                gl.glGenTextures(1, textures, 0);
                // 獲取textures紋理數(shù)組中的第一個紋理
                texture = textures[0];
                // 通知OpenGL將texture紋理綁定到GL10.GL_TEXTURE_2D目標(biāo)中
                gl.glBindTexture(GL10.GL_TEXTURE_2D, texture);
                // 設(shè)置紋理被縮邢德濉(距離視點(diǎn)很遠(yuǎn)時被縮锌⌒浴)時的濾波方式
                gl.glTexParameterf(GL10.GL_TEXTURE_2D,
                        GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST);
                // 設(shè)置紋理被放大(距離視點(diǎn)很近時被方法)時的濾波方式
                gl.glTexParameterf(GL10.GL_TEXTURE_2D,
                        GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
                // 設(shè)置在橫向、縱向上都是平鋪紋理
                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);
            } finally {
                // 生成紋理之后描扯,回收位圖
                if (bitmap != null)
                    bitmap.recycle();
            }
        }
    }

    // 定義一個工具方法定页,將float[]數(shù)組轉(zhuǎn)換為OpenGL ES所需的FloatBuffer
    private FloatBuffer floatBufferUtil(float[] arr) {
        FloatBuffer mBuffer;
        // 初始化ByteBuffer,長度為arr數(shù)組的長度*4绽诚,因?yàn)橐粋€int占4個字節(jié)
        ByteBuffer qbb = ByteBuffer.allocateDirect(arr.length * 4);
        // 數(shù)組排列用nativeOrder
        qbb.order(ByteOrder.nativeOrder());
        mBuffer = qbb.asFloatBuffer();
        mBuffer.put(arr);
        mBuffer.position(0);
        return mBuffer;
    }
}

摘抄至《瘋狂Android講義(第4版)》

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末典徊,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子恩够,更是在濱河造成了極大的恐慌卒落,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蜂桶,死亡現(xiàn)場離奇詭異儡毕,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)扑媚,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進(jìn)店門腰湾,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人疆股,你說我怎么就攤上這事费坊。” “怎么了旬痹?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵附井,是天一觀的道長。 經(jīng)常有香客問我唱凯,道長羡忘,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任磕昼,我火速辦了婚禮卷雕,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘票从。我一直安慰自己漫雕,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布峰鄙。 她就那樣靜靜地躺著浸间,像睡著了一般。 火紅的嫁衣襯著肌膚如雪吟榴。 梳的紋絲不亂的頭發(fā)上魁蒜,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼兜看。 笑死锥咸,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的细移。 我是一名探鬼主播搏予,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼弧轧!你這毒婦竟也來了雪侥?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤精绎,失蹤者是張志新(化名)和其女友劉穎速缨,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體捺典,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡鸟廓,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了襟己。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片引谜。...
    茶點(diǎn)故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖擎浴,靈堂內(nèi)的尸體忽然破棺而出员咽,到底是詐尸還是另有隱情,我是刑警寧澤贮预,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布贝室,位于F島的核電站,受9級特大地震影響仿吞,放射性物質(zhì)發(fā)生泄漏滑频。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一唤冈、第九天 我趴在偏房一處隱蔽的房頂上張望峡迷。 院中可真熱鬧,春花似錦你虹、人聲如沸绘搞。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽夯辖。三九已至,卻和暖如春董饰,著一層夾襖步出監(jiān)牢的瞬間蒿褂,已是汗流浹背圆米。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留啄栓,地道東北人榨咐。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像谴供,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子齿坷,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評論 2 345

推薦閱讀更多精彩內(nèi)容