[OpengGL]渲染流程和程序流程

這節(jié)要說(shuō)的是Opengles的渲染流程和程序流程,都是一些非惩希基礎(chǔ)的東西野舶,覺(jué)得已經(jīng)熟悉的同學(xué)可以自行忽略。
以下是一幅經(jīng)典的Opengl渲染管線流程圖


Opengl渲染管線.png

1.頂點(diǎn)數(shù)據(jù)

2.基本圖元

Opengles中包含三種圖元方式宰衙,點(diǎn)愕贡,線讽挟,三角形

3.頂點(diǎn)著色器

包含對(duì)頂點(diǎn)數(shù)據(jù)的處理和轉(zhuǎn)換

4.圖元裝配

把所有輸入的頂點(diǎn)數(shù)據(jù)作為輸入,將所有點(diǎn)配裝成指定圖元的形狀

5.幾何著色器

(Opengl特有) 把基本圖元形式的頂點(diǎn)的幾何作為輸入,可以通過(guò)產(chǎn)生新頂點(diǎn)構(gòu)造出新的基本圖元來(lái)生成其它形狀

6.細(xì)分著色器

(Opengl特有)可以把基本圖元細(xì)分為更多的基本圖形菌湃,創(chuàng)建出更加平滑的視覺(jué)效果

7.光柵化

像素化,圖形映射到屏幕上網(wǎng)絡(luò)的像素點(diǎn)逐抑,生成提供片段給片元著色器處理刚夺,光柵化包含一個(gè)剪裁處理,會(huì)計(jì)算舍棄超出定義視窗外的像素

8.片元著色器

為每一個(gè)像素點(diǎn)提供最終的顏色涛贯,這里會(huì)可以提供紋理題圖诽嘉,如果是3D場(chǎng)景其可以包含3D場(chǎng)景的一些額外數(shù)據(jù),例如光線弟翘,陰影

9.測(cè)試和混合

對(duì)每個(gè)像素點(diǎn)進(jìn)行深度測(cè)試虫腋,Alpha測(cè)試并進(jìn)行顏色混合操作,進(jìn)一步合成整個(gè)視窗每一個(gè)像素點(diǎn)最終要顯示的顏色和透明度

Opengl渲染管線.png

如果從API的角度來(lái)分析衅胀,你會(huì)發(fā)現(xiàn)有更多的操作岔乔。

0.頂點(diǎn)緩沖

在輸入頂點(diǎn)數(shù)據(jù)的時(shí)候需要線做頂點(diǎn)緩沖,這里可以使用頂點(diǎn)緩沖去對(duì)象(VBO)滚躯,頂點(diǎn)數(shù)組對(duì)象(VAO)雏门。VBO可以減少IO開(kāi)銷嘿歌,并使用數(shù)組記錄每一個(gè)快數(shù)據(jù)對(duì)應(yīng)綁定的類型(頂點(diǎn)位置、法向量)茁影,這些數(shù)據(jù)會(huì)存放在GPU上宙帝。VAO是使用一個(gè)數(shù)組來(lái)存每一個(gè)VBO儲(chǔ)存的數(shù)據(jù)、類型募闲,每次回執(zhí)時(shí)就不需要一個(gè)一個(gè)傳遞了步脓。
經(jīng)過(guò)片元著色之后,測(cè)試和混合也是分很多種

10.剪裁測(cè)試

每一個(gè)片元在幀緩沖中對(duì)應(yīng)的位置浩螺,若干對(duì)應(yīng)的位置裁剪窗口中則將此片元送入下一個(gè)階段靴患,否則會(huì)丟棄此片元,可以在屏幕上指定區(qū)域繪制要出,不在這片區(qū)域不進(jìn)行繪制

11.深度測(cè)試和模版測(cè)試

深度測(cè)試是用片元的深度值和幀緩沖中儲(chǔ)存的對(duì)應(yīng)位置的片元的深度值進(jìn)行比較鸳君,深度值小的片元會(huì)覆蓋或混合深度值大得片元。
模板測(cè)試 講回執(zhí)區(qū)域限定在一定的范圍內(nèi)患蹂,一般用于湖面倒影或颊,鏡像等場(chǎng)合

12.顏色緩沖和混合

如果程序開(kāi)啟了Alpha混合,則可以根據(jù)上一階段對(duì)應(yīng)的片元和幀緩沖的位置片元進(jìn)行alpha混合

13.抖動(dòng)

抖動(dòng)可以模擬更大的色深传于,需要自己編寫算法實(shí)現(xiàn)囱挑,通過(guò)GL_DITHER來(lái)控制

14.幀緩沖

