glBindFramebuffer() 离屏渲染+双缓存+读取opengl像素 glReadPixels()

Opengl4.0中可以进行离屏渲染,即创造一个帧缓存对象(FBO),绑定一个帧缓存对象后,所有对Op--engl的操作都会针对这个帧缓存对象执行。而最近做项目时,在做一个拍照功能——读取Opengl渲染出的像素,并存入到BMP位图中。项目采用的是Opengl1.0和Opengl4.3结合的方法,并且两者的使用相对独立。使用旧的Opengl方法运行程序时,通过
glReadBuffer(GL_FRONT);//指定要读取的缓存
glReadPixels(0, 0, width, height, GL_BGRA_EXT, GL_UNSIGNED_BYTE, (unsigned char*)imageData);
即可读取到像素,并保存起来。

但是,一旦使用Opengl4.3进行离屏渲染后,发现glReadBuffer()和glReadPixels()不能再读取到像素,于是我对每一部分使用Opengl4.3的代码都做了glGetError()检测,发现使用Opengl4.3的代码部分并没有调用错误,所以就一直查不出来问题在哪里。最后我想会不会是Opengl绑定的问题,终于发现Opengl4.3使用离屏渲染后没有解绑帧缓存。

解决方案即:在使用完帧缓存对象的最后,对帧缓存对象进行解绑,函数如下

