【问题标题】:How to efficiently copy depth buffer to texture on OpenGL ES如何有效地将深度缓冲区复制到 OpenGL ES 上的纹理
【发布时间】:2012-10-11 20:39:09
【问题描述】:

我正在尝试通过从标准 GL 移植 some code,在 iOS 上的 OpenGL ES 2.0 中获得一些阴影效果。部分示例涉及将深度缓冲区复制到纹理:

glBindTexture(GL_TEXTURE_2D, g_uiDepthBuffer);
glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, 0, 0, 800, 600, 0);

但是,似乎 ES 不支持 glCopyTexImage2D。阅读related thread,看来我可以使用帧缓冲区和片段着色器来提取深度数据。所以我试图将深度分量写入颜色缓冲区,然后复制它:

// clear everything
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); 

// turn on depth rendering
glUseProgram(m_BaseShader.uiId);

// this is a switch to cause the fragment shader to just dump out the depth component
glUniform1i(uiBaseShaderRenderDepth, true);

// and for this, the color buffer needs to be on
glColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_TRUE);

// and clear it to 1.0, like how the depth buffer starts
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);

// draw the scene
DrawScene();

// bind our texture 
glBindTexture(GL_TEXTURE_2D, g_uiDepthBuffer);
glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, width, height, 0);

这是片段着色器:

uniform sampler2D sTexture;
uniform bool bRenderDepth;

varying lowp    float LightIntensity;
varying mediump vec2  TexCoord;

void main()
{    
    if(bRenderDepth) {
        gl_FragColor = vec4(vec3(gl_FragCoord.z), 1.0);
    } else {
        gl_FragColor = vec4(texture2D(sTexture, TexCoord).rgb * LightIntensity, 1.0);
    }
}

我已经尝试不使用“bRenderDepth”分支,但它并没有显着加快速度。

现在几乎只是以 14fps 的速度执行此步骤,这显然是不可接受的。如果我以高于 30fps 的速度拉出副本。我从 Xcode OpenGLES 分析器中得到了两个关于复制命令的建议:

  1. file://localhost/Users/xxxx/Documents/Development/xxxx.mm:错误: 验证错误:glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, 960, 640, 0) : Height 不是 2 的幂

  2. file://localhost/Users/xxxx/Documents/Development/xxxx.mm:警告: GPU 等待纹理:您的应用更新了当前的纹理 用于渲染。这导致CPU等待GPU 完成渲染。

我将努力解决上述两个问题(也许它们是其中的症结所在)。与此同时,谁能提出一种更有效的方法来将深度数据提取到纹理中?

提前致谢!

【问题讨论】:

  • 我还没有尝试过,但是您不能使用片段着色器将深度信息写入渲染纹理的颜色缓冲区,然后将其用作另一个着色器的输入以进行后期处理吗?然后,OpenGL 应该只在 GPU 上进行同步,并且您不会停止执行基于 CPU 的回读/复制的管道。另见相关讨论here

标签: opengl-es opengl-es-2.0 depth-buffer


【解决方案1】:

iOS设备一般都支持OES_depth_texture,所以在有扩展的设备上,你可以设置一个带有深度纹理的framebuffer对象作为其唯一的附件:

GLuint g_uiDepthBuffer;
glGenTextures(1, &g_uiDepthBuffer);
glBindTexture(GL_TEXTURE_2D, g_uiDepthBuffer);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, width, height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL);
// glTexParameteri calls omitted for brevity

GLuint g_uiDepthFramebuffer;
glGenFramebuffers(1, &g_uiDepthFramebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, g_uiDepthFramebuffer);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, g_uiDepthBuffer, 0);

然后,当您绘制场景时,您的纹理会接收所有写入深度缓冲区的值(您可以为此使用普通的片段着色器),并且您可以直接从中进行纹理处理,而无需调用 glCopyTexImage2D

【讨论】:

  • 你是 100% 正确的。我的理解基于开放 gl 2.0 ES 规范支持的内容,该规范不包括任何对扩展的提及。所有 iOS ES 2.0 设备都支持 OES_depth_texture,所以这确实是解决方案。谢谢!
  • 所以可以有一个只有深度的帧缓冲附件吗?
猜你喜欢
  • 2011-05-01
  • 2011-09-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-09
  • 2011-02-05
相关资源
最近更新 更多