Opengl ES(二):畫一個三角形之創造一個三角形

###

在第一個例子裏面,我們創建了兩個類來更改背景顏色  Opengl ES(一):第一個例子

對於opengl ES的架構有了一定的認識,接下來我們繼續去畫一個三角形,代碼參考

https://developer.android.google.cn/training/graphics/opengl/shapes

https://developer.android.google.cn/training/graphics/opengl/draw

###

可以分爲兩步,第一步是創造一個三角形,第二步是將這個三角形輸出到屏幕上顯示。

本篇文章先介紹如何創造一個三角形。

###創造一個三角形

根據Opengl的渲染流程,我們創造一個三角形就需要將三角形頂點座標表示出來,並存儲到頂點緩衝區,以待後面頂點着色器處理。

Opengl支持的座標是三維float型歸一化的,通常用一維數組來表示,如[0,0,0]表示座標原點,[1,1,0]表示最右上角。下面的一維float數組就存儲了三個頂點的信息。

    static float triangleCoords[] = {   // in counterclockwise order:
             0.0f,  0.622008459f, 0.0f, // top
            -0.5f, -0.311004243f, 0.0f, // bottom left
             0.5f, -0.311004243f, 0.0f  // bottom right
    };

接下來我們將頂點信息存儲到頂點緩存區即可,來看看代碼。

public class Triangle {

    private FloatBuffer vertexBuffer;

    static float triangleCoords[] = {   // in counterclockwise order:
             0.0f,  0.622008459f, 0.0f, // top
            -0.5f, -0.311004243f, 0.0f, // bottom left
             0.5f, -0.311004243f, 0.0f  // bottom right
    };

    public Triangle() {
        // 初始化頂點數據Buffer
        ByteBuffer bb = ByteBuffer.allocateDirect(
                // (一個float型4字節)
                triangleCoords.length * 4);
        // 字節序使用native order
        bb.order(ByteOrder.nativeOrder());

        // 將ByteBuffer轉換爲浮點型FloatBuffer
        vertexBuffer = bb.asFloatBuffer();
        // 將頂點數據添加到Buffer
        vertexBuffer.put(triangleCoords);
        // Buffer位置調整到開頭
        vertexBuffer.position(0);
    }
}

我們使用的類型是FloatBuffer,理論上直接將頂點數據put進我們創建的vertexBuffer即可。那爲什麼要繞一圈使用ByteBuffer再構建FloatBuffer呢?

##?爲什麼不直接使用FloatBuffer構建

我嘗試直接用FloatBuffer來存儲頂點座標,提示的錯誤是:Must use a native order direct Buffer

至於爲什麼要這樣做,我沒有查到,也許是opengl的規範?

網上很多文章說是因爲order的問題,即java是大端字節序,opengl是小端字節序,但根據FloatBuffer中order的描述和自己的驗證(使用.odrer()輸出字節序),直接使用FloatBuffer的allocate就是native order。所以問題應該出在direct這裏,這裏Buffer有兩個要求,一個是native order,另一個是direct Buffer。

驗證order()的結果
FloatBuffer中order()的描述

 

我們可以從FloatBuffer的描述中發現,確實是direct Buffer的問題。有且僅有從direct的ByteBuffer轉換到FloatBuffer纔是direct的。再去查看ByteBuffer的方法函數,發現它有兩個allocate作用的函數,allocateDirect()就是我們需要的。

再查看ByteBuffer的其他方法的話,可以發現它也有兩個order()函數,一個是用於查詢,一個是用於修改,而FloatBuffer只有一個用於查看字節序的方法。

所以爲了保險起見,我們最好使用ByteBuffer.order()設置order爲native order。

ByteBuffer的order()方法
FloatBuffer的order()方法

這時候就清楚了,由於Must use a native order direct Buffer這個要求,我們需要先用ByteBuffer創建Direct緩存區,並保證order爲native order,再轉換成FloatBuffer,最後傳入數據即可。

###

我們就已經將頂點數據傳入了Buffer,在創造三角形的時候,我們還可以添加顏色等信息,所以在類中可以再加入一些信息。

最後創造三角形的代碼如下

public class Triangle {

    private FloatBuffer vertexBuffer;

    // 數組中每個頂點的座標數(即維數)
    static final int COORDS_PER_VERTEX = 3;
    static float triangleCoords[] = {   // in counterclockwise order:
             0.0f,  0.622008459f, 0.0f, // top
            -0.5f, -0.311004243f, 0.0f, // bottom left
             0.5f, -0.311004243f, 0.0f  // bottom right
    };
    // 顏色信息,分別是RGB和alpha通道的歸一化值
    float color[] = { 0.63671875f, 0.76953125f, 0.22265625f, 1.0f };

    public Triangle() {
        // 初始化頂點數據Buffer
        ByteBuffer bb = ByteBuffer.allocateDirect(
                // (一個float型4字節)
                triangleCoords.length * 4);
        // 字節序使用native order
        bb.order(ByteOrder.nativeOrder());

        // 將ByteBuffer轉換爲浮點型FloatBuffer
        vertexBuffer = bb.asFloatBuffer();
        // 將頂點數據添加到Buffer
        vertexBuffer.put(triangleCoords);
        // Buffer位置調整到開頭
        vertexBuffer.position(0);
    }
}

接下來就是將這個三角形輸出顯示到屏幕上了!

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