opengles并不是直接在屏幕上進(jìn)行繪制,是預(yù)先在幀緩沖區(qū)進(jìn)行繪制沼溜,當(dāng)繪制完之后再下將繪制的結(jié)果交換到屏幕上平挑,因此每繪制新的一幀是都需要清除緩沖區(qū)的相關(guān)數(shù)據(jù),否則會(huì)產(chǎn)生不正確的繪制效果盛末。

這些都是基本的渲染流程弹惦,接下來(lái)說(shuō)一下程序流程,以Android程序?yàn)槔?br> 這個(gè)之前需要了解一下Android中屏幕顯示對(duì)Opengles的承載悄但,
SurfaceTexture棠隐,TextureView, SurfaceView和GLSurfaceView

值得注意的是Android直接內(nèi)置了Opengles,并內(nèi)置了GL10檐嚣,GL20助泽,GL30的類,封裝了Opengles的Android API嚎京,當(dāng)然其中也屏蔽了一些細(xì)節(jié)嗡贺,對(duì)于真正去理解opengles實(shí)現(xiàn)有一定的差距。
初學(xué)者很多會(huì)選用GLSurfaceView來(lái)做實(shí)現(xiàn)鞍帝,例如簡(jiǎn)單繪制圖形是沒(méi)問(wèn)題的诫睬。但是我們?nèi)绻钊胍稽c(diǎn)學(xué)習(xí),例如濾鏡帕涌,例如錄制播放摄凡,還是需要使用SurfaceView來(lái)做的续徽,因?yàn)镾urfaceView可以控制繪制的線程,需要自己定義EGL環(huán)境亲澡,還有SurfaceTexture綁定钦扭,同樣這也是初學(xué)者使用時(shí)的難點(diǎn)。

使用一個(gè)GLSurfaceView來(lái)顯示一個(gè)三角形為例床绪,這里就屏蔽了EGL客情、GLThread和SurfaceTexture使用的細(xì)節(jié),重點(diǎn)關(guān)注在Opengles中的實(shí)現(xiàn)癞己。
GLSurfaceView.Render提供三個(gè)回調(diào)接口
onSurfaceCreated 紋理窗口創(chuàng)建
onSurfaceChanged 視口大小更改
onDrawFrame 繪制

初始化流程.png

初始化的時(shí)候膀斋,準(zhǔn)備好頂點(diǎn)著色器和片元著色器內(nèi)容,這里面頂點(diǎn)做色器和片元著色器可以使用字符串讀取末秃,也可以使用glsl的shader文件來(lái)讀取概页。

 //頂點(diǎn)著色器內(nèi)容
    char vShaderStr[] =
                    "#version 300 es                        \n"
                    "layout(location = 0)in vec4 vPosition; \n"
                    "void main()                            \n"
                    "{                                      \n"
                    " gl_Position = vPosition;              \n"
                    "}                                      \n";

    //片元著色器內(nèi)容
    char fShaderStr[] =
                    "#version 300 es                        \n"
                    "precision mediump float;               \n"
                    "out vec4 fragColor;                    \n"
                    "void main()                            \n"
                    "{                                      \n"
                    "   fragColor = vec4(1.0,0.0,0.0,1.0);  \n"
                    "}                                      \n";

加載紋理

GLuint LoadShader(GLenum type,const char *shaderSrc){
    GLuint shader;
    GLint compiled;
    //通過(guò)shader類型來(lái)獲取
    shader = glCreateShader(type);

    if(shader ==0){
        return 0;
    }

    //加載shader資源
    glShaderSource(shader,1,&shaderSrc,NULL);
    //編譯shader資源
    glCompileShader(shader);
    //獲取shader信息
    glGetShaderiv(shader,GL_COMPILE_STATUS,&compiled);

    //編譯不成功籽御,打印日志
    if(!compiled){
        GLint infoLen = 0;
        glGetShaderiv(shader,GL_INFO_LOG_LENGTH,&infoLen);

        if(infoLen >1){
            char *infoLog= (char*)malloc(sizeof(char*) *infoLen);
            glGetShaderInfoLog(shader,infoLen,NULL,infoLog);
            LOGE("Error compiling shader:[%s]",infoLog);
            free(infoLog);
        }
        glDeleteShader(shader);
        return 0;
    }
    //返回編譯成功的shader
    return shader;
}

創(chuàng)建紋理空間->加載紋理資源->編譯紋理

