如何在OpenGL ES上有效地将深度缓冲区复制到纹理 [英] How to efficiently copy depth buffer to texture on OpenGL ES

查看:596
本文介绍了如何在OpenGL ES上有效地将深度缓冲区复制到纹理的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正试图通过移植来自标准GL的一些代码.该示例的一部分涉及将深度缓冲区复制到纹理:

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

但是,似乎ES上不支持glCopyTexImage2D.阅读相关线程,看来我可以使用帧缓冲区和片段着色器以提取深度数据.因此,我尝试将深度组件写入颜色缓冲区,然后将其复制:

// 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):高度<640>不是2的幂

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

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

提前谢谢!

解决方案

iOS设备通常支持 OES_depth_texture ,因此在存在扩展名的设备上,您可以将具有深度纹理的帧缓冲对象设置为其唯一附件:

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.

I'm trying to get some shadowing effects to work in OpenGL ES 2.0 on iOS by porting some code from standard GL. Part of the sample involves copying the depth buffer to a texture:

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

However, it appears the glCopyTexImage2D is not supported on ES. Reading a related thread, it seems I can use the frame buffer and fragment shaders to extract the depth data. So I'm trying to write the depth component to the color buffer, then copying it:

// 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);

Here is the fragment shader:

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);
    }
}

I have experimented with not having the 'bRenderDepth' branch, and it doesn't speed it up significantly.

Right now pretty much just doing this step its at 14fps, which obviously is not acceptable. If I pull out the copy its way above 30fps. I'm getting two suggestions from the Xcode OpenGLES analyzer on the copy command:

  1. file://localhost/Users/xxxx/Documents/Development/xxxx.mm: error: Validation Error: glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, 960, 640, 0) : Height<640> is not a power of two

  2. file://localhost/Users/xxxx/Documents/Development/xxxx.mm: warning: GPU Wait on Texture: Your app updated a texture that is currently used for rendering. This caused the CPU to wait for the GPU to finish rendering.

I'll work to resolve the two above issues (perhaps they are the crux if of it). In the meantime can anyone suggest a more efficient way to pull that depth data into a texture?

Thanks in advance!

解决方案

iOS devices generally support OES_depth_texture, so on devices where the extension is present, you can set up a framebuffer object with a depth texture as its only attachment:

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);

Your texture then receives all the values being written to the depth buffer when you draw your scene (you can use a trivial fragment shader for this), and you can texture from it directly without needing to call glCopyTexImage2D.

这篇关于如何在OpenGL ES上有效地将深度缓冲区复制到纹理的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