[ - OpenGLES3.0 - ] 第二集 主線 - 繪製面與圖片貼圖

問:學OpenGL能幹嗎? 答: 隨心所欲。編程

提及OpenGLES,你們可能都敬而遠之,其實它並無想象中的那麼可怕,固然也並無那麼容易
都0202年了,本系列使用OpenGLES3.0,這是一次有預謀的計劃:數組

這是正文的第二篇,在上一篇講述了OpenGLES的基本使用
如今你已經可以操做着色器繪製點線了,若是你還不會,請先看第一集緩存


1.三角形繪製

三角形是OpenGL中最重要的一種圖形,能夠說全部的體和麪都是由三角形拼組而成
全部這一節是很是重要的。bash


1.1 三點繪製三角形:GL_TRIANGLES

目前的座標系以下: 三個點從右上角開始逆時針,白、紅、綠微信

//頂點數組
private final float vertexes[] = {//以逆時針順序
        1.0f, 1.0f, 0.0f,
        -1.0f, 1.0f, 0.0f,
        -1.0f, -1.0f, 0.0f,
};
// 顏色數組
private final float colors[] = new float[]{
        1.0f, 1.0f, 1.0f, 1.0f,//白色
        1.0f, 0.0f, 0.0f, 1.0f,//紅色
        0.0f, 1.0f, 0.0f, 1.0f,//綠色
};
複製代碼

由三點進行繪製三角形,繪製時使用GLES30.GL_TRIANGLES便可函數

GLES30.glDrawArrays(GLES30.GL_TRIANGLES, 0, vertexes.length / VERTEX_DIMENSION);
複製代碼

1.2 三角形三種模式比較

繪製三角形有三種模式,另外兩個是:GL_TRIANGLE_STRIPGL_TRIANGLE_STRIP
下面經過四個點進行對比演示工具

//頂點數組
private final float vertexes[] = {   //以逆時針順序
        1.0f, 1.0f, 0.0f,//原點
        -1.0f, 1.0f, 0.0f,
        -1.0f, -1.0f, 0.0f,
        1.0f, -1.0f, 0.0f,
};
// 顏色數組
private final float colors[] = new float[]{
        1.0f, 1.0f, 1.0f, 1.0f,//白色
        1.0f, 0.0f, 0.0f, 1.0f,//紅色
        0.0f, 1.0f, 0.0f, 1.0f,//綠色
        0.0f, 0.0f, 1.0f, 1.0f,//藍色
};
複製代碼

glDrawArrays:
---->[繪製點線]-------
GLES20.GL_POINTS            繪製點
GLES20.GL_LINES             兩點一線
GLES20.GL_LINE_STRIP        相鄰兩點一線(不連首尾)
GLES20.GL_LINE_LOOP         相鄰兩點一線(連首尾)

---->[繪製三角形]-------
GLES20.GL_TRIANGLES         三點一個(不夠三個,被忽略)
GLES20.GL_TRIANGLE_STRIP    相鄰三點一個
GLES20.GL_TRIANGLE_FAN      第一點中心,散射到其餘點
複製代碼

矩形也就是兩個三角形拼成的,因此如今繪製面的技能你已經get了。post


2.圓的繪製

如今你應該有所體會,OpenGL中最重要的是處理頂點和顏色的數據
圓形的繪製無非就是找到那些頂點在哪裏,根據三角函數很容易求得測試

下面的圖很好的體現了這些點的座標是如何肯定的ui

private void initData() {
    //頂點座標數據的初始化
    int verticeCount = splitCount + 2;
    vertexes = new float[verticeCount * 3];//座標數據
    colors = new float[verticeCount * 4];//顏色數據
    float thta = 360.f / splitCount;
    vertexes[0] = 0;
    vertexes[1] = 0;
    vertexes[2] = 0;
    colors[0] = 1;
    colors[1] = 1;
    colors[2] = 1;
    colors[3] = 1;
    
    for (int n = 1; n <= verticeCount - 1; n++) {
        vertexes[n * 3] = r * cos((n - 1) * thta);//x
        vertexes[n * 3 + 1] = r * sin((n - 1) * thta);//y
        vertexes[n * 3 + 2] = 0;//z
        
        colors[4 * n] = 1;
        colors[4 * n + 1] = 0;
        colors[4 * n + 2] = 0;
        colors[4 * n + 3] = 1.0f;
    }
}
複製代碼

3.貼圖的使用

沒有貼圖,就像肉包裏沒有肉餡。以前咱們都是自定義顏色去給頂點着色
而貼圖就是使用圖形象的像素信息來給頂點着色,get貼圖技能以後,
你就能夠用OpenGLES 對圖片進行處理和展現,甚至保存。這也是支線1的基礎


