OpenGL ES MRT多目標渲染

OpenGL ES3.0 多目標渲染(MRT:Multiple Render Target)容許應(yīng)用程序一次渲染到多個緩沖區(qū)肠缔。利用 MRT 技術(shù),片斷著色器能夠輸出多個顏色。

MRT需要與FBO結(jié)合使用泽艘。FBO是一個容器猖毫,自身不能用于渲染台谍,但它提供了 3 個附著(Attachment),分別是顏色附著吁断、深度附著和模板附著趁蕊。使用MRT,需要為FBO設(shè)置多個顏色附著仔役,即多個顏色附著(color attachment)對應(yīng)綁定多個texture掷伙。

image.png

需要注意的是,著色器要指定使用OpenGL ES 3.0版本又兵,且FBO紋理坐標系與紋理坐標系不一樣任柜。
image.png

一、MRT渲染

mrt 頂點著色器代碼

#version 300 es
in vec4 vPosition; // 頂點坐標
in vec2 vTextureCoord;  //紋理坐標
// mvp矩陣
uniform mat4 vMatrix;
void main(){
    gl_Position =vMatrix * vPosition;
    aCoord = vTextureCoord;
}

mrt 片元著色器代碼

#version 300 es
precision mediump float;// 數(shù)據(jù)精度
in vec2 aCoord;
layout(location = 0) out vec4 outColor0;
layout(location = 1) out vec4 outColor1;
layout(location = 2) out vec4 outColor2;
layout(location = 3) out vec4 outColor3;

uniform sampler2D  vTexture;// samplerExternalOES: 圖片沛厨, 采樣器
// MRT多目標渲染

void main(){
    vec4 rgba = texture(vTexture, aCoord);//rgba
    outColor0 = rgba;
    outColor1 = vec4(rgba.r, 0.0, 0.0, 1.0);
    outColor2 = vec4(0.0, rgba.g, 0.0, 1.0);
    outColor3 = vec4(0.0, 0.0, rgba.b, 1.0);
}

可以看出與一般的片元著色器顏色輸出不同之處在于宙地,這里的顏色輸出是4個:outColor0、outColor1逆皮、outColor2宅粥、outColor3。

創(chuàng)建FBO电谣,綁定color attachment

    private fun createFBO(){
        GLES30.glGenTextures(mAttachTextIds.size,mAttachTextIds,0)
        // 創(chuàng)建一個frame buffer用于綁定多個渲染目標
        frameBuffers = IntArray(1)
        GLES30.glGenFramebuffers(frameBuffers.size, frameBuffers, 0)
        frameBufferMTR = frameBuffers[0]
        GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, frameBufferMTR)
        // 將4個渲染目標綁定到frame buffer上的4個attachment(附著)上
        for (i in mAttachTextIds.indices) {
            Log.e(TAG, "createFBO: i=$i textId=${mAttachTextIds[i]}")
            GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, mAttachTextIds[i])
            GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MIN_FILTER, GLES30.GL_LINEAR)
            GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MAG_FILTER, GLES30.GL_LINEAR)
            GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_WRAP_S, GLES30.GL_CLAMP_TO_EDGE)
            GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_WRAP_T, GLES30.GL_CLAMP_TO_EDGE)
            GLES30.glTexImage2D(GLES30.GL_TEXTURE_2D, 0, GLES30.GL_RGBA, mWidth, mHeight, 0, GLES30.GL_RGBA, GLES30.GL_UNSIGNED_BYTE, null)
            GLES30.glFramebufferTexture2D(GLES30.GL_FRAMEBUFFER, GLES30.GL_COLOR_ATTACHMENT0 + i, GLES30.GL_TEXTURE_2D, mAttachTextIds[i], 0)
            // 檢測fbo綁定是否成功
            if (GLES30.glCheckFramebufferStatus(GLES30.GL_FRAMEBUFFER) != GLES30.GL_FRAMEBUFFER_COMPLETE) {
                throw RuntimeException("FBO附著異常")
            }
            GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, 0)
        }

        val attachments = intArrayOf(GLES30.GL_COLOR_ATTACHMENT0, GLES30.GL_COLOR_ATTACHMENT1, GLES30.GL_COLOR_ATTACHMENT2,GLES30.GL_COLOR_ATTACHMENT3)
        val attachmentBuffer = IntBuffer.allocate(attachments.size)
        attachmentBuffer.put(attachments)
        attachmentBuffer.position(0)
        GLES30.glDrawBuffers(attachments.size, attachmentBuffer)
        GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, 0)
    }