加載紋理綁定到程序

    GLuint vertexShader;
    GLuint fragmentShader;
    GLuint programObject;
    GLint linked;

    //加載頂點(diǎn)著色器
    vertexShader = LoadShader(GL_VERTEX_SHADER, vShaderStr);
    //加載片元著色器
    fragmentShader = LoadShader(GL_FRAGMENT_SHADER, fShaderStr);

    //創(chuàng)建程序
    programObject = glCreateProgram();
    if (programObject == 0) {
        return;
    }

    //綁定頂點(diǎn)著色器
    glAttachShader(programObject, vertexShader);
    //綁定片元著色器
    glAttachShader(programObject, fragmentShader);

    //關(guān)聯(lián)到程序
    glLinkProgram(programObject);

    //獲取程序狀態(tài)
    glGetProgramiv(programObject, GL_LINK_STATUS, &linked);

    //如果沒(méi)有鏈接成功
    if (!linked) {
        GLint infoLen = 0;
        //獲取錯(cuò)誤日志
        glGetProgramiv(programObject, GL_INFO_LOG_LENGTH, &infoLen);

        //錯(cuò)誤日志有內(nèi)容
        if (infoLen > 1) {
            char *infoLog = (char *) malloc(sizeof(char *) * infoLen);
            //讀取對(duì)應(yīng)長(zhǎng)度內(nèi)容
            glGetProgramInfoLog(programObject, infoLen, NULL, infoLog);
            //打印
            LOGE("Error compiling shader:[%s]", infoLog);
            //釋放log
            free(infoLog);
        }
        //關(guān)閉程序
        glDeleteProgram(programObject);
        return;
    }
    //轉(zhuǎn)為全局地址
    g_programObject = programObject;

    //清屏幕
    glClearColor(1.0f, 1.0f, 1.0f, 0.0f);

加載紋理->綁定程序

在GLsurfaceView繪制的時(shí)候练慕,調(diào)用繪制渲染


基礎(chǔ)繪制流程.png
 //頂點(diǎn)
    GLfloat vVertices[] = {
            0.0f, 0.5f, 0.0f,
            -0.5f, -0.5f, 0.0f,
            0.5f, -0.5f, 0.0f
    };

    //清屏
    glViewport(0, 0, g_width, g_height);
    glClear(GL_COLOR_BUFFER_BIT);
    //指定使用程序
    glUseProgram(g_programObject);
    //綁定頂點(diǎn)數(shù)據(jù)到shader
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, vVertices);
    //允許頂點(diǎn)著色器讀取GPU數(shù)據(jù)
    glEnableVertexAttribArray(0);
    //畫三角形
    glDrawArrays(GL_TRIANGLES, 0, 3);

清屏->指定使用程序->傳入?yún)?shù)到著色器->允許GPU讀取->繪制圖形


image.png

日志打印

#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)

Opengles2.0與Opengles3.0區(qū)別

Opengles2.0對(duì)應(yīng)的是Android 2.2(API 8)
Opengles3.0對(duì)應(yīng)的是Android 4.3(API 18)
Opengles3.1對(duì)應(yīng)的是Android 5.0(API 21)

先將頂點(diǎn)著色器和片段著色器文件貼出來(lái)(這是用來(lái)渲染普通視頻用的),這是使用的OpenGLES3.0版本技掏。(存在兼容性問(wèn)題)铃将,下面只是一部分問(wèn)題,且這里就不將bug的log寫出來(lái)了哑梳,這是提示大家正確的寫法劲阎。

頂點(diǎn)著色器

#version 300 es
in vec4 aPosition;//頂點(diǎn)位置
in vec2 aTexCoord;//S T 紋理坐標(biāo)
out vec2 vTexCoord;
void main() {
    vTexCoord = aTexCoord;
    gl_Position = aPosition;
}

片段著色器

#version 300 es
#extension GL_OES_EGL_image_external_essl3 : require
precision mediump float;
in vec2 vTexCoord;
uniform samplerExternalOES sTexture;
out vec4 vFragColor;
void main() {
    vFragColor=texture(sTexture, vTexCoord);
}

1.沒(méi)有在著色器文件中標(biāo)明使用版本的時(shí)候默認(rèn)使用2.0版本。
在上面的著色器文件中添加#version 300 es即表明使用3.0版本鸠真,如果不添加則使用默認(rèn)2.0版本(注意此行必須放在第一行)悯仙。同時(shí)注意使用3.0的api的時(shí)候必須添加此行。

2.3.0中attribute變成了in和out
OpenGL ES 3.0中將2.0的attribute改成了in吠卷,頂點(diǎn)著色器的varying改成out锡垄,片段著色器的varying改成了in,也就是說(shuō)頂點(diǎn)著色器的輸出就是片段著色器的輸入祭隔,另外uniform跟2.0用法一樣货岭。

3.3.0中使用內(nèi)置參數(shù)gl_FragColor會(huì)出問(wèn)題
這里我們只能自定義顏色向量out vec4 vFragColor;

