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掷伙。
需要注意的是,著色器要指定使用OpenGL ES 3.0版本又兵,且FBO紋理坐標系與紋理坐標系不一樣任柜。
一、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)著正確的紋理單元。
代碼:
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