OpenGL之顏色

OpenGL之基礎(chǔ)
OpenGL之繪制簡單形狀

平滑著色

實現(xiàn)矩形中間亮,邊緣暗淡的效果,使用三角形扇繪制矩形,并給頂點添加顏色信息

三角形扇

如下圖所示,如果用四個三角形組成矩形,有很多頂點是可以共用的,三角形扇就是一種共用頂點的方式


image-20211220220703248.png

一個三角形扇以一個中心頂點作為起始,使用相鄰的兩個頂點創(chuàng)建第一個三角形,接下來的每個頂點都會創(chuàng)建一個三角形,圍繞起始的中心點按扇形展開。為了使這個扇形閉合,我們只需要在最后重復(fù)第二個點


image-20211220221031080.png

添加顏色屬性

給頂點數(shù)組增加顏色屬性

// 頂點數(shù)據(jù)
float[] vertex = new float[]{
        // 位置(x,y)+顏色(r,g,b)信息
        0f, 0f, 0.9f, 0.9f, 0.9f,
        -0.8f, -0.8f, 0.6f, 0.6f, 0.6f,
        0.8f, -0.8f, 0.6f, 0.6f, 0.6f,
        0.8f, 0.8f, 0.6f, 0.6f, 0.6f,
        -0.8f, 0.8f, 0.6f, 0.6f, 0.6f,
        -0.8f, -0.8f, 0.6f, 0.6f, 0.6f,

        -0.8f, 0f, 1f, 0f, 0f,
        0.8f, 0f, 1f, 0f, 0f,

        0f, -0.5f, 0f, 1f, 0f,
        0f, 0.5f, 0f, 0f, 1f
};

OpenGL中的一種顏色有4個分量(紅色、綠色、藍(lán)色和阿爾法),但不必指定所有分量的值,不像uniform 必須傳入4個分量,OpenGL 會用默認(rèn)值替換 attribute 中未指定值的分量:前三個分量會被設(shè)為0,而最后一個分量會被設(shè)為1

我這里的顏色分量是隨意寫的,可以使用下面的方法獲取顏色分量

int parsedColor = Color.parseColor("#874326");
float red = Color.red(parsedColor) / 255f;
float green = Color.green(parsedColor) / 255f;
float blue = Color.blue(parsedColor) / 255f;

給著色器增加顏色屬性

頂點著色器
attribute vec4 a_Position;
attribute vec4 a_Color;

varying vec4 v_Color;
void main(){
    v_Color=a_Color;
    gl_Position=a_Position;
    gl_PointSize=10.0;
}

加入了一個新的 attribute 類型的 a_Color,也加入了一個 varying 類型的 v_Color

varying 是一個特殊的變量類型,它會把給它的那些值進(jìn)行混合,并把這些混合后的值發(fā)送給片段著色器

例如:兩個頂點 A 和 B 構(gòu)成一條直線,并為這條直線生成片段,如果頂點 A 的 a_Color 是紅色,且頂點 B 的 a_Color 是綠色,通過把 a_Color 賦值給 v_Color,來告訴 OpenGL 我們需要每個片段都接收一個混合后的顏色,接近頂點0的片段,混合后的顏色顯得更紅,而越接近頂點1的片段,顏色就會越綠。

片段著色器
precision mediump float;
varying vec4 v_Color;
void main(){
    gl_FragColor=v_Color;
}

用 varying 類型的變量 v_Color 替換了原來代碼中的 uniform 類型的 u_Color,如果那個片段屬于一條直線,那么 OpenGL 就會用構(gòu)成那條直線的兩個頂點計算其混合后的顏色,如果那個片段屬于一個三角形,那 OpenGL 就會用構(gòu)成那個三角形的三個頂點計算其混合后的顏色,然后傳給 v_Color ,而 v_Color 的值又會被賦值給最終的顏色值 gl_FragColor 作為當(dāng)前片段的最終顏色

