OpenGL ES 2调用glFramebufferTexture2D遇帧缓冲附件错误求助
首先得说,你代码里有几个致命的低级错误,这是导致帧缓冲错误的核心原因,先把这些解决了再看其他问题:
1. 最关键的错误:帧缓冲生成函数用错了
你写了glGenTextures(1, &framebuffer);——这完全不对!glGenTextures是用来生成纹理ID的,帧缓冲对象必须用glGenFramebuffers(1, &framebuffer);来生成。现在你的framebuffer变量里存的是一个无效的纹理ID,不是真正的帧缓冲,绑定后自然会提示GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT,因为你根本没绑定一个合法的帧缓冲。
2. 变量名写错了
你生成的纹理变量是texture,但绑定的时候写的是glBindTexture(GL_TEXTURE_EXTERNAL_OES, textureId);——textureId这个变量根本没定义过!这导致你绑定了一个随机的无效纹理ID,后面的glEGLImageTargetTexture2DOES完全没作用到你生成的texture上,所以把texture附加到FBO时,这个纹理是空的,触发附件错误。
3. 外部OES纹理的使用限制
OpenGL ES里,GL_TEXTURE_EXTERNAL_OES这类外部纹理(通常用于相机预览、视频解码)大多数平台不支持作为帧缓冲的渲染目标,它们的设计初衷是用来采样(比如在Shader里用samplerExternalOES读取),而不是让你渲染到上面。所以即使前面的错误都改了,你可能还是无法把它直接附加到FBO。
4. EGLImage销毁时机错误
你在纹理还关联着EGLImage的时候就调用了eglDestroyImageKHR(display,image);,一旦销毁EGLImage,对应的纹理内容会直接失效,必须等你彻底不再使用这个纹理之后再销毁它。
修正后的代码示例
GLuint texture; GLuint framebuffer; EGLImageKHR image = eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_NATIVE_PIXMAP_KHR, (EGLClientBuffer)&pixmap, NULL); assert(image != EGL_NO_IMAGE_KHR); // 生成纹理(正确) glGenTextures(1, &texture); // 生成帧缓冲(改用正确的函数!) glGenFramebuffers(1, &framebuffer); // 配置外部纹理参数 glBindTexture(GL_TEXTURE_EXTERNAL_OES, texture); // 这里用正确的变量名texture glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // 将EGLImage关联到纹理 glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, image); // 绑定帧缓冲并尝试附加纹理 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); // 注意:如果平台不支持外部OES纹理作为FBO附件,这一步会失败 GLenum attachStatus = glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_EXTERNAL_OES, texture, 0); if (attachStatus != GL_TRUE) { printf("平台不支持将外部OES纹理作为FBO附件\n"); } // 检查帧缓冲状态 GLenum fbStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER); if (fbStatus != GL_FRAMEBUFFER_COMPLETE) { printf("FBO错误状态:0x%X\n", fbStatus); } // 先不要销毁EGLImage,直到纹理不再使用 // eglDestroyImageKHR(display,image); glBindFramebuffer(GL_FRAMEBUFFER, 0); glBindTexture(GL_TEXTURE_EXTERNAL_OES, 0); // 当彻底不用这些资源时再清理: // glDeleteFramebuffers(1, &framebuffer); // glDeleteTextures(1, &texture); // eglDestroyImageKHR(display,image);
关于GL_TEXTURE_2D的错误说明
改成GL_TEXTURE_2D后出现GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT,除了上面的变量名和帧缓冲生成错误外,还有一个原因:不是所有EGLImage都能直接关联到普通2D纹理,格式不匹配也会导致附件无效。如果需要把外部图像转成可渲染的2D纹理,正确的做法是:
- 创建一个普通2D纹理
- 绑定FBO到这个2D纹理
- 把外部OES纹理渲染到这个FBO上,间接得到可用于渲染目标的2D纹理
内容的提问来源于stack exchange,提问作者KennyTan