glFramebufferTexture2D作用:通過glFramebufferTexture2D()將texture綁定到顏色附著(color attachment)秽梅。
glDrawBuffers作用:OpenGL允許一個應(yīng)用程序通過為每個緩沖區(qū)指定顏色綁定來將著色器輸出映射到不同的FBO緩沖區(qū)。默認的行為是一個單獨的顏色輸出將被發(fā)送到顏色綁定0剿牺。glFramebufferTexture2D()中已經(jīng)分別綁定了要渲染到的color attachment企垦,但不是綁了多少它就對應(yīng)渲染多少,通過調(diào)用glDrawBuffers來對著色器輸出進行路由晒来。

通過MRT渲染后的顏色輸出outColor0钞诡、···,再通過另一個著色器程序顯示出來。

二臭增、渲染到屏幕上

頂點著色器與mrt頂點著色器代碼一樣懂酱。
片元著色器代碼如下:

#version 300 es
precision mediump float;// 數(shù)據(jù)精度
in vec2 aCoord;

uniform sampler2D  vTexture0;// samplerExternalOES: 圖片, 采樣器
uniform sampler2D  vTexture1;// samplerExternalOES: 圖片誊抛, 采樣器
uniform sampler2D  vTexture2;// samplerExternalOES: 圖片列牺, 采樣器
uniform sampler2D  vTexture3;// samplerExternalOES: 圖片, 采樣器
// 多目標渲染
out vec4 gl_FragColor;
void main(){
    if(aCoord.x < 0.5 && aCoord.y < 0.5){
        gl_FragColor = texture(vTexture0, aCoord);
    }else if(aCoord.x > 0.5 && aCoord.y < 0.5){
        gl_FragColor = texture(vTexture1, aCoord);
    }else if(aCoord.x < 0.5 && aCoord.y > 0.5){
        gl_FragColor = texture(vTexture2, aCoord);
    }else{
        gl_FragColor = texture(vTexture3, aCoord);
    }
}

主要渲染代碼如下:

    override fun onDrawFrame(gl: GL10?) {
        //把顏色緩沖區(qū)設(shè)置為我們預(yù)設(shè)的顏色
        GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT or GLES30.GL_DEPTH_BUFFER_BIT)
        GLES30.glEnable(GLES30.GL_DEPTH_TEST)
        //1拗窃、 多目標渲染瞎领,繪制到FBO綁定的顏色附著中
        GLES30.glUseProgram(mMrtProgram)
        //開啟FBO
        GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER,frameBufferMTR)
        GLES30.glUniformMatrix4fv(mHMrtMvpMatrix, 1, false, mMvpMatrix, 0)
        GLES30.glEnableVertexAttribArray(mHMrtPosition)
        GLES30.glVertexAttribPointer(mHMrtPosition, 3, GLES30.GL_FLOAT, false, 0, vertexBuffer)
        GLES30.glEnableVertexAttribArray(mHMrtTextCoordinate)
        GLES30.glVertexAttribPointer(mHMrtTextCoordinate, 2, GLES30.GL_FLOAT, false, 0, textureBuffer)
        // 啟用紋理
        GLES30.glActiveTexture(GLES30.GL_TEXTURE0)
        GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, textureId)
        GLES30.glDrawArrays(GLES30.GL_TRIANGLES, 0, triangleCoords.size / 3)
        GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, 0)
        GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, 0)

        //2、渲染到屏幕上
        GLES30.glUseProgram(mProgram)
        GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER,0)//關(guān)閉FBO
        GLES30.glUniformMatrix4fv(mDispMvpMatrix, 1, false, mMvpMatrix, 0)
        GLES30.glEnableVertexAttribArray(mDispPosition)
        GLES30.glVertexAttribPointer(mDispPosition, 3, GLES30.GL_FLOAT, false, 0, vertexBuffer)
        GLES30.glEnableVertexAttribArray(mDispTextCoordinate)
        GLES30.glVertexAttribPointer(mDispTextCoordinate, 2, GLES30.GL_FLOAT, false, 0, textureDisBuffer)
        // 保證每個uniform采樣器對應(yīng)著正確的紋理單元随夸。
        for (i in 0 until MULTI_TARGET_NUM) {
            GLES30.glActiveTexture(GLES30.GL_TEXTURE0 + i)
            GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, mAttachTextIds[i])
            GLES30.glUniform1i(GLES30.glGetUniformLocation(mProgram, "vTexture$i"), i)
        }
        GLES30.glDrawArrays(GLES30.GL_TRIANGLES, 0, triangleCoords.size / 3)
    }