3.1 貼圖紋理座標

要注意,貼圖的紋理座標系是一個二維繫,原點在左上角,注意和頂點系區分
下面是頂點系xoy面紋理系的示意圖,咱們須要給出紋理座標,就能夠把圖片貼起來:

點位座標與紋理座標.png

//頂點數組
private final float vertexes[] = {   //以逆時針順序
        1.0f, 1.0f, 0.0f,//原點
        -1.0f, 1.0f, 0.0f,
        -1.0f, -1.0f, 0.0f,
        1.0f, -1.0f, 0.0f,
};
// 貼圖座標
private final float textureCoo[] = new float[]{
        1.0f,0.0f,
        0.0f,0.0f,
        0.0f,1.0f,
        1.0f,1.0f,
};

private static final int VERTEX_DIMENSION = 3;
private static final int TEXTURE_DIMENSION = 2;
複製代碼

3.2 圖片紋理的加載

這裏給出一個圖片加載成貼圖的工具類

//貼圖工具類
public class GLTexture {
    /**
     * 資源id 加載紋理,默認重複方式:RepeatType.REPEAT
     *
     * @param ctx   上下文
     * @param resId 資源id
     * @return 紋理id
     */
    public static int loadTexture(Context ctx, int resId) {
        return loadTexture(ctx, resId, RepeatType.REPEAT);
    }
    /**
     * 圖片加載紋理,默認重複方式:RepeatType.REPEAT
     * @param bitmap 圖片
     * @return 紋理id
     */
    public static int loadTexture(Bitmap bitmap) {
        return loadTexture(bitmap, RepeatType.REPEAT);
    }
    /**
     * 資源id 加載紋理
     *
     * @param ctx        上下文
     * @param resId      資源id
     * @param repeatType 重複方式 {@link RepeatType}
     * @return 紋理id
     */
    public static int loadTexture(Context ctx, int resId, RepeatType repeatType) {
        Bitmap bitmap = BitmapFactory.decodeResource(ctx.getResources(), resId);
        return loadTexture(bitmap, repeatType);
    }
    /**
     * bitmap 加載紋理
     *
     * @param bitmap     bitmap
     * @param repeatType 重複方式 {@link RepeatType}
     * @return 紋理id
     */
    public static int loadTexture(Bitmap bitmap, RepeatType repeatType) {
        //生成紋理ID
        int[] textures = new int[1];
        //(產生的紋理id的數量,紋理id的數組,偏移量)
        GLES30.glGenTextures(1, textures, 0);
        int textureId = textures[0];
        //綁定紋理id
        GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, textureId);
        //採樣方式MIN
        GLES30.glTexParameterf(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MIN_FILTER, GLES30.GL_NEAREST);
        GLES30.glTexParameterf(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MAG_FILTER, GLES30.GL_LINEAR);
        int wrapS = 0;
        int wrapT = 0;
        switch (repeatType) {
            case NONE:
                wrapS = GLES30.GL_CLAMP_TO_EDGE;
                wrapT = GLES30.GL_CLAMP_TO_EDGE;
                break;
            case REPEAT_X:
                wrapS = GLES30.GL_REPEAT;
                wrapT = GLES30.GL_CLAMP_TO_EDGE;
                break;
            case REPEAT_Y:
                wrapS = GLES30.GL_CLAMP_TO_EDGE;
                wrapT = GLES30.GL_REPEAT;
                break;
            case REPEAT:
                wrapS = GLES30.GL_REPEAT;
                wrapT = GLES30.GL_REPEAT;
                break;
        }
        //設置s軸拉伸方式---重複
        GLES30.glTexParameterf(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_WRAP_S, wrapS);
        //設置t軸拉伸方式---重複
        GLES30.glTexParameterf(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_WRAP_T, wrapT);
        //實際加載紋理(紋理類型,紋理的層次,紋理圖像,紋理邊框尺寸)
        GLUtils.texImage2D(GLES30.GL_TEXTURE_2D, 0, bitmap, 0);
        bitmap.recycle();          //紋理加載成功後釋放圖片
        return textureId;
    }
}

enum RepeatType {
    NONE,//不重複
    REPEAT_X,//僅x軸重複
    REPEAT_Y,//僅y軸重複
    REPEAT//x,y重複
}
複製代碼

3.3 shader着色器更改

主要將vsh中顏色的輸入變量緩存座標變量,在fsh中經過texture函數獲取色值

