哪種語(yǔ)言做的網(wǎng)站好seo診斷站長(zhǎng)
系列文章目錄
- LearnOpenGL 筆記 - 入門(mén) 01 OpenGL
- LearnOpenGL 筆記 - 入門(mén) 02 創(chuàng)建窗口
- LearnOpenGL 筆記 - 入門(mén) 03 你好,窗口
- LearnOpenGL 筆記 - 入門(mén) 04 你好,三角形
- OpenGL - 如何理解 VAO 與 VBO 之間的關(guān)系
- LearnOpenGL - Android OpenGL ES 3.0 繪制三角形
- LearnOpenGL - Android OpenGL ES 3.0 繪制紋理
- LearnOpenGL - Android OpenGL ES 3.0 YUV 渲染
一、前言
利用 FBO(Framebuffer Object),我們可以實(shí)現(xiàn)離屏渲染。在前面的章節(jié)中,當(dāng)我們調(diào)用 glDrawElements 后,手機(jī)屏幕上就會(huì)顯示出繪制的圖像。這意味著 OpenGL 將數(shù)據(jù)直接渲染到了手機(jī)屏幕上。通過(guò)使用 FBO,我們可以將數(shù)據(jù)渲染到紋理上,而不是直接渲染到屏幕,這個(gè)過(guò)程稱(chēng)為離屏渲染。
通過(guò)離屏渲染,我們可以在最終顯示之前對(duì)圖像進(jìn)行復(fù)雜的處理。這種方法非常有用,比如在后期處理效果(如模糊、HDR、陰影等)中,或者在渲染多個(gè)場(chǎng)景以進(jìn)行紋理貼圖、環(huán)境映射等操作時(shí)。
假設(shè)你在開(kāi)發(fā)一款圖片處理軟件,包含美顏、濾鏡等功能。用戶(hù)可以同時(shí)應(yīng)用多種濾鏡,如瘦臉、美白、長(zhǎng)腿等,每種濾鏡都通過(guò) OpenGL Shader 進(jìn)行處理和渲染。為實(shí)現(xiàn)這種功能,你可以設(shè)計(jì)一個(gè)圖片渲染鏈。
一種直觀的方法是為每種濾鏡創(chuàng)建一個(gè)獨(dú)立的模塊,通過(guò)組合不同的模塊實(shí)現(xiàn)多種濾鏡的處理鏈。在處理鏈完成之前,我們無(wú)法將結(jié)果渲染到屏幕上。模塊與模塊之間的處理結(jié)果應(yīng)該通過(guò)某種介質(zhì)進(jìn)行傳遞,這里使用的介質(zhì)就是紋理。這也解釋了我們?yōu)槭裁葱枰褂?FBO。
通過(guò) FBO,我們可以在離屏狀態(tài)下將渲染結(jié)果存儲(chǔ)到紋理中,然后將該紋理作為輸入傳遞給下一個(gè)濾鏡模塊。這樣,整個(gè)處理鏈就可以逐步處理圖像,直到應(yīng)用所有濾鏡后,將最終結(jié)果渲染到屏幕上。
本文所有代碼在 FBODrawer.kt
二、FBO 簡(jiǎn)介
上圖顯示了幀緩沖區(qū)對(duì)象的結(jié)構(gòu),它提供了顏色緩沖區(qū)和深度緩沖區(qū)的替代品。如你所見(jiàn),繪制操作并不是直接發(fā)生在幀緩沖區(qū)中的,而是發(fā)生在幀緩沖區(qū)所關(guān)聯(lián)的對(duì)象(attachment)上。一個(gè)幀緩沖區(qū)有多個(gè)關(guān)聯(lián)對(duì)象:顏色關(guān)聯(lián)對(duì)象(color attachment)、深度關(guān)聯(lián)對(duì)象(depth attachment)和模板關(guān)聯(lián)對(duì)象(stencil attachment),分別用來(lái)替代顏色緩沖區(qū)、深度緩沖區(qū)和模板緩沖區(qū)。經(jīng)過(guò)一些設(shè)置,OpenGL 就可以向幀緩沖區(qū)的關(guān)聯(lián)對(duì)象中寫(xiě)入數(shù)據(jù),就像寫(xiě)入顏色緩沖區(qū)或深度緩沖區(qū)一樣。我們目前只關(guān)注顏色關(guān)聯(lián)對(duì)象即可
每個(gè)關(guān)聯(lián)對(duì)象又可以是兩種類(lèi)型的:紋理對(duì)象或渲染緩沖區(qū)對(duì)象(renderbuffer object)。當(dāng)我們把紋理對(duì)象作為顏色關(guān)聯(lián)對(duì)象關(guān)聯(lián)到幀緩沖區(qū)對(duì)象后,OpenGL 就可以在紋理對(duì)象中繪圖。渲染緩沖區(qū)對(duì)象表示一種更加通用的繪圖區(qū)域,可以向其中寫(xiě)入多種類(lèi)型的數(shù)據(jù)。
2.1 渲染緩沖對(duì)象
渲染緩沖區(qū)對(duì)象(Renderbuffer Object)是 OpenGL 和 OpenGL ES 中的一種緩沖區(qū)類(lèi)型,用于離屏渲染。它提供了一種高效的方式來(lái)存儲(chǔ)圖像數(shù)據(jù),特別適用于深度緩沖區(qū)和模板緩沖區(qū)。
渲染緩沖區(qū)對(duì)象的特點(diǎn):
-
高效存儲(chǔ):
- 渲染緩沖區(qū)對(duì)象在實(shí)現(xiàn)上通常比紋理對(duì)象更高效,特別是用于深度和模板數(shù)據(jù)的存儲(chǔ)。
- 它不需要紋理過(guò)濾、MIP 貼圖等特性,因此在某些場(chǎng)景下可以提供更好的性能。
-
不可直接采樣:
- 與紋理對(duì)象不同,渲染緩沖區(qū)對(duì)象不能直接被著色器采樣。
- 這意味著你不能在著色器中直接訪問(wèn)渲染緩沖區(qū)對(duì)象中的數(shù)據(jù),只能用于渲染過(guò)程。
-
用途廣泛:
- 渲染緩沖區(qū)對(duì)象可以用作顏色、深度或模板緩沖區(qū)。
- 在使用 FBO 進(jìn)行離屏渲染時(shí),渲染緩沖區(qū)對(duì)象可以作為這些附件類(lèi)型附加到 FBO 上。
渲染緩沖區(qū)對(duì)象的使用步驟:
-
創(chuàng)建渲染緩沖區(qū)對(duì)象:
GLuint rbo; glGenRenderbuffers(1, &rbo); glBindRenderbuffer(GL_RENDERBUFFER, rbo);
-
分配存儲(chǔ):
- 根據(jù)用途分配存儲(chǔ),比如深度緩沖區(qū)、顏色緩沖區(qū)等。
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width, height); // 或者為顏色緩沖區(qū)分配存儲(chǔ) // glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, width, height);
-
附加到 FBO:
- 將渲染緩沖區(qū)對(duì)象附加到 FBO 作為附件。
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rbo); // 如果是顏色緩沖區(qū) // glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo);
紋理對(duì)象與渲染緩沖區(qū)對(duì)象的對(duì)比:
-
紋理對(duì)象:
- 可以在著色器中采樣,用于更靈活的圖像處理。
- 適用于需要在多個(gè)渲染步驟中反復(fù)使用和處理的圖像數(shù)據(jù)。
-
渲染緩沖區(qū)對(duì)象:
- 高效的存儲(chǔ)和寫(xiě)入,但不能在著色器中采樣。
- 適用于深度緩沖區(qū)和模板緩沖區(qū),或者不需要在著色器中采樣的顏色緩沖區(qū)。
結(jié)合使用:
在實(shí)際應(yīng)用中,常常將紋理對(duì)象和渲染緩沖區(qū)對(duì)象結(jié)合使用。比如:
- 使用渲染緩沖區(qū)對(duì)象存儲(chǔ)深度和模板數(shù)據(jù),以獲得更高的性能。
- 使用紋理對(duì)象存儲(chǔ)顏色數(shù)據(jù),以便在后續(xù)渲染步驟中進(jìn)行采樣和處理。
例子:
假設(shè)我們?cè)陂_(kāi)發(fā)一個(gè)圖片處理軟件,通過(guò) FBO 進(jìn)行多重濾鏡處理。每個(gè)濾鏡模塊會(huì)產(chǎn)生一個(gè)中間結(jié)果,這些中間結(jié)果通常存儲(chǔ)在紋理對(duì)象中,因?yàn)樗鼈冃枰缓罄m(xù)的濾鏡模塊采樣和處理。然而,為了提高性能,我們可以使用渲染緩沖區(qū)對(duì)象來(lái)存儲(chǔ)深度數(shù)據(jù),因?yàn)檫@些數(shù)據(jù)通常不需要在濾鏡處理中直接訪問(wèn)。
// 創(chuàng)建并綁定 FBO
GLuint fbo;
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);// 創(chuàng)建并附加顏色附件(紋理對(duì)象)
GLuint colorTex;
glGenTextures(1, &colorTex);
glBindTexture(GL_TEXTURE_2D, colorTex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTex, 0);// 創(chuàng)建并附加深度附件(渲染緩沖區(qū)對(duì)象)
GLuint depthRbo;
glGenRenderbuffers(1, &depthRbo);
glBindRenderbuffer(GL_RENDERBUFFER, depthRbo);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width, height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthRbo);// 檢查 FBO 完整性
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {// 處理錯(cuò)誤
}// 解綁 FBO 以恢復(fù)默認(rèn)幀緩沖區(qū)
glBindFramebuffer(GL_FRAMEBUFFER, 0);
通過(guò)這種方式,我們可以高效地實(shí)現(xiàn)圖像的離屏渲染和多重濾鏡處理。
三、FBO 使用流程
GLES30.glGenTextures(1, fboTexIds)
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, fboTexIds[0])
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.glBindTexture(GLES30.GL_TEXTURE_2D, GLES30.GL_NONE)// generate fbo id and config fbo
// 創(chuàng)建 FBO
GLES30.glGenFramebuffers(1, fbo);
GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, fbo[0])
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, fboTexIds[0])
GLES30.glFramebufferTexture2D(GLES30.GL_FRAMEBUFFER, GLES30.GL_COLOR_ATTACHMENT0, GLES30.GL_TEXTURE_2D, fboTexIds[0], 0)
GLES30.glTexImage2D(GLES30.GL_TEXTURE_2D, 0, GLES30.GL_RGBA, imageWidth, imageHeight, 0, GLES30.GL_RGBA, GLES30.GL_UNSIGNED_BYTE, null)
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, GLES30.GL_NONE)
GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, GLES30.GL_NONE)
這段代碼用于在 OpenGL ES 3.0 中創(chuàng)建并配置一個(gè)幀緩沖區(qū)對(duì)象(FBO),并將一個(gè)紋理對(duì)象附加到這個(gè)幀緩沖區(qū)對(duì)象上作為顏色附件,以便進(jìn)行離屏渲染。下面是對(duì)每行代碼的詳細(xì)解釋:
創(chuàng)建和配置紋理對(duì)象
// 生成一個(gè)紋理對(duì)象,并將其ID存儲(chǔ)在 fboTexIds 數(shù)組中
GLES30.glGenTextures(1, fboTexIds);// 綁定生成的紋理對(duì)象
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, fboTexIds[0]);// 設(shè)置紋理過(guò)濾參數(shù),線性過(guò)濾
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.glBindTexture(GLES30.GL_TEXTURE_2D, GLES30.GL_NONE);
-
生成紋理對(duì)象:
GLES30.glGenTextures(1, fboTexIds);
:生成一個(gè)紋理對(duì)象,并將其ID存儲(chǔ)在fboTexIds
數(shù)組中。
-
綁定紋理對(duì)象:
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, fboTexIds[0]);
:將生成的紋理對(duì)象綁定到目標(biāo)GL_TEXTURE_2D
。
-
設(shè)置紋理參數(shù):
GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MIN_FILTER, GLES30.GL_LINEAR);
:設(shè)置紋理的縮小過(guò)濾為線性過(guò)濾。GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MAG_FILTER, GLES30.GL_LINEAR);
:設(shè)置紋理的放大過(guò)濾為線性過(guò)濾。
-
解除紋理綁定:
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, GLES30.GL_NONE);
:解除當(dāng)前綁定的紋理對(duì)象。
創(chuàng)建和配置幀緩沖區(qū)對(duì)象
// 生成一個(gè)幀緩沖區(qū)對(duì)象,并將其ID存儲(chǔ)在 fbo 數(shù)組中
GLES30.glGenFramebuffers(1, fbo);// 綁定生成的幀緩沖區(qū)對(duì)象
GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, fbo[0]);// 重新綁定之前創(chuàng)建的紋理對(duì)象
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, fboTexIds[0]);// 將紋理對(duì)象附加到幀緩沖區(qū)對(duì)象的顏色附件上
GLES30.glFramebufferTexture2D(GLES30.GL_FRAMEBUFFER, GLES30.GL_COLOR_ATTACHMENT0, GLES30.GL_TEXTURE_2D, fboTexIds[0], 0);// 為紋理對(duì)象分配存儲(chǔ)空間
GLES30.glTexImage2D(GLES30.GL_TEXTURE_2D, 0, GLES30.GL_RGBA, imageWidth, imageHeight, 0, GLES30.GL_RGBA, GLES30.GL_UNSIGNED_BYTE, null);// 解除紋理綁定
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, GLES30.GL_NONE);// 解除幀緩沖區(qū)對(duì)象的綁定
GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, GLES30.GL_NONE);
-
生成幀緩沖區(qū)對(duì)象:
GLES30.glGenFramebuffers(1, fbo);
:生成一個(gè)幀緩沖區(qū)對(duì)象,并將其ID存儲(chǔ)在fbo
數(shù)組中。
-
綁定幀緩沖區(qū)對(duì)象:
GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, fbo[0]);
:將生成的幀緩沖區(qū)對(duì)象綁定到目標(biāo)GL_FRAMEBUFFER
。
-
重新綁定紋理對(duì)象:
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, fboTexIds[0]);
:將之前創(chuàng)建的紋理對(duì)象重新綁定到目標(biāo)GL_TEXTURE_2D
。
-
附加紋理對(duì)象到幀緩沖區(qū)對(duì)象:
GLES30.glFramebufferTexture2D(GLES30.GL_FRAMEBUFFER, GLES30.GL_COLOR_ATTACHMENT0, GLES30.GL_TEXTURE_2D, fboTexIds[0], 0);
:將紋理對(duì)象作為顏色附件附加到幀緩沖區(qū)對(duì)象上。
-
為紋理對(duì)象分配存儲(chǔ)空間:
GLES30.glTexImage2D(GLES30.GL_TEXTURE_2D, 0, GLES30.GL_RGBA, imageWidth, imageHeight, 0, GLES30.GL_RGBA, GLES30.GL_UNSIGNED_BYTE, null);
:為紋理對(duì)象分配存儲(chǔ)空間,并指定其格式和尺寸。
-
解除紋理綁定:
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, GLES30.GL_NONE);
:解除當(dāng)前綁定的紋理對(duì)象。
-
解除幀緩沖區(qū)對(duì)象的綁定:
GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, GLES30.GL_NONE);
:解除當(dāng)前綁定的幀緩沖區(qū)對(duì)象。
四、FBO 離屏渲染
為了演示 FBO 離屏渲染,我在 FBODrawer.kt 構(gòu)建了兩個(gè) shader,第一個(gè) shader 將 RGB 圖片轉(zhuǎn)換為灰度圖,第二個(gè) shader 則將紋理渲染到屏幕上。
companion object {val vertexShaderSource ="""#version 300 eslayout(location = 0) in vec3 a_positlayout(location = 1) in vec2 a_texcoout vec2 v_texcoord;void main(){gl_Position = vec4(a_position, 1v_texcoord = a_texcoord;}""".trimIndent()val fragmentShaderSource ="""#version 300 esprecision mediump float;uniform sampler2D texture0;in vec2 v_texcoord;out vec4 fragColor;void main(void){fragColor = texture(texture0, v_}""".trimIndent()val fboFragmentShaderSource ="""#version 300 esprecision mediump float;uniform sampler2D texture0;in vec2 v_texcoord;out vec4 fragColor;void main(void)void main(void){vec4 tempColor = texture(texture0, v_texcoord);float gray = 0.299*tempColor.a + 0.587*tempColor.g + 0.114*tempColor.b;fragColor = vec4(vec3(gray), 1.0);}""".trimIndent()
}
private val shader = Shader(vertexShaderSource,fragmentShaderSource
)
private val fboShader = Shader(vertexShaderSource,fboFragmentShaderSource
)
因此我們需要調(diào)用兩次 draw 方法:
- 第一次,我們的 shader 輸入是 rgb 圖片的紋理,輸出是灰度圖紋理
- 第二次,我們的 shader 輸入是灰度圖紋理,然后直接繪制到紋理上
override fun draw() {// first, fbo off screen renderingGLES30.glViewport(0, 0, imageWidth, imageHeight)GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, fbo[0])fboShader.use()fboShader.setInt("texture0", 0)GLES30.glBindVertexArray(vaos[0])GLES30.glActiveTexture(GLES30.GL_TEXTURE0)GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, imageTexIds[0])GLES30.glDrawElements(GLES30.GL_TRIANGLES, indices.size, GLES30.GL_UNSIGNED_INT, 0)GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, 0)GLES30.glBindVertexArray(0)GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, 0)// second, draw texture to screenGLES30.glViewport(0, 0, screenWidth, screenHeight)shader.use()shader.setInt("texture0", 0)GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT)GLES30.glBindVertexArray(vaos[0])GLES30.glActiveTexture(GLES30.GL_TEXTURE0)GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, fboTexIds[0]) // 用 fbo 渲染的結(jié)果作為紋理的輸入GLES30.glDrawElements(GLES30.GL_TRIANGLES, indices.size, GLES30.GL_UNSIGNED_INT, 0)GLES30.glBindVertexArray(0)
}
這段代碼展示了如何使用幀緩沖區(qū)對(duì)象(FBO)進(jìn)行離屏渲染,然后將離屏渲染的結(jié)果繪制到屏幕上。具體分為兩個(gè)步驟:第一步是將場(chǎng)景渲染到 FBO,第二步是將 FBO 的內(nèi)容作為紋理繪制到屏幕上。
第一步:離屏渲染到 FBO
// 設(shè)置視口為 FBO 的尺寸
GLES30.glViewport(0, 0, imageWidth, imageHeight);// 綁定 FBO
GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, fbo[0]);// 使用離屏渲染的著色器程序
fboShader.use();// 設(shè)置著色器程序中紋理單元的位置
fboShader.setInt("texture0", 0);// 綁定 VAO
GLES30.glBindVertexArray(vaos[0]);// 激活紋理單元并綁定需要渲染的紋理
GLES30.glActiveTexture(GLES30.GL_TEXTURE0);
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, imageTexIds[0]);// 繪制元素
GLES30.glDrawElements(GLES30.GL_TRIANGLES, indices.size, GLES30.GL_UNSIGNED_INT, 0);// 解除紋理綁定
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, 0);// 解除 VAO 綁定
GLES30.glBindVertexArray(0);// 解除 FBO 綁定,恢復(fù)默認(rèn)幀緩沖區(qū)
GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, 0);
- 設(shè)置視口:
GLES30.glViewport(0, 0, imageWidth, imageHeight)
設(shè)置渲染區(qū)域?yàn)?FBO 的尺寸。 - 綁定 FBO:
GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, fbo[0])
綁定幀緩沖區(qū)對(duì)象。 - 使用著色器程序:
fboShader.use()
使用用于離屏渲染的著色器程序。 - 設(shè)置紋理單元:
fboShader.setInt("texture0", 0)
設(shè)置著色器程序中的紋理單元。 - 綁定 VAO:
GLES30.glBindVertexArray(vaos[0])
綁定頂點(diǎn)數(shù)組對(duì)象(VAO)。 - 激活并綁定紋理:
GLES30.glActiveTexture(GLES30.GL_TEXTURE0)
和GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, imageTexIds[0])
激活并綁定需要渲染的紋理。 - 繪制元素:
GLES30.glDrawElements(GLES30.GL_TRIANGLES, indices.size, GLES30.GL_UNSIGNED_INT, 0)
使用索引數(shù)組繪制三角形。 - 解除綁定:解除紋理和 VAO 的綁定,以及 FBO 的綁定,恢復(fù)默認(rèn)幀緩沖區(qū)。
第二步:將 FBO 的內(nèi)容繪制到屏幕上
// 設(shè)置視口為屏幕尺寸
GLES30.glViewport(0, 0, screenWidth, screenHeight);// 使用屏幕渲染的著色器程序
shader.use();// 設(shè)置著色器程序中紋理單元的位置
shader.setInt("texture0", 0);// 清除顏色緩沖區(qū)
GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT);// 綁定 VAO
GLES30.glBindVertexArray(vaos[0]);// 激活紋理單元并綁定 FBO 的紋理
GLES30.glActiveTexture(GLES30.GL_TEXTURE0);
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, fboTexIds[0]);// 繪制元素
GLES30.glDrawElements(GLES30.GL_TRIANGLES, indices.size, GLES30.GL_UNSIGNED_INT, 0);// 解除 VAO 綁定
GLES30.glBindVertexArray(0);
- 設(shè)置視口:
GLES30.glViewport(0, 0, screenWidth, screenHeight)
設(shè)置渲染區(qū)域?yàn)槠聊坏某叽纭?/li> - 使用著色器程序:
shader.use()
使用用于屏幕渲染的著色器程序。 - 設(shè)置紋理單元:
shader.setInt("texture0", 0)
設(shè)置著色器程序中的紋理單元。 - 清除顏色緩沖區(qū):
GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT)
清除顏色緩沖區(qū)。 - 綁定 VAO:
GLES30.glBindVertexArray(vaos[0])
綁定頂點(diǎn)數(shù)組對(duì)象(VAO)。 - 激活并綁定紋理:
GLES30.glActiveTexture(GLES30.GL_TEXTURE0)
和GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, fboTexIds[0])
激活并綁定 FBO 的紋理(即離屏渲染的結(jié)果)。 - 繪制元素:
GLES30.glDrawElements(GLES30.GL_TRIANGLES, indices.size, GLES30.GL_UNSIGNED_INT, 0)
使用索引數(shù)組繪制三角形。 - 解除綁定:解除 VAO 的綁定。
總結(jié)
- 第一步:在 FBO 中進(jìn)行離屏渲染,將結(jié)果存儲(chǔ)在一個(gè)紋理對(duì)象中。
- 第二步:將 FBO 中的紋理對(duì)象作為輸入,繪制到屏幕上。
這種方法在圖形應(yīng)用程序中非常常見(jiàn),特別是在實(shí)現(xiàn)多重渲染效果(如后期處理、反射、陰影映射等)時(shí)。
參考
- FBODrawer.kt
- NDK OpenGLES3.0 開(kāi)發(fā)(五):FBO 離屏渲染