将OpenGL ES 2.0渲染成图像

5
我正在尝试将一些OpenGL ES 2.0渲染到图像文件中,与向用户显示的渲染无关。我渲染的图像尺寸与用户屏幕不同。我只需要一个GL_RGB数据的字节数组。我熟悉glReadPixels,但我认为在这种情况下它不起作用,因为我没有从已经渲染好的用户屏幕中获取数据。
伪代码:
// Switch rendering to another buffer (framebuffer? renderbuffer?)

// Draw code here

// Save byte array of rendered data GL_RGB to file

// Switch rendering back to user's screen.

我该如何在不影响用户显示的情况下实现这一功能?我不想让用户的屏幕闪烁,只为一个帧绘制我的所需信息,glReadPixel函数读取后再消失。

再次强调,我不希望向用户显示任何内容。以下是我的代码。但它并不能正常工作,我有什么遗漏吗?

unsigned int canvasFrameBuffer;
bglGenFramebuffers(1, &canvasFrameBuffer);
bglBindFramebuffer(BGL_RENDERBUFFER, canvasFrameBuffer);
unsigned int canvasRenderBuffer;
bglGenRenderbuffers(1, &canvasRenderBuffer);
bglBindRenderbuffer(BGL_RENDERBUFFER, canvasRenderBuffer);
bglRenderbufferStorage(BGL_RENDERBUFFER, BGL_RGBA4, width, height);
bglFramebufferRenderbuffer(BGL_FRAMEBUFFER, BGL_COLOR_ATTACHMENT0, BGL_RENDERBUFFER, canvasRenderBuffer);

unsigned int canvasTexture;
bglGenTextures(1, &canvasTexture);
bglBindTexture(BGL_TEXTURE_2D, canvasTexture);
bglTexImage2D(BGL_TEXTURE_2D, 0, BGL_RGB, width, height, 0, BGL_RGB, BGL_UNSIGNED_BYTE, 0);
bglFramebufferTexture2D(BGL_FRAMEBUFFER, BGL_COLOR_ATTACHMENT0, BGL_TEXTURE_2D, canvasTexture, 0);

Matrix::matrix_t identity;
Matrix::LoadIdentity(&identity);
bglClearColor(1.0f, 1.0f, 1.0f, 1.0f);
bglClear(BGL_COLOR_BUFFER_BIT);
Draw(&identity, &identity, this);
bglFlush();
bglFinish();

byte *buffer = (byte*)Z_Malloc(width * height * 4, ZT_STATIC);
bglReadPixels(0, 0, width, height, BGL_RGB, BGL_UNSIGNED_BYTE, buffer);
SaveTGA("canvas.tga", buffer, width, height);
Z_Free(buffer);

// unbind frame buffer
bglBindRenderbuffer(BGL_RENDERBUFFER, 0);
bglBindFramebuffer(BGL_FRAMEBUFFER, 0);
bglDeleteTextures(1, &canvasTexture);
bglDeleteRenderbuffers(1, &canvasRenderBuffer);
bglDeleteFramebuffers(1, &canvasFrameBuffer);

1
我找到了一些关于渲染到纹理的信息,但我不确定那是否是我想要的,因为我想将其渲染到字节数组以保存/分析图像数据。我很好奇正确的方法是什么。 - user1054922
1
无论缓冲区是否出现在屏幕上,GPU仍然必须对其进行渲染。没有办法使离屏渲染不影响性能... - Justin Meiners
我不是在谈论影响性能,而是仅仅不向用户显示任何东西(即闪烁)。 - user1054922
非 ES 版本:https://dev59.com/gnA75IYBdhLWcg3wo6le || https://dev59.com/CG025IYBdhLWcg3wtoVA - Ciro Santilli OurBigBook.com
2个回答

5
以下是针对需要此解决方案的任何人的解决方案:

这里是解决方案:

    // Create framebuffer
unsigned int canvasFrameBuffer;
glGenFramebuffers(1, &canvasFrameBuffer);
glBindFramebuffer(GL_RENDERBUFFER, canvasFrameBuffer);

// Attach renderbuffer
unsigned int canvasRenderBuffer;
glGenRenderbuffers(1, &canvasRenderBuffer);
glBindRenderbuffer(GL_RENDERBUFFER, canvasRenderBuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA4, width, height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, canvasRenderBuffer);

    // Clear the target (optional)
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);

    // Draw whatever you want here

char *buffer = (char*)malloc(width * height * 3);
glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, buffer);
SaveTGA("canvas.tga", buffer, width, height); // Your own function to save the image data to a file (in this case, a TGA)
free(buffer);

// unbind frame buffer
glBindRenderbuffer(GL_RENDERBUFFER, 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glDeleteRenderbuffers(1, &canvasRenderBuffer);
glDeleteFramebuffers(1, &canvasFrameBuffer);

请问如果宽度/高度大于GL_MAX_RENDERBUFFER_SIZE,您会怎么做?这样就无法创建所需大小的渲染缓冲区了... - XZen
我在linux上无法使其正常工作。BGL_RGBA4,ZT_CACHE和Z_MALLOC,SAVE_TGA,Z_FREE是什么? - Adam Hunyadi
抱歉,这些是我自己编写的函数。我已经编辑了我的帖子,用标准等效函数替换它们。 - user1054922

1

更新了帖子,其中包含我正在尝试渲染到离屏纹理的一些代码。 - user1054922
在stackoverflow上更新了我的答案,并附带了一些相关问题和答案。 - Trax
我没有看到glBindFramebuffer的调用,它在Draw函数里面吗? - Trax
Draw() 只包含基本的 OpenGL 绘图代码... 绑定数组和 glDrawArrays 等。OpenGL ES 2.0 没有 glReadBuffer...?我看过你提供的链接,其中一个发布了一个“解决方案”,但它看起来高度特定于 iOS。寻找一些仅限于 GL 的东西。 - user1054922
抱歉,我的错。你不需要使用glReadBuffer了,版本太多了 :) - Trax

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接