glUniform1i:通過glUniform1i的設(shè)置九默,保證每個uniform采樣器對應(yīng)著正確的紋理單元。

image.png

代碼:
https://github.com/godtrace12/DOpenglTest
參考:
https://mp.weixin.qq.com/s/R32iePD2JW13TNGlveeRbQ
https://juejin.cn/post/6869202501216763912
http://www.javashuo.com/article/p-nerrduso-nx.html
https://www.cnblogs.com/striver-zhu/p/4561337.html
https://blog.csdn.net/mumuzi_1/article/details/62047112
http://www.reibang.com/p/78a64b8fb315

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末宾毒,一起剝皮案震驚了整個濱河市驼修,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌诈铛,老刑警劉巖乙各,帶你破解...
    沈念sama閱讀 217,406評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異幢竹,居然都是意外死亡耳峦,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評論 3 393
  • 文/潘曉璐 我一進店門焕毫,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蹲坷,“玉大人,你說我怎么就攤上這事邑飒⊙” “怎么了?”我有些...
    開封第一講書人閱讀 163,711評論 0 353
  • 文/不壞的土叔 我叫張陵幸乒,是天一觀的道長懦底。 經(jīng)常有香客問我,道長罕扎,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,380評論 1 293
  • 正文 為了忘掉前任丐重,我火速辦了婚禮腔召,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘扮惦。我一直安慰自己臀蛛,他們只是感情好,可當我...
    茶點故事閱讀 67,432評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著浊仆,像睡著了一般客峭。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上抡柿,一...
    開封第一講書人閱讀 51,301評論 1 301
  • 那天舔琅,我揣著相機與錄音,去河邊找鬼洲劣。 笑死备蚓,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的囱稽。 我是一名探鬼主播郊尝,決...
    沈念sama閱讀 40,145評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼战惊!你這毒婦竟也來了流昏?” 一聲冷哼從身側(cè)響起魏滚,我...
    開封第一講書人閱讀 39,008評論 0 276
  • 序言:老撾萬榮一對情侶失蹤奇适,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后己肮,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體衫哥,經(jīng)...
    沈念sama閱讀 45,443評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡茎刚,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,649評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了撤逢。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片膛锭。...
    茶點故事閱讀 39,795評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖蚊荣,靈堂內(nèi)的尸體忽然破棺而出初狰,到底是詐尸還是另有隱情,我是刑警寧澤互例,帶...
    沈念sama閱讀 35,501評論 5 345
  • 正文 年R本政府宣布奢入,位于F島的核電站,受9級特大地震影響媳叨,放射性物質(zhì)發(fā)生泄漏腥光。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,119評論 3 328
  • 文/蒙蒙 一糊秆、第九天 我趴在偏房一處隱蔽的房頂上張望武福。 院中可真熱鬧,春花似錦痘番、人聲如沸捉片。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽伍纫。三九已至宗雇,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間莹规,已是汗流浹背赔蒲。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留访惜,地道東北人嘹履。 一個月前我還...
    沈念sama閱讀 47,899評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像债热,于是被迫代替她去往敵國和親砾嫉。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,724評論 2 354

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