Adreno OpenGL ES 3.0 介绍(7)
3.3.2渲染为2D阵列纹理–demo
在以下目录中找到此演示:<SDK_install_dir> \ Development \ Tutorials \ OpenGLES \ 25_FramebufferTextureLayerOGLES30。
此应用程序演示了一些实际使用的OpenGL ES 3.0功能,包括:
- 渲染为2D阵列纹理
- 将2D阵列纹理的图层拖到默认帧缓冲区的不同区域
该演示使用屏幕外的帧缓冲区将大量帧渲染到2D阵列纹理的连续层。 每帧都显示一个金字塔,旋转到略微不同的角度。 渲染完成后,这些层将使用帧缓冲区混合机制来合成后缓冲区内容。 最后,将后缓冲区与前缓冲区交换,以将呈现的帧呈现给用户。
为了更好地了解应用程序的工作方式,请查看以下方面:
- 配置屏幕外帧缓冲区
- 进行屏幕外渲染
- 合成最终渲染结果
跳过了与之前的演示演练中已介绍的部分相似的代码部分的讨论。
3.3.2.1配置屏幕外帧缓冲区
屏幕外帧缓冲区是在CreateFBO中构造的。
glGenTextures( 1, &g_hTextureHandle ); glBindTexture(
GL_TEXTURE_2D_ARRAY, g_hTextureHandle );
glTexParameteri( GL_TEXTURE_2D_ARRAY,
GL_TEXTURE_MAG_FILTER,
GL_LINEAR );
glTexParameteri( GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER,
GL_LINEAR ); glTexImage3D( GL_TEXTURE_2D_ARRAY, 0,
nInternalFormat, nWidth,
nHeight, g_nLayers, 0,
nFormat, nType, NULL );
上面的代码初始化了2D数组纹理。 这是9层,因为它是常数g_nLayers的值。
glGenRenderbuffers( 1, &(*ppFBO)->m_hRenderBuffer );
glBindRenderbuffer( GL_RENDERBUFFER, (*ppFBO)->m_hRenderBuffer );
glRenderbufferStorage( GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, nWidth,
nHeight );
在这里,它将创建一个单独的渲染缓冲区,以24位精度保存深度数据。
glFramebufferTextureLayer( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
g_hTextureHandle, 0, 0);
glFramebufferRenderbuffer( GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
GL_RENDERBUFFER, (*ppFBO)->m_hRenderBuffer );
现在,帧缓冲区配置了以下附件:
- 2D阵列纹理的零层附加到颜色附加点零
- Renderbuffer绑定到深度附着点
3.3.2.2屏幕外渲染
屏幕外渲染过程由render函数的第一部分完成:
for(int i=0; i<g_nLayers; i++) {
BeginFBO( g_pOffscreenFBO, i );
glClearColor( 0.0f, 0.5f, 0.0f, 1.0f );
RenderScene( fTime+i*0.1f );
EndFBO( g_pOffscreenFBO );
}
该块在所有2D阵列纹理层上循环。 对于每一层,BeginFBO用于配置帧缓冲区对象,其操作如下:
glBindFramebuffer( GL_FRAMEBUFFER, pFBO->m_hFrameBuffer );
glFramebufferTextureLayer( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
g_hTextureHandle, 0, layer);
glViewport( 0, 0, pFBO->m_nWidth, pFBO->m_nHeight );
将当前图层作为颜色附件零进行附加。 另外,请确保视口分辨率与纹理分辨率保持同步。 如果不这样做,则金字塔将不适合渲染目标,或者将仅绘制渲染目标的一部分。
完成此操作后,render会调用RenderScene,后者负责发送渲染金字塔所需的命令。
glBindFramebuffer( GL_FRAMEBUFFER, 0 );
glViewport( 0, 0, g_nWindowWidth, g_nWindowHeight );
最后,在EndFBO中,绑定回默认的帧缓冲区,并将视口分辨率重置为窗口的尺寸。
渲染循环完成执行后,所有2D阵列纹理层均填充有旋转到不同角度的金字塔。 在这一点上,这些金字塔都还没有进入后台缓冲区。
3.3.2.3合成最终图像
合成过程由渲染功能的其余部分实现。
FLOAT offsets[9][4] =
{
{ 0.0f,
0.0f, 1.0f/3.0f, 1.0f/3.0f },
{ 1.0f/3.0f, 0.0f, 2.0f/3.0f, 1.0f/3.0f },
{ 2.0f/3.0f, 0.0f, 1.0f,
{ 0.0f,
1.0f/3.0f },
1.0f/3.0f, 1.0f/3.0f, 2.0f/3.0f },
{ 1.0f/3.0f, 1.0f/3.0f, 2.0f/3.0f, 2.0f/3.0f },
{ 2.0f/3.0f, 1.0f/3.0f, 1.0f,
{ 0.0f,
2.0f/3.0f },
2.0f/3.0f, 1.0f/3.0f, 1.0f },
{ 1.0f/3.0f, 2.0f/3.0f, 2.0f/3.0f, 1.0f },
{ 2.0f/3.0f, 2.0f/3.0f, 1.0f,
1.0f },
};
这从定义阵列图像放置区域的数组开始。 定义了九个矩形。 每个矩形给出的四个值如下:
- 左上角的X坐标
- 左上角的Y坐标
- 右下角的X坐标
- 右下角的Y坐标
glBindFramebuffer( GL_DRAW_FRAMEBUFFER, 0 );
glBindFramebuffer( GL_READ_FRAMEBUFFER,
g_pOffscreenFBO->m_hFrameBuffer );
在进入进行合成的循环之前,请准备帧缓冲区绑定:
- 将默认帧缓冲区作为所有渲染操作的目标,以将金字塔图像映射到后缓冲区。
- 屏幕外的帧缓冲区被设置为读取操作的源; 这告诉glBlitFramebuffer应该从哪里获取源数据。
for(int i=0; i<g_nLayers; i++)
{
glFramebufferTextureLayer( GL_READ_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0, g_hTextureHandle, 0, i);
0, 0, g_pOffscreenFBO->m_nWidth,
>m_nHeight,
glBlitFramebuffer(
g_pOffscreenFBO-
INT32(g_nWindowWidth*offsets[i][0]),
INT32(g_nWindowHeight*offsets[i][1]),
INT32(g_nWindowWidth*offsets[i][2]),
INT32(g_nWindowHeight*offsets[i][3]),
GL_COLOR_BUFFER_BIT, GL_LINEAR );
}
对于2D阵列纹理的每一层,必须完成两件事以将图像数据复制到后台缓冲区:
- 将该层配置为读取帧缓冲区的颜色附件零; 这将是blit行动的源头
- 使用glBlitFramebuffer将一幅金字塔图像从读取帧缓冲区中向背面缓冲区中,在数组中矩形坐标定义的位置处进行对齐
当循环完成并且渲染函数返回时,最终图像现在将在后台缓冲区中完全合成。 现在可以将后缓冲区与前缓冲区交换,以使场景在屏幕上可见。