- mongodb - 在 MongoDB mapreduce 中,如何展平值对象?
- javascript - 对象传播与 Object.assign
- html - 输入类型 ="submit"Vs 按钮标签它们可以互换吗?
- sql - 使用 MongoDB 而不是 MS SQL Server 的优缺点
我的目标是将没有窗口的 OpenGL 场景直接渲染到文件中。场景可能比我的屏幕分辨率大。
我该怎么做?
如果可能的话,我希望能够将渲染区域大小选择为任意大小,例如 10000x10000?
最佳答案
一切从 glReadPixels
开始,您将使用它来将存储在 GPU 上特定缓冲区中的像素传输到主内存 (RAM)。正如您将在文档中注意到的那样,没有选择哪个缓冲区的参数。与 OpenGL 一样,要读取的当前缓冲区是一个状态,您可以使用 glReadBuffer
进行设置。
所以一个非常基本的离屏渲染方法如下所示。我使用 c++ 伪代码,因此它可能包含错误,但应该使一般流程清晰:
//Before swapping
std::vector<std::uint8_t> data(width*height*4);
glReadBuffer(GL_BACK);
glReadPixels(0,0,width,height,GL_BGRA,GL_UNSIGNED_BYTE,&data[0]);
这将读取当前的后台缓冲区(通常是您正在绘制的缓冲区)。您应该在交换缓冲区之前调用它。请注意,您也可以使用上述方法完美地读取后台缓冲区,清除它并在交换之前绘制完全不同的东西。从技术上讲,您也可以读取前端缓冲区,但通常不鼓励这样做,因为理论上允许实现一些优化,这可能会使您的前端缓冲区包含垃圾。
这样做有一些缺点。首先,我们并没有真正进行离屏渲染。我们渲染到屏幕缓冲区并从中读取。我们可以通过从不交换后台缓冲区来模拟屏幕外渲染,但感觉不对。除此之外,前缓冲区和后缓冲区都经过优化以显示像素,而不是读取它们。那是Framebuffer Objects发挥作用。
本质上,FBO 允许您创建一个非默认帧缓冲区(如 FRONT 和 BACK 缓冲区),允许您绘制到内存缓冲区而不是屏幕缓冲区。在实践中,您可以绘制到纹理或 renderbuffer .当您想将 OpenGL 本身中的像素重新用作纹理(例如,游戏中的“安全摄像头”)时,第一个是最佳选择,如果您只想渲染/回读,则后者是最佳选择。有了这个,上面的代码就会变成这样,又是伪代码,所以如果输入错误或忘记了一些语句,请不要杀我。
//Somewhere at initialization
GLuint fbo, render_buf;
glGenFramebuffers(1,&fbo);
glGenRenderbuffers(1,&render_buf);
glBindRenderbuffer(render_buf);
glRenderbufferStorage(GL_RENDERBUFFER, GL_BGRA8, width, height);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER,fbo);
glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, render_buf);
//At deinit:
glDeleteFramebuffers(1,&fbo);
glDeleteRenderbuffers(1,&render_buf);
//Before drawing
glBindFramebuffer(GL_DRAW_FRAMEBUFFER,fbo);
//after drawing
std::vector<std::uint8_t> data(width*height*4);
glReadBuffer(GL_COLOR_ATTACHMENT0);
glReadPixels(0,0,width,height,GL_BGRA,GL_UNSIGNED_BYTE,&data[0]);
// Return to onscreen rendering:
glBindFramebuffer(GL_DRAW_FRAMEBUFFER,0);
这是一个简单的示例,实际上您可能还需要存储深度(和模板)缓冲区。您可能还想渲染到纹理,但我将把它留作练习。无论如何,您现在将执行真正的离屏渲染,它可能比读取后台缓冲区更快。
最后,您可以使用 pixel buffer objects使读取像素异步。问题是 glReadPixels
阻塞,直到像素数据完全传输,这可能会使您的 CPU 停滞。使用 PBO 的实现可能会立即返回,因为它无论如何都控制缓冲区。只有当您映射缓冲区时,管道才会阻塞。但是,PBO 可以优化为仅在 RAM 上缓冲数据,因此该 block 可能需要更少的时间。读取的像素代码会变成这样:
//Init:
GLuint pbo;
glGenBuffers(1,&pbo);
glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo);
glBufferData(GL_PIXEL_PACK_BUFFER, width*height*4, NULL, GL_DYNAMIC_READ);
//Deinit:
glDeleteBuffers(1,&pbo);
//Reading:
glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo);
glReadPixels(0,0,width,height,GL_BGRA,GL_UNSIGNED_BYTE,0); // 0 instead of a pointer, it is now an offset in the buffer.
//DO SOME OTHER STUFF (otherwise this is a waste of your time)
glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo); //Might not be necessary...
pixel_data = glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY);
大写的部分是必不可少的。如果您只是向 PBO 发出 glReadPixels
,然后再发出该 PBO 的 glMapBuffer
,那么您只获得了很多代码。当然 glReadPixels
可能会立即返回,但现在 glMapBuffer
将停止,因为它必须安全地将数据从读取缓冲区映射到 PBO 和 main 中的内存块内存。
还请注意,我在所有地方都使用 GL_BGRA,这是因为许多显卡在内部使用它作为最佳渲染格式(或不带 alpha 的 GL_BGR 版本)。它应该是这样的像素传输最快的格式。我会试着找到我在几个月前读到的关于这方面的 nvidia 文章。
在使用 OpenGL ES 2.0 时,GL_DRAW_FRAMEBUFFER
可能不可用,在这种情况下您应该使用 GL_FRAMEBUFFER
。
关于c++ - 如何在 OpenGL 上渲染屏幕外?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12157646/
在 OpenGL/ES 中,在实现渲染到纹理功能时,您必须小心,不要引起反馈循环(从正在写入的同一纹理中读取像素)。由于显而易见的原因,当您读取和写入纹理的相同像素时,行为是未定义的。但是,如果您正在
正如我们最终都知道的那样,规范是一回事,实现是另一回事。大多数错误是我们自己造成的,但有时情况并非如此。 我相信列出以下内容会很有用: GPU 驱动程序中当前已知的与最新版本的 OpenGL 和 GL
很难说出这里问的是什么。这个问题是模棱两可的、模糊的、不完整的、过于宽泛的或修辞的,无法以目前的形式得到合理的回答。为了帮助澄清这个问题以便可以重新打开它,visit the help center
我正在学习 OpenGL,非常想知道与显卡的交互如何。 我觉得了解它是如何在图形驱动程序中实现的,会让我了解 opengl 的完整内部结构(通过这个我可以知道哪些阶段/因素影响我对 opengl 性能
我正在尝试绘制到大于屏幕尺寸(即 320x480)的渲染缓冲区 (512x512)。 执行 glReadPixels 后,图像看起来是正确的,除非图像的尺寸超过屏幕尺寸——在本例中,超过 320 水平
我正在 Windows 中制作一个 3D 小行星游戏(使用 OpenGL 和 GLUT),您可以在其中穿过一堆障碍物在太空中移动并生存下来。我正在寻找一种方法来针对无聊的 bg 颜色选项设置图像背景。
如果我想要一个包含 100 个 10*10 像素 Sprite 的 Sprite 表,是否可以将它们全部排成一排来制作 1,000*10 像素纹理?还是 GPU 对不那么窄的纹理表现更好?这对性能有什
这个问题在这里已经有了答案: Rendering 2D sprites in a 3D world? (7 个答案) 关闭 6 年前。 我如何概念化让图像始终面对相机。我尝试将三角函数与 arcta
是否可以在 OpenGL 中增加缓冲区? 假设我想使用实例化渲染。每次在世界上生成一个新对象时,我都必须用实例化数据更新缓冲区。 在这种情况下,我有一个 3 个 float 的缓冲区 std::v
有人可以向我解释为什么下面的代码没有绘制任何东西,但如果我使用 GL_LINE_LOOP 它确实形成了一个闭环吗? glBegin(GL_POLYGON); for(int i = 0; i <= N
正如标题所说,OpenGL 中的渲染目标是什么?我对 OpenGL 很陌生,我看到的所有网站都让我很困惑。 它只是一个缓冲区,我在其中放置稍后将用于渲染的东西吗? 如果您能提供一个很好的引用来阅读它,
当使用 OpenGL 1.4 固定功能多纹理时,每个纹理阶段的输出在传递到下一个阶段之前是否都固定在 [0, 1]? spec说(第 153 页): If the value of TEXTURE_E
我比较了 2 个函数 openGL ES 和 openGL gvec4 texelFetchOffset(gsampler2DArray sampler, ivec3 P, int lod, ivec
关闭。这个问题是off-topic .它目前不接受答案。 想改进这个问题吗? Update the question所以它是on-topic用于堆栈溢出。 关闭 10 年前。 Improve thi
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 想改进这个问题?将问题更新为 on-topic对于堆栈溢出。 6年前关闭。 Improve this qu
那么当你调用opengl函数时,比如glDraw或者gLBufferData,是否会导致程序线程停止等待GL完成调用呢? 如果不是,那么 GL 如何处理调用像 glDraw 这样的重要函数,然后立即更
我正在尝试实现级联阴影贴图,当我想访问我的视锥体的每个分区的相应深度纹理时,我遇到了一个错误。 更具体地说,当我想选择正确的阴影纹理时会出现我的问题,如果我尝试下面的代码,我会得到一个像 this 中
我想为OpenGL ES和OpenGL(Windows)使用相同的着色器源。为此,我想定义自定义数据类型并仅使用OpenGL ES函数。 一种方法是定义: #define highp #define
我尝试用 6 个位图映射立方体以实现天空盒效果。我的问题是一个纹理映射到立方体的每个面。我已经检查了 gDEBugger,在立方体纹理内存中我只有一个 图像(因为我尝试加载六个图像)。 代码准备纹理:
在 OpenGL 中偏移深度的最佳方法是什么?我目前每个多边形都有索引顶点属性,我将其传递给 OpenGL 中的顶点着色器。我的目标是在深度上偏移多边形,其中最高索引始终位于较低索引的前面。我目前有这
我是一名优秀的程序员,十分优秀!