【问题标题】:Render to texture and render to renderbuffer at the same time同时渲染到纹理和渲染到渲染缓冲区
【发布时间】:2012-09-17 12:47:57
【问题描述】:

我使用这样的代码来设置我的帧缓冲区:

glGenRenderbuffers(1, &colorBuffer_) ;

glBindRenderbuffer(GL_RENDERBUFFER, colorBuffer_);

if (!colorBuffer_)
{
    NSLog(@"glGenRenderbuffers() failed");
    break;
}

[self.context renderbufferStorage:GL_RENDERBUFFER fromDrawable:drawable_];
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &width_);
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &height_);

glGenFramebuffers(1, &fbo);

glBindFramebuffer(GL_FRAMEBUFFER, fbo);

if (!fbo)
{
    NSLog(@"glGenFramebuffers() failed");
    break;
}

CVReturn err = CVOpenGLESTextureCacheCreate(kCFAllocatorDefault, NULL, self.context, NULL, &textureCache_);
if (err)
{
    NSAssert(NO, @"Error at CVOpenGLESTextureCacheCreate %d", err);
}
CFDictionaryRef empty; // empty value for attr value.
CFMutableDictionaryRef attrs;
empty = CFDictionaryCreate(kCFAllocatorDefault, // our empty IOSurface properties dictionary
                           NULL,
                           NULL,
                           0,
                           &kCFTypeDictionaryKeyCallBacks,
                           &kCFTypeDictionaryValueCallBacks);
attrs = CFDictionaryCreateMutable(kCFAllocatorDefault,
                                  1,
                                  &kCFTypeDictionaryKeyCallBacks,
                                  &kCFTypeDictionaryValueCallBacks);

CFDictionarySetValue(attrs,
                     kCVPixelBufferIOSurfacePropertiesKey,
                     empty);

CVPixelBufferCreate(kCFAllocatorDefault,
                    (int)width_,
                    (int)height_,
                    kCVPixelFormatType_32BGRA,
                    attrs,
                    &renderTarget_);

err = CVOpenGLESTextureCacheCreateTextureFromImage (kCFAllocatorDefault,
                                                    textureCache_, renderTarget_,
                                                    NULL, // texture attributes
                                                    GL_TEXTURE_2D,
                                                    GL_RGBA, // opengl format
                                                    (int)width_,
                                                    (int)height_,
                                                    GL_BGRA, // native iOS format
                                                    GL_UNSIGNED_BYTE,
                                                    0,
                                                    &renderTexture_);
if (err)
{
    NSAssert(NO, @"Error at CVOpenGLESTextureCacheCreate %d", err);
}

CFRelease(attrs);
CFRelease(empty);

glBindTexture(CVOpenGLESTextureGetTarget(renderTexture_), CVOpenGLESTextureGetName(renderTexture_));
checkForErrors();

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

NSLog(@"%u", CVOpenGLESTextureGetName(renderTexture_));

glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, CVOpenGLESTextureGetName(renderTexture_), 0);

glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorBuffer_);

我想同时渲染到纹理和渲染到渲染缓冲区(在屏幕上查看渲染结果)。但是这段代码不起作用。我认为我不能同时使用glFramebufferTexture2DglFramebufferRenderbuffer。我对吗?我该怎么做?

【问题讨论】:

    标签: ios opengl-es opengl-es-2.0


    【解决方案1】:

    您是对的,您不能将纹理和渲染缓冲区都附加到同一个附加点以自动渲染到两者中。

    只需将其渲染到纹理,然后在屏幕上绘制一个屏幕大小的纹理四边形来显示它。当然,请记住在渲染时取消绑定纹理 (glBindTexture(GL_TEXTURE_2D, 0)),目前您还没有这样做。

    或者通过像往常一样将结果渲染到屏幕并使用glCopyTexSubImage2D将这些结果复制到纹理中来做相反的事情。但最终你不会绕过副本,无论是间接地以绘制带纹理的四边形或直接帧缓冲区到纹理副本的形式。

    编辑:您也可以使用多个渲染目标来解决这个问题,方法是将纹理和渲染缓冲区附加到不同的颜色附件,并在片段着色器的多个通道上输出相同的结果颜色(使用 @ 987654323@ 而不是 gl_FragColor)。但我不确定这是否真的能给你带来任何好处,而且它要求你的着色器知道双重渲染。最后我不确定 ES 是否真的支持多个渲染目标。

    【讨论】:

    • 我有一个类似于苹果 GLPAint 示例的应用程序(使用 kEAGLDrawablePropertyRetainedBacking = YES)。 Ant 同时渲染纹理和绘制纹理四边形太昂贵了。有没有其他方法可以快速完成?
    • @miksayer 我列出了所有显而易见的方法。你真的需要每帧更新纹理吗?如果没有,则继续渲染到屏幕,仅在必要时使用glCopyTexSubImage2D。我不知道这个 GLPaint 应用程序的语义,但如果它是一些标准的绘画应用程序,你只需要在需要时更新实际的图像(纹理),或者至少在你完成交互式绘图时(例如释放鼠标/手指/任何东西时)。
    • 我已经尝试过使用 glCopyTexSubImage2D 的方法。但我没有任何性能提升(在我使用 glReadPixels 获取屏幕截图之前)。
    • @miksayer 好吧,glReadPixels(我猜后面是glTexSubImage2D)绝对是错误的方法,因为它往返于 CPU 是不必要的。虽然,如果性能存在差异,它仍然取决于您的系统和应用程序,也许您的实现甚至可以使用glCopyTexSubImage2D 在 CPU 上进行往返,但我真的很怀疑。我对 ES 设备的实际硬件也没有太多经验。尽管如此,glCopyTexSubImage2D 在概念上比glReadPixels 更正确(并且在最坏情况下性能等效)。
    • 我只想从屏幕上获取带有像素的缓冲区。我想快速完成。 glReadPixels 和 glCopyTexSubImage2D 没有给我我想要的性能:(
    最近更新 更多