glBindFramebuffer(GL_FRAMEBUFFER, GL_NONE);
于是我去查了www.khronos.org/关于glBindFramebuffer的定义:
While a non-zero framebuffer object name is bound, all rendering to the framebuffer (with glDrawArrays and glDrawElements) and reading from the framebuffer (with glReadPixels, glCopyTexImage2D, or glCopyTexSubImage2D) use the images attached to the application-created framebuffer object rather than the default window-system-provided framebuffer.
Application created framebuffer objects (i.e. those with a non-zero name) differ from the default window-system-provided framebufferin a few important ways. First, they have modifiable attachment points for a color buffer, a depth buffer, and a stencil buffer to which framebuffer attachable images may be attached and detached. Second, the size and format of the attached images are controlled entirely within the GL and are not affected by window-system events, such as pixel format selection, window resizes, and display mode changes. Third, when rendering to or reading from an application created framebuffer object, the pixel ownership test always succeeds (i.e. they own all their pixels).Fourth, there are no visible color buffer bitplanes, only a single "off-screen" color image attachment, so there is no sense of front and back buffers or swapping. Finally, there is no multisample buffer, so the value of the implementation-dependent state variables GL_SAMPLES and GL_SAMPLE_BUFFERS are both zero for application created framebuffer objects.
也就是说,使用glBindFramebuffer()进行离屏渲染时,Opengl的渲染和读取都是通过attached的纹理对帧缓存进行操作的,不再是对windows系统提供的默认帧缓存进行操作,所以我们见到的屏幕上显示出来的图像并不是一个可见的颜色缓存位面(visible color buffer bitplane),只不过是一个“离屏”的颜色纹理("off-screen" color image attachment),所以双缓存就不起作用了(即使调用swapbuffer(),像素也不会被渲染到前后缓存中),所以glReadBuffer(GL_FRONT);也就读取不出像素出来。
这个Bug前后找了将近两个星期,在这里Mark一下,说白了还是对Opengl理解不够,Opengl的使用个人感觉比较晦涩,还需要好好研究。希望对大家有所帮助。
格式一直调不好。。好吧。。
  • 9
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
### 回答1: 很抱歉,由于我的输入和输出都是基于文本的,所以我无法直接呈现完整的OpenGL ES离屏渲染代码。不过,我可以向您提供一些有用的资源和指导,帮助您了解OpenGL ES离屏渲染,并且编写出自己的完整代码。 OpenGL ES是一种开放标准的图形API,可以用于在移动设备和嵌入式设备上进行图形渲染离屏渲染是一种技术,可以在不将渲染结果显示在屏幕上的情况下进行渲染操作。这种技术通常用于图像处理、后期处理和离线渲染等方面。 要使用OpenGL ES进行离屏渲染,您需要创建一个离屏渲染目标,并将渲染操作发送到该目标。离屏渲染目标通常是一个帧缓冲对象(Framebuffer Object,FBO),可以将渲染操作发送到其中,然后将渲染结果保存到纹理或渲染缓冲区中。 以下是一些有用的资源,可以帮助您进一步了解OpenGL ES离屏渲染: 1. OpenGL ES官方文档:https://www.khronos.org/registry/OpenGL-Refpages/es3.0/ 2. OpenGL ES教程:http://www.learnopengles.com/ 3. OpenGL ES代码样例:https://github.com/learnopengles 4. Android OpenGLES官方文档:https://developer.android.com/guide/topics/graphics/opengl 5. iOS OpenGLES官方文档:https://developer.apple.com/library/archive/documentation/3DDrawing/Conceptual/OpenGLES_ProgrammingGuide/Introduction/Introduction.html 希望这些资源能够帮助您了解OpenGL ES离屏渲染,并编写出自己的完整代码。如果您有任何其他问题或疑问,请随时向我提问。 ### 回答2: opengles离屏渲染是指将渲染结果绘制到一个离屏的缓冲区中,而不是直接绘制到屏幕上。这个技术在一些特定的应用场景中很有用,比如生成纹理、实现后期处理效果等。 下面是一个使用opengles进行离屏渲染的完整代码示例: 1. 首先,我们需要创建一个新的Framebuffer对象和Renderbuffer对象。 GLuint framebuffer; glGenFramebuffers(1, &framebuffer); glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); GLuint renderbuffer; glGenRenderbuffers(1, &renderbuffer); glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer); 2. 将Renderbuffer对象附加到Framebuffer对象的颜色附件上。 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderbuffer); 3. 调用glRenderbufferStorage函数为Renderbuffer对象分配内存。 glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, width, height); 4.创建和编译着色器程序。 // 创建顶点着色器 GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER); glShaderSource(vertexShader, 1, &vertexShaderSource, NULL); glCompileShader(vertexShader); // 创建片段着色器 GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL); glCompileShader(fragmentShader); // 创建着色器程序 GLuint program = glCreateProgram(); glAttachShader(program, vertexShader); glAttachShader(program, fragmentShader); glLinkProgram(program); 5. 将Fragment Shader指定为离屏渲染的目标。 // 绑定Framebuffer对象 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); // 使用离屏渲染Framebuffer进行渲染 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderbuffer); // 指定渲染目标为离屏渲染 glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); // 使用离屏渲染Framebuffer进行渲染 glViewport(0, 0, width, height); glUseProgram(program); // 其他渲染操作 6. 清除OpenGL ES环境。 glDeleteShader(vertexShader); glDeleteShader(fragmentShader); glDeleteProgram(program); glDeleteRenderbuffers(1, &renderbuffer); glDeleteFramebuffers(1, &framebuffer); 以上代码展示了一个简单的使用OpenGL ES进行离屏渲染的过程。在实际应用中,可能需要进一步配置和设置OpenGL ES环境,并根据具体需求编写对应的顶点和片段着色器代码。 ### 回答3: OpenGLES离屏渲染的完整代码如下: ```java // 导入必要的库 import android.opengl.GLES20; import android.opengl.GLUtils; // 创建离屏渲染FrameBuffer int[] frameBuffer = new int[1]; GLES20.glGenFramebuffers(1, frameBuffer, 0); GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, frameBuffer[0]); // 创建离屏渲染的纹理 int[] texture = new int[1]; GLES20.glGenTextures(1, texture, 0); GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture[0]); GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, width, height, 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, null); GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR); GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR); GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_TEXTURE_2D, texture[0], 0); // 检查FrameBuffer状态 if (GLES20.glCheckFramebufferStatus(GLES20.GL_FRAMEBUFFER) != GLES20.GL_FRAMEBUFFER_COMPLETE) { // 离屏渲染失败 return; } // 开始离屏渲染 GLES20.glViewport(0, 0, width, height); GLES20.glClearColor(1.0f, 1.0f, 1.0f, 1.0f); GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); // 绘制离屏渲染的内容 // ... // 读取离屏渲染结果 ByteBuffer buffer = ByteBuffer.allocate(width * height * 4); GLES20.glReadPixels(0, 0, width, height, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, buffer); // 恢复默认的FrameBuffer GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0); // 清除离屏渲染FrameBuffer和纹理 GLES20.glDeleteTextures(1, texture, 0); GLES20.glDeleteFramebuffers(1, frameBuffer, 0); ``` 上述代码首先创建了一个离屏渲染FrameBuffer,然后创建了一个纹理用于存储渲染结果。接下来,通过绘制的相关操作,将渲染结果绘制到离屏渲染FrameBuffer中。最后,通过`glReadPixels`函数将离屏渲染的结果读取到一个ByteBuffer中。然后,代码恢复默认的FrameBuffer,并清除离屏渲染FrameBuffer和纹理。 需要注意的是,离屏渲染的尺寸由`width`和`height`确定,绘制的内容需要根据具体需求进行操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值