OpenGL ES 多目標渲染(MRT),即多重渲染目標,是 OpenGL ES 3.0 新特性,它容許應用程序一次渲染到多個緩衝區。web
利用 MRT 技術,片斷着色器能夠輸出多個顏色,能夠用於保存 RGBA 顏色、 法線、 深度信息或者紋理座標,每一個顏色鏈接一個顏色緩衝區。算法
就目前接觸的 MRT 技術,在圖形圖像算法中比較經常使用,主要用於獲取算法中間結果、底圖或者 Mask ,也用於多種高級渲染算法中,例如延遲着色和快速環境遮蔽估算。微信
使用 MRT 技術,通常須要爲幀緩衝區對象(FBO)的設置多個顏色附着。FBO(Frame Buffer Object)即幀緩衝區對象,其實是一個可添加緩衝區的容器,能夠爲其添加紋理或渲染緩衝區對象(RBO)。app
FBO 自己不能用於渲染,只有添加了紋理或者渲染緩衝區以後才能做爲渲染目標,它提供了 3 種附着(Attachment),分別是顏色附着、深度附着和模板附着。編輯器
本文爲演示 MRT 技術的使用,爲 FBO 的顏色附着設置 4 個紋理,一個紋理做爲一個顏色附着(顏色緩衝區)。學習
const GLenum attachments[ATTACHMENT_NUM] = {
GL_COLOR_ATTACHMENT0,
GL_COLOR_ATTACHMENT1,
GL_COLOR_ATTACHMENT2,
GL_COLOR_ATTACHMENT3
};
//生成幀緩衝區對象
glGenFramebuffers(1, &m_FBO);
glBindFramebuffer(GL_FRAMEBUFFER, m_FBO);
//生成 4 個紋理
glGenTextures(ATTACHMENT_NUM, m_AttachTexIds);
for (int i = 0; i < ATTACHMENT_NUM; ++i) {
glBindTexture(GL_TEXTURE_2D, m_AttachTexIds[i]);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_RenderImage.width, m_RenderImage.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, attachments[i], GL_TEXTURE_2D, m_AttachTexIds[i], 0);
}
//告訴 OpenGL ,我要渲染到 4 個顏色附着上
glDrawBuffers(ATTACHMENT_NUM, attachments);
if (GL_FRAMEBUFFER_COMPLETE != glCheckFramebufferStatus(GL_FRAMEBUFFER))
{
return false;
}
本文使用 MRT 技術對應的頂點和片斷着色器以下,咱們使用了 4 個紋理做爲顏色附着,其中直接渲染原圖到第一個紋理,分別渲染 RGB 三個通道的圖像到另外三個紋理,而後再利用另一個着色器將 4 個紋理的結果渲染到屏幕上。flex
#version 300 es
layout(location = 0) in vec4 a_position;
layout(location = 1) in vec2 a_texCoord;
out vec2 v_texCoord;
void main()
{
gl_Position = a_position;
v_texCoord = a_texCoord;
}
#version 300 es
precision mediump float;
in vec2 v_texCoord;
//分別對應 4 個綁定的紋理對象,將渲染結果保存到 4 個紋理中
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 s_Texture;
void main()
{
vec4 outputColor = texture(s_Texture, v_texCoord);
outColor0 = outputColor;
outColor1 = vec4(outputColor.r, 0.0, 0.0, 1.0);
outColor2 = vec4(0.0, outputColor.g, 0.0, 1.0);
outColor3 = vec4(0.0, 0.0, outputColor.b, 1.0);
}
用於渲染(採樣) 4 個紋理的片斷着色器,其實是將 4 張圖作一個拼接。google
#version 300 es
precision mediump float;
in vec2 v_texCoord;
layout(location = 0) out vec4 outColor;
uniform sampler2D s_Texture0;
uniform sampler2D s_Texture1;
uniform sampler2D s_Texture2;
uniform sampler2D s_Texture3;
void main()
{
if(v_texCoord.x < 0.5 && v_texCoord.y < 0.5)
{
outColor = texture(s_Texture0, v_texCoord);
}
else if(v_texCoord.x > 0.5 && v_texCoord.y < 0.5)
{
outColor = texture(s_Texture1, v_texCoord);
}
else if(v_texCoord.x < 0.5 && v_texCoord.y > 0.5)
{
outColor = texture(s_Texture2, v_texCoord);
}
else
{
outColor = texture(s_Texture3, v_texCoord);
}
}
首先獲取當前默認幀緩衝區的 id ,而後綁定咱們新建立的 FBO 渲染,渲染完成再綁定默認幀緩衝區對象,使用另一個着色器程序渲染四張紋理圖。spa
//首先獲取當前默認幀緩衝區的 id
GLint defaultFrameBuffer = GL_NONE;
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &defaultFrameBuffer);
//綁定咱們新建立的 FBO 渲染
glBindFramebuffer(GL_FRAMEBUFFER, m_FBO);
glViewport ( 0, 0, m_RenderImage.width, m_RenderImage.height);
glClear(GL_COLOR_BUFFER_BIT);
glDrawBuffers(ATTACHMENT_NUM, attachments);
//使用渲染輸出到 4 個紋理的着色器程序
glUseProgram (m_MRTProgramObj);
glBindVertexArray(m_VaoId);
UpdateMVPMatrix(m_MVPMatrix, 180, m_AngleY, (float)screenW / screenH);
glUniformMatrix4fv(m_MVPMatLoc, 1, GL_FALSE, &m_MVPMatrix[0][0]);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_TextureId);
glUniform1i(m_SamplerLoc, 0);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, (const void *)0);
//綁定默認幀緩衝區對象,繪製到屏幕上
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, defaultFrameBuffer);
glViewport ( 0, 0, m_SurfaceWidth, m_SurfaceHeight);
glClear(GL_COLOR_BUFFER_BIT);
//渲染(採樣) 4 個紋理的着色器程序
glUseProgram (m_ProgramObj);
UpdateMVPMatrix(m_MVPMatrix, 0, m_AngleY, (float)screenW / screenH);
glUniformMatrix4fv(m_MVPMatLoc, 1, GL_FALSE, &m_MVPMatrix[0][0]);
//指定 4 個紋理做爲輸入
for (int i = 0; i < ATTACHMENT_NUM; ++i)
{
glActiveTexture(GL_TEXTURE0 + i);
glBindTexture(GL_TEXTURE_2D, m_AttachTexIds[i]);
char samplerName[64] = {0};
sprintf(samplerName, "s_Texture%d", i);
GLUtils::setInt(m_ProgramObj, samplerName, i);
}
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, (const void *)0);
OpenGL ES 多目標渲染結果。.net
-- END --
進技術交流羣,掃碼添加個人微信:Byte-Flow
獲取視頻教程和源碼
推薦:
FFmpeg + OpenGL ES 實現 3D 全景播放器
FFmpeg + OpenGLES 實現視頻解碼播放和視頻濾鏡
以爲不錯,點個在看唄~
本文分享自微信公衆號 - 字節流動(google_developer)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。