使用新的顏色屬性渲染

已經(jīng)給數(shù)據(jù)增加了一個顏色屬性,并且更新了頂點和片段著色器,讓它們使用這個屬性,因此要去掉使用 unifom 傳遞顏色的舊代碼,并告訴 OpenGL 把顏色作為一個頂點屬性讀入

public class MyRenderer implements GLSurfaceView.Renderer {
    private final FloatBuffer mVertexBuffer;
    private Context mContext;
    private int a_color;
    private int a_position;

    public MyRenderer(Context context) {
        mContext = context;
        // 頂點數(shù)據(jù)
        float[] vertex = new float[]{
                // 位置(x,y)+顏色(r,g,b)信息
                0f, 0f, 0.9f, 0.9f, 0.9f,
                -0.8f, -0.8f, 0.6f, 0.6f, 0.6f,
                0.8f, -0.8f, 0.6f, 0.6f, 0.6f,
                0.8f, 0.8f, 0.6f, 0.6f, 0.6f,
                -0.8f, 0.8f, 0.6f, 0.6f, 0.6f,
                -0.8f, -0.8f, 0.6f, 0.6f, 0.6f,

                -0.8f, 0f, 1f, 0f, 0f,
                0.8f, 0f, 1f, 0f, 0f,

                0f, -0.5f, 0f, 1f, 0f,
                0f, 0.5f, 0f, 0f, 1f
        };
        mVertexBuffer = ByteBuffer.allocateDirect(vertex.length * 4)
                .order(ByteOrder.nativeOrder())
                .asFloatBuffer()
                .put(vertex);
        mVertexBuffer.position(0);
    }

    @Override
    public void onSurfaceCreated(GL10 gl10, EGLConfig eglConfig) {
        glClearColor(1f, 1f, 1f, 1f);

        int vertexShader = ShaderHelper.compileVertexShader(mContext, R.raw.gradient2_vertex);
        int fragmentShader = ShaderHelper.compileFragmentShader(mContext, R.raw.gradient2_fragment);
        int program = ProgramHelper.getProgram(vertexShader, fragmentShader);
        glUseProgram(program);

        a_color = glGetAttribLocation(program, "a_Color");
        a_position = glGetAttribLocation(program, "a_Position");

        // 調(diào)節(jié)緩沖區(qū)的指針,從第一個數(shù)據(jù)讀
        mVertexBuffer.position(0);
        // STRIDE 傳入一個頂點的所有屬性占用的 Float 個數(shù),表示下一個頂點數(shù)據(jù)從哪里開始讀
        glVertexAttribPointer(a_position, POSITION_COMPONENT_COUNT, GL_FLOAT, false, STRIDE, mVertexBuffer);
        // 使能頂點屬性數(shù)組,每個attribute都要調(diào)用一次,相當(dāng)于一個開關(guān),調(diào)用后,OpenGL才知道到哪里找到屬性對應(yīng)的數(shù)據(jù)
        glEnableVertexAttribArray(a_position);

        // 調(diào)節(jié)緩沖區(qū)的指針,從表示顏色的位置開始讀
        mVertexBuffer.position(POSITION_COMPONENT_COUNT);
        glVertexAttribPointer(a_color, COLOR_COMPONENT_COUNT, GL_FLOAT, false, STRIDE, mVertexBuffer);
        glEnableVertexAttribArray(a_color);
    }

    @Override
    public void onSurfaceChanged(GL10 gl10, int width, int height) {
        glViewport(0, 0, width, height);
    }

    @Override
    public void onDrawFrame(GL10 gl10) {
        glClear(GL_COLOR_BUFFER_BIT);
        glDrawArrays(GL_TRIANGLE_FAN, 0, 6);

        glDrawArrays(GL_LINES, 6, 2);

        glDrawArrays(GL_POINTS, 8, 1);
        glDrawArrays(GL_POINTS, 9, 1);
    }
}

效果圖

image-20211220220504459.png
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容