OpenGL ES 渲染到纹理,然后绘制纹理

Posted

技术标签:

【中文标题】OpenGL ES 渲染到纹理,然后绘制纹理【英文标题】:OpenGL ES render to texture, then draw texture 【发布时间】:2009-10-30 11:12:46 【问题描述】:

我正在尝试渲染到纹理,然后使用 iPhone 上的 OpenGL ES 将该纹理绘制到屏幕上。我以this question 为起点,在 Apple 演示 EAGLView 的子类中进行绘图。

实例变量:

GLuint textureFrameBuffer;
Texture2D * texture;

要初始化帧缓冲区和纹理,我这样做:

GLint oldFBO;
glGetIntegerv(GL_FRAMEBUFFER_BINDING_OES, &oldFBO);

// initWithData results in a white image on the device (works fine in the simulator)
texture = [[Texture2D alloc] initWithImage:[UIImage imageNamed:@"blank320.png"]];

// create framebuffer
glGenFramebuffersOES(1, &textureFrameBuffer);
glBindFramebufferOES(GL_FRAMEBUFFER_OES, textureFrameBuffer);

// attach renderbuffer
glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_TEXTURE_2D, texture.name, 0);

if(glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES)
    NSLog(@"incomplete");

glBindFramebufferOES(GL_FRAMEBUFFER_OES, oldFBO);

现在,如果我像往常一样简单地将场景绘制到屏幕上,它可以正常工作:

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// draw some triangles, complete with vertex normals
[contentDelegate draw];
[self swapBuffers];

但是,如果我渲染到“textureFrameBuffer”,然后在屏幕上绘制“纹理”,则生成的图像是颠倒的并且“由内向外”。也就是说,看起来好像 3d 对象的法线指向内部而不是外部——每个对象的最前面是透明的,我可以看到背面的内部。代码如下:

GLint oldFBO;
glGetIntegerv(GL_FRAMEBUFFER_BINDING_OES, &oldFBO);

glBindFramebufferOES(GL_FRAMEBUFFER_OES, textureFrameBuffer);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

// draw some polygons
[contentDelegate draw];

glBindFramebufferOES(GL_FRAMEBUFFER_OES, oldFBO);

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnable(GL_TEXTURE_2D);
glColor4f(1, 1, 1, 1);
[texture drawInRect:CGRectMake(0, 0, 320, 480)];    
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisable(GL_TEXTURE_2D);

[self swapBuffers];

通过相应地重新排序 (glTexCoordPointer) 坐标(在 Texture2D 的 drawInRect 方法中),我可以轻松地将图像正面朝上翻转,但这并不能解决“由内而外”的问题。

我尝试用手动创建的 OpenGL 纹理替换 Texture2D 纹理,结果是一样的。绘制从 PNG 图像加载的 Texture2D 效果很好。

对于绘制对象,每个顶点都有一个单位法线指定,并启用GL_NORMALIZE

glVertexPointer(3, GL_FLOAT, 0, myVerts);
glNormalPointer(GL_FLOAT, 0, myNormals);
glDrawArrays(GL_TRIANGLES, 0, numVerts);

渲染到屏幕时一切都很好; GL_DEPTH_TEST 已启用并且运行良好。

关于如何解决此问题的任何建议?谢谢!

【问题讨论】:

对于“由内而外”的问题:如果您的正面图元被剔除,那么您的顶点顺序有问题,用于确定面法线。除非我误解了某些东西,否则这不是纹理的问题。您是否启用了 GL_CULL_FACE? GL_CULL_FACE 未启用。启用它肯定会改善整体外观。对象法线现在似乎是正确的出路,但是许多应该隐藏的正面现在可见,无论它们是否(或者更确切地说,应该)被另一个面遮挡。这是否表明我的三角形缠绕有问题?我正在使用脚本从 Blender 中导出顶点;我会确保输出时绕组是均匀的。请注意,当我直接在屏幕上绘制时,一切看起来都很完美(开启或关闭 GL_CULL_FACE 没有区别)。 【参考方案1】:

有趣的是,当直接绘制到后台缓冲区时,您会看到不同的结果。由于您使用的是 iPhone 平台,因此您总是在绘制到 FBO,即使在绘制到后台缓冲区时也是如此。

确保您已将深度缓冲区附加到屏幕外 FBO。在您的初始化代码中,您可能希望在 glBindFramebufferOES(...) 之后添加以下 sn-p。

// attach depth buffer
GLuint depthRenderbuffer;
glGenRenderbuffersOES(1, &depthRenderbuffer);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, depthRenderbuffer);
glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_DEPTH_COMPONENT16_OES, width, height);
glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, depthRenderbuffer);

【讨论】:

你可能正在做一些事情,但它还没有工作......在这样做并附加纹理之后(如前所述),glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) 返回 GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_OES。 frameBuffer 是否也需要附加一个颜色渲染缓冲区? (很快就试过了,还没有运气,但我会坚持下去。)顺便谢谢你的帮助,我真的很感激。 哦,我的意思是将该渲染添加到后台缓冲区,然后使用 glCopyTexSubImage2D 复制到我的图像中,然后显示图像作品(一切都按照它应该的方式绘制),它只是非常缓慢。回到找出我的缓冲区出了什么问题...... 有趣。是的,您还需要附加颜色渲染缓冲区。顺便说一句,这不相关,但您可能希望确保您的纹理对象具有 2 的幂大小,以便它适用于较旧的 iPhone。祝你好运! 好吧,我已经离开了这个项目,并没有开始设置所有适当的缓冲区。我将其标记为正确,因为它可能是。如果我再回来,我会在这里发布我的工作代码。

以上是关于OpenGL ES 渲染到纹理,然后绘制纹理的主要内容,如果未能解决你的问题,请参考以下文章

我的OpenGL学习进阶之旅关于OpenGL ES 绘制纹理,因为加载纹理坐标设置错误,导致纹理无法渲染的问题

我的OpenGL学习进阶之旅关于OpenGL ES 绘制纹理,因为加载纹理坐标设置错误,导致纹理无法渲染的问题

绘制到纹理后的Opengl ES 2.0 glDeleteFramebuffers

渲染到纹理 OpenGL ES 2.0

OpenGL ES 2.0 Framebuffer 渲染到纹理 iOS:没有显示

OpenGL:渲染到 FBO 时是不是支持纹理组合器功能?