4.3.0中將GL_OES_EGL_image_external變?yōu)榱薌L_OES_EGL_image_external_essl3
在使用紋理擴(kuò)展的時(shí)候,也就是uniform samplerExternalOES sTexture的時(shí)候疾渴。在3.0中我們使用GL_OES_EGL_image_external_essl3而不是GL_OES_EGL_image_external千贯。使用相機(jī)采集紋理的時(shí)候就知道了

5.3.0中將紋理的處理方法統(tǒng)一為texture
在2.0中2D紋理和3D紋理處理分別使用texture2D和texture3D方法,而在3.0后使用texture統(tǒng)一處理搞坝。

6.in或者out變量等不能在函數(shù)內(nèi)(如main函數(shù)內(nèi))聲明

OpenglES3.0新特性

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末搔谴,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子桩撮,更是在濱河造成了極大的恐慌敦第,老刑警劉巖慌核,帶你破解...
    沈念sama閱讀 206,839評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異申尼,居然都是意外死亡垮卓,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門师幕,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)粟按,“玉大人,你說(shuō)我怎么就攤上這事霹粥∶鸾” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,116評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵后控,是天一觀的道長(zhǎng)庙曙。 經(jīng)常有香客問(wèn)我,道長(zhǎng)浩淘,這世上最難降的妖魔是什么捌朴? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,371評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮张抄,結(jié)果婚禮上砂蔽,老公的妹妹穿的比我還像新娘。我一直安慰自己署惯,他們只是感情好左驾,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,384評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著极谊,像睡著了一般诡右。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上轻猖,一...
    開(kāi)封第一講書(shū)人閱讀 49,111評(píng)論 1 285
  • 那天帆吻,我揣著相機(jī)與錄音,去河邊找鬼蜕依。 笑死桅锄,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的样眠。 我是一名探鬼主播友瘤,決...
    沈念sama閱讀 38,416評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼檐束!你這毒婦竟也來(lái)了辫秧?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,053評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤被丧,失蹤者是張志新(化名)和其女友劉穎盟戏,沒(méi)想到半個(gè)月后绪妹,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,558評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡柿究,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,007評(píng)論 2 325
  • 正文 我和宋清朗相戀三年邮旷,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蝇摸。...
    茶點(diǎn)故事閱讀 38,117評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡婶肩,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出貌夕,到底是詐尸還是另有隱情律歼,我是刑警寧澤,帶...
    沈念sama閱讀 33,756評(píng)論 4 324
  • 正文 年R本政府宣布啡专,位于F島的核電站险毁,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏们童。R本人自食惡果不足惜畔况,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,324評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望病附。 院中可真熱鬧问窃,春花似錦、人聲如沸完沪。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,315評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)覆积。三九已至,卻和暖如春熟呛,著一層夾襖步出監(jiān)牢的瞬間宽档,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,539評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工庵朝, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留吗冤,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,578評(píng)論 2 355
  • 正文 我出身青樓九府,卻偏偏與公主長(zhǎng)得像椎瘟,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子侄旬,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,877評(píng)論 2 345

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

  • 本文首發(fā)于個(gè)人博客:Lam's Blog - 【OpenGL ES】入門及繪制一個(gè)三角形肺蔚,文章由MarkDown語(yǔ)...
    格子林ll閱讀 7,248評(píng)論 2 18
  • 本文首發(fā)于個(gè)人博客:Lam's Blog - 【OpenGL-ES】二維紋理,文章由MarkDown語(yǔ)法編寫儡羔,可能...
    格子林ll閱讀 3,744評(píng)論 0 9
  • 一宣羊、紋理基礎(chǔ) 3D圖形渲染中最基本的操作就是對(duì)一個(gè)表面應(yīng)用紋理璧诵。紋理可以表現(xiàn)只從網(wǎng)格的幾何形狀無(wú)法得到的附加細(xì)節(jié)。...
    cain_huang閱讀 8,683評(píng)論 0 7
  • 本文主要介紹仇冯,如何使用 OpenGL ES 來(lái)渲染一張圖片之宿。內(nèi)容包括:基礎(chǔ)概念的講解,如何使用 GLKit 來(lái)渲染...
    雷曼同學(xué)閱讀 4,815評(píng)論 11 18
  • 早就聽(tīng)過(guò)大名鼎鼎的 OpenGL苛坚,卻遲遲沒(méi)有實(shí)踐學(xué)習(xí)澈缺,有些慚愧。今天開(kāi)始通過(guò)實(shí)踐+博文方式學(xué)習(xí)掌握 OpenGL炕婶。...
    王英豪閱讀 22,480評(píng)論 1 33