OpenGL ES 多目标渲染(MRT)

OpenGL ES 多目标渲染

OpenGL ES 多目标渲染(MRT),即多重渲染目标,是 OpenGL ES 3.0 新特性,它容许应用程序一次渲染到多个缓冲区。web


利用 MRT 技术,片断着色器能够输出多个颜色,能够用于保存 RGBA 颜色、 法线、 深度信息或者纹理坐标,每一个颜色链接一个颜色缓冲区算法


就目前接触的 MRT 技术,在图形图像算法中比较经常使用,主要用于获取算法中间结果、底图或者 Mask ,也用于多种高级渲染算法中,例如延迟着色和快速环境遮蔽估算。微信


使用 MRT 技术,通常须要为帧缓冲区对象(FBO)的设置多个颜色附着。FBO(Frame Buffer Object)即帧缓冲区对象,其实是一个可添加缓冲区的容器,能够为其添加纹理或渲染缓冲区对象(RBO)。app


FBO 帧缓冲区对象

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.00.01.0);
    outColor2 = vec4(0.0, outputColor.g, 0.01.0);
    outColor3 = vec4(0.00.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 ( 00, 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 ( 00, 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


OpenGL ES 多目标渲染

-- END --


进技术交流群,扫码添加个人微信:Byte-Flo



获取视频教程和源码



推荐:

字节流动 OpenGL ES 技术交流群来啦

FFmpeg + OpenGL ES 实现 3D 全景播放器

FFmpeg + OpenGLES 实现视频解码播放和视频滤镜

一文掌握 YUV 图像的基本处理

Android OpenGL ES 从入门到精通系统性学习教程

OpenGL ES 实现动态(水波纹)涟漪效果


以为不错,点个在看呗~

本文分享自微信公众号 - 字节流动(google_developer)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。

相关文章
相关标签/搜索