---->[texture.vsh]----
#version 300 es
layout (location = 0) in vec3 aPosition;
layout (location = 1) in vec2 aTexCoord;
uniform mat4 uMVPMatrix;

out vec2 vTexCoord;

void main(){
    gl_Position = uMVPMatrix*vec4(aPosition.x, aPosition.y, aPosition.z, 1.0);
    vTexCoord = aTexCoord;
}

---->[texture.fsh]----
#version 300 es
precision mediump float;
out vec4 outColor;

in vec2 vTexCoord;

uniform sampler2D sTexture;

void main(){
    outColor = texture(sTexture, vTexCoord);
}
複製代碼

3.4 代碼的使用

主體和前面同樣,這裏用GLTextureTriangle類進行貼圖測試

public class GLTextureTriangle {
    //頂點數組
    private final float vertexes[] = {   //以逆時針順序
            1.0f, 1.0f, 0.0f,//原點
            -1.0f, 1.0f, 0.0f,
            -1.0f, -1.0f, 0.0f,
            1.0f, -1.0f, 0.0f,
    };

    // 貼圖座標
    private final float textureCoo[] = new float[]{
            1.0f,0.0f,
            0.0f,0.0f,
            0.0f,1.0f,
            1.0f,1.0f,
    };

    private int program;
    private static final int VERTEX_DIMENSION = 3;
    private static final int TEXTURE_DIMENSION = 2;

    private FloatBuffer vertBuffer;
    private FloatBuffer textureCooBuffer;

    private int aPosition = 0;//位置的句柄
    private int aTexCoord = 1;//顏色的句柄
    private int uMVPMatrix;//頂點變換矩陣句柄
    private int textureId;//貼圖id


    public GLTextureTriangle(Context context) {
        textureId= GLTexture.loadTexture(context, R.mipmap.chaos);

        program = GLLoader.initProgramByAssets(context, "texture.vsh", "texture.fsh");
        vertBuffer = GLBuffer.getFloatBuffer(vertexes);
        textureCooBuffer = GLBuffer.getFloatBuffer(textureCoo);
        uMVPMatrix = GLES30.glGetUniformLocation(program, "uMVPMatrix");
    }

    public void draw(float[] mvpMatrix) {
        //清除顏色緩存和深度緩存
        GLES30.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);

        // 將程序添加到OpenGL ES環境中
        GLES30.glUseProgram(program);
        GLES30.glUniformMatrix4fv(uMVPMatrix, 1, false, mvpMatrix, 0);

        //啓用三角形頂點的句柄
        GLES30.glEnableVertexAttribArray(aPosition);
        //啓用三角形頂點顏色的句柄
        GLES30.glEnableVertexAttribArray(aTexCoord);
        //準備三角座標數據
        GLES30.glVertexAttribPointer(
                aPosition, VERTEX_DIMENSION,
                GLES30.GL_FLOAT, false,
                VERTEX_DIMENSION * 4, vertBuffer);

        //準備頂點顏色數據
        GLES30.glVertexAttribPointer(
                aTexCoord, TEXTURE_DIMENSION,
                GLES30.GL_FLOAT, false,
                TEXTURE_DIMENSION * 4, textureCooBuffer);


        //綁定紋理
        GLES30.glActiveTexture(GLES30.GL_TEXTURE0);
        GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, textureId);

        //繪製點
        GLES30.glLineWidth(10);
        GLES30.glDrawArrays(GLES30.GL_TRIANGLE_FAN, 0, vertexes.length / VERTEX_DIMENSION);
        //禁用頂點數組
        GLES30.glDisableVertexAttribArray(aPosition);
        GLES30.glDisableVertexAttribArray(aTexCoord);
    }
}
複製代碼

4. 着色器小試牛刀

也許你會以爲,廢了這麼大半天的勁就展現了一個圖片,有什麼意義?
這就像你給一個不懂編程的人用計算機算出10+10=20同樣,他也會以爲沒什麼意義
但當你演示34564*9894=341976216他就會以爲很厲害。其實本質並無什麼區別
經過着色器的編寫,你就能夠完成你須要的特效,好比OpenGLES3.0 接入視頻實現特效 - 引言

理論上你能夠經過shader完成一切圖片特效。下一篇將會詳細介紹着色器代碼的使用,你將會了解如何經過着色器的代碼控制像素值以及像素的位置。本片就這樣,相信你已經能夠完成貼圖了。


@張風捷特烈 2020.01.11 未允禁轉
個人公衆號:編程之王
聯繫我--郵箱:1981462002@qq.com --微信:zdl1994328
~ END ~

相關文章
相關標籤/搜索