Android音視頻之使用OpenGL ES繪制圖片

關(guān)于 OpenGL ES 的介紹,請先看上篇:Android 音視頻之使用 OpenGL ES 繪制三角形

1. 紋理介紹

使用 OpenGL ES 繪制簡單的幾何形狀還不夠,OpenGL 更多地是用來顯示而紋理圖像,比如本地圖片、相機畫面。簡單說,紋理(texture)就是一個圖像或照片,它們可以被加載進 OpenGL 中。

OpenGL 中的紋理可以用來表示圖像、照片等,每個二維的紋理都由許多小的紋理元素組成,它們是小塊的數(shù)據(jù),類似片段和像素。要使用紋理,最常用的方式是直接從一個圖像文件加載數(shù)據(jù)。

紋理不會被直接繪制,它們要被綁定到紋理單元,然后把這些紋理單元傳遞給著色器。紋理映射的基本思想就是:首先為圖元中的每個頂點指定恰當(dāng)?shù)募y理坐標(biāo),然后通過紋理坐標(biāo)在紋理圖中可以確定選中的紋理區(qū)域,最后將選中紋理區(qū)域中的內(nèi)容根據(jù)紋理坐標(biāo)映射到指定的圖元上。

紋理的坐標(biāo)系和頂點著色器的坐標(biāo)系是不一樣的。紋理坐標(biāo)用浮點數(shù)來表示,范圍 [0, 1],左上角坐標(biāo)為 (0.0, 0.0),右上角坐標(biāo)為 (1.0, 0.0)。注意:要將紋理坐標(biāo)對應(yīng)到正確的頂點上,才能使紋理正確地顯示。

2. 使用紋理顯示圖片

定義頂點和紋理坐標(biāo),兩者的順序必須一一對應(yīng)。

    private static final int COORDS_PER_VERTEX = 2;
    private static final int COORDS_PER_TEXTURE = 2;
    private static final float[] VERTEX = {
            1, 1,  // top right
            -1, 1, // top left
            1, -1, // bottom right
            -1, -1,// bottom left
    };
    private static final float[] TEXTURE = {
            1, 0,  // top right
            0, 0,  // top left
            1, 1,  // bottom right
            0, 1,  // bottom left
    };

定義著色器。

    private static final String VERTEX_SHADER =
            "uniform mat4 uMVPMatrix;" +
                    "attribute vec4 aPosition;" +
                    "attribute vec2 aTexCoord;" +
                    "varying vec2 vTexCoord;" +
                    "void main() {" +
                    "  gl_Position = uMVPMatrix * aPosition;" +
                    "  vTexCoord = aTexCoord;" +
                    "}";
    private static final String FRAGMENT_SHADER =
            "precision mediump float;" +
                    "uniform sampler2D uTextureUnit;" +
                    "varying vec2 vTexCoord;" +
                    "void main() {" +
                    "  gl_FragColor = texture2D(uTextureUnit, vTexCoord);" +
                    "}";

加載圖片到 OpenGL 中。

        // 加載圖片并且保存在 OpenGL 紋理系統(tǒng)中
        Bitmap bitmap = BitmapFactory.decodeFile(mImagePath);
        mBitmapWidth = bitmap.getWidth();
        mBitmapHeight = bitmap.getHeight();
        int[] texture = new int[1];
        // 生成紋理
        GLES20.glGenTextures(1, texture, 0);
        // 綁定紋理
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture[0]);
        // 激活紋理
        GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
        // 設(shè)置縮小過濾為三線性過濾
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR_MIPMAP_LINEAR);
        // 設(shè)置放大過濾為雙線性過濾
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
        // 加載紋理到 OpenGL,讀入 Bitmap 定義的位圖數(shù)據(jù),并把它復(fù)制到當(dāng)前綁定的紋理對象
        GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
        // 生成 MIP 貼圖
        GLES20.glGenerateMipmap(GLES20.GL_TEXTURE_2D);
        // 把選定的紋理單元傳給片段著色器
        GLES20.glUniform1i(texUnitHandle, 0);

計算變換矩陣,采用 CenterInside 或者 CenterCrop 的方式顯示。

    public static float[] changeMvpMatrixInside(float viewWidth, float viewHeight, float textureWidth, float textureHeight) {
        float scale = viewWidth * textureHeight / viewHeight / textureWidth;
        float[] mvp = new float[16];
        Matrix.setIdentityM(mvp, 0);
        Matrix.scaleM(mvp, 0, scale > 1 ? (1F / scale) : 1F, scale > 1 ? 1F : scale, 1F);
        return mvp;
    }

    public static float[] changeMvpMatrixCrop(float viewWidth, float viewHeight, float textureWidth, float textureHeight) {
        float scale = viewWidth * textureHeight / viewHeight / textureWidth;
        float[] mvp = new float[16];
        Matrix.setIdentityM(mvp, 0);
        Matrix.scaleM(mvp, 0, scale > 1 ? 1F : (1F / scale), scale > 1 ? scale : 1F, 1F);
        return mvp;
    }

顯示圖片。

        GLES20.glUseProgram(mProgram);
        GLES20.glUniformMatrix4fv(mMvpMatrixHandle, 1, false, mMvpMatrix, 0);
        // 傳入頂點坐標(biāo)
        GLES20.glEnableVertexAttribArray(mPositionHandle);
        GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, 0, mVertexBuffer);
        // 傳入紋理坐標(biāo)
        GLES20.glEnableVertexAttribArray(mTexCoordHandle);
        GLES20.glVertexAttribPointer(mTexCoordHandle, COORDS_PER_TEXTURE, GLES20.GL_FLOAT, false, 0, mTextureBuffer);
        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, VERTEX.length / COORDS_PER_VERTEX);
        GLES20.glDisableVertexAttribArray(mPositionHandle);
        GLES20.glDisableVertexAttribArray(mTexCoordHandle);
        GLES20.glUseProgram(0);

源碼在 GitHub 上。

參考資料:

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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