最近项目需要对GL_OVR_multiview进行了研究,
需求是对 unity 渲染完成的GL_TEXTURE_2D_ARRAY做二次渲染,通过一次draw call将不同的纹理绘制到GL_TEXTURE_2D_ARRAY不同的layer中。
首先介绍下GL_OVR_multiview,在OpenGL ES SDK for Android上对GL_OVR_multiview做了比较详细的介绍。
可以理解为GL_OVR_multiview是通过一次draw call 实现将帧缓冲对象(framebuffer Object)渲染到2D纹理数组(GL_TEXTURE_2D_ARRAY)的技术
首先初始化渲染环境
bool setupFBO(int width, int height)
{
// Create array texture
GL_CHECK(glGenTextures(1, &frameBufferTextureId));
GL_CHECK(glBindTexture(GL_TEXTURE_2D_ARRAY, frameBufferTextureId));
GL_CHECK(glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
GL_CHECK(glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
GL_CHECK(glTexStorage3D(GL_TEXTURE_2D_ARRAY, 1, GL_RGBA8, width, height, 2));
/* Initialize FBO. */
GL_CHECK(glGenFramebuffers(1, &frameBufferObjectId));
/* Bind our framebuffer for rendering. */
GL_CHECK(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, frameBufferObjectId));
/* Attach texture to the framebuffer. */
GL_CHECK(glFramebufferTextureMultiviewOVR(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
frameBufferTextureId, 0, 0, 2));
/* Create array depth texture */
GL_CHECK(glGenTextures(1, &frameBufferDepthTextureId));
GL_CHECK(glBindTexture(GL_TEXTURE_2D_ARRAY, frameBufferDepthTextureId));
GL_CHECK(glTexStorage3D(GL_TEXTURE_2D_ARRAY, 1, GL_DEPTH_COMPONENT24, width, height, 2));
/* Attach depth texture to the framebuffer. */
GL_CHECK(glFramebufferTextureMultiviewOVR(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
frameBufferDepthTextureId, 0, 0, 2));
/* Check FBO is OK. */
GLenum result = GL_CHECK(glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER));
if (result != GL_FRAMEBUFFER_COMPLETE)
{
LOGE("Framebuffer incomplete at %s:%i\n", __FILE__, __LINE__);
/* Unbind framebuffer. */
GL_CHECK(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0));
return false;
}
return true;
}
上述方法是在unity渲染线程使用的,unity会将frameBufferObjectId渲染到frameBufferTextureId 2D纹理数组上。
unity完成渲染后,会将frameBufferTextureId 2D纹理数组传递给SDK,由SDK做二次渲染。
首先SDK需要检查当前绑定的纹理是否为renderTexture2DArrayId,如果不是需要重新绑定renderTexture2DArrayId并设置GL_OVR_multiview
代码如下:
GLint defaultActiveTextureArray = 0;
GL(glGetIntegerv(GL_TEXTURE_BINDING_2D_ARRAY, &defaultActiveTextureArray));
GLint renderTexture2DArrayId = frameBufferTextureId;
glBindTexture(GL_TEXTURE_2D_ARRAY, renderTexture2DArrayId);
//相当于glFramebufferTexture2D
glFramebufferTextureMultiviewOVR(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,renderTexture2DArrayId, 0, 0, 2);
GLint defaultFbId;
GL(glGetIntegerv(GL_FRAMEBUFFER_BINDING, &defaultFbId));
//postprocess renderTexture2DArrayId only by on draw call
postprocess(renderTexture2DArrayId);
glBindTexture(GL_TEXTURE_2D_ARRAY, defaultActiveTextureArray);
shader 中需要打开GL_OVR_multiview feature(由于绘制的2D纹理数组,如果不同layer不仅gl_Position不同,纹理及纹理坐标都不同,需要GL_OVR_multiview2 feature)
定点着色器如下
+char multiviewVs[] =
+ "#version 300 es\n"
+ "#extension GL_OVR_multiview2 : require\n"
+ "layout(num_views = 2) in;\n"
+ "in vec2 position[2];\n"
+ "in vec2 texcoord[2];\n"
+ "out vec3 vTexcoord0;\n"
+ "uniform mat4 mvpMatrix[2];\n"
+ "void main()\n"
+ "{\n"
+ " vec2 vposition = position[gl_ViewID_OVR];\n"
+ " vec2 vtexcoord = texcoord[gl_ViewID_OVR];\n"
+ " mat4 currentmvp= mvpMatrix[gl_ViewID_OVR];\n"
+ " gl_Position = currentmvp*vec4(vposition .x, vposition y, 0.0, 1.0);\n"
+ " vTexcoord0 = vec3(vtexcoord .x,vtexcoord .y,gl_ViewID_OVR);\n"
+ "}\n";
片段着色器代码如下
+char multiviewFs[] =
+ "#version 300 es\n"
+ "in vec3 vTexcoord0;\n"
+ "uniform sampler2DArray srcTex;\n"
+ "//uniform sampler2D srcTex;\n"
+ "out vec4 outColor;\n"
+ "void main()\n"
+ "{\n"
+ " outColor = texture(srcTex, vTexcoord0);\n"
+ "}\n";
最终的效果是对renderTexture2DArrayId纹理进行了二次处理,将sampler2DArray中的内容绘制到了renderTexture2DArrayId。效果如下图