当前位置: 首页 > 知识库问答 >
问题:

如何将一个LWJGL游戏场景渲染到一个ByteBuffer?

申宜
2023-03-14

我目前正在从事一个项目,该项目涉及将LWJGL游戏场景渲染为视频流而不是窗口。我相信,如果将游戏场景渲染为中间格式(如 ByteBuffer),我就能实现这一目标。我正在尝试扩展LWJGL VoxelGame演示作为概念证明。

我发现了一个类似的SO问题和一个论坛帖子,但我无法做到这一点。我是OpenGL和LWJGL的初学者,我正在努力寻找关于这方面的可理解文档。

在渲染循环runUpdateAndRenderLoop)的开始,调用函数glBindFramebuffer。根据我的理解,它将FBO绑定到当前上下文,以便任何渲染都将定向到它。

我尝试过使用<code>glGetTexImage来填充字节缓冲区,但它不起作用。我在<code>glBlitFramebuffer</code>之后也尝试过,因为我想将完整的渲染图像获取到ByteBuffer。

如何将当前游戏场景渲染到ByteBuffer?有没有更好的方法将游戏场景渲染到视频流而不是中间ByteBuffer?

private void runAndUpdateRenderLoop() {
    // ...
    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
    glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
    byte[] pixels = new byte[width * height * 4];
    ByteBuffer buffer = ByteBuffer.allocateDirect(pixels.length).order(ByteOrder.nativeOrder());
    glGetTexImage(GL_TEXTURE_BUFFER, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
    glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
    glfwSwapBuffers(window);
}

共有2个答案

微生昌胤
2023-03-14

@Blindy的答案是100%正确的,你应该接受它作为答案。

但是,如果您想要一个直接工作的解决方案的代码,那么在

glBlitFramebuffer(0, 0, 宽度, 高度, 0, 0, 宽度, 高度, GL_COLOR_BUFFER_BIT, GL_NEAREST);

但在之前

<代码>glfwSwapBuffers(窗口)

代码:

ByteBuffer bb = org.lwjgl.system.MemoryUtil.memAlloc(width * height * 4);
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, bb);
// Test with stb_image to write as jpeg:
// org.lwjgl.stb.STBImageWrite.stbi_flip_vertically_on_write(true);
// org.lwjgl.stb.STBImageWrite.stbi_write_jpg("frame.jpg", width, height, 4, bb, 50);
org.lwjgl.system.MemoryUtil.memFree(bb);

这将导致ByteBufferbb保存当前帧的像素数据。

但是,正如@Blindy所指出的那样,这是一个严重的GPU停顿,因为您被迫等待当前帧的数据完全渲染并强制GPU-

像素路径性能警告:像素传输与3D渲染同步。

根据您的实际用例,其他方法可能更有用,例如直接从GPU内存对视频进行编码(例如使用NVENC)。

胡承悦
2023-03-14

你的代码中有一大堆问题,甚至还没有看到问题的核心,因为它在<code>/…</code>部分:

>

  • 当您尝试在无头设置中渲染时,不使用<code>glfwSwapBuffers

    您不需要 glGetTexImageglReadPixel,它们都将数据从图形内存读取到系统内存。在你的例子中,你正在缓冲区中读取纹理数据,然后用反向缓冲器数据覆盖它,这些数据应该是空的,因为你从来没有写过它。

    你肯定不想要< code>glBlitFramebuffer,那是用于从视频存储器复制到视频存储器的。你真的需要停下来阅读文档,对你的视频驱动程序使用随机函数肯定会让它崩溃。

    您需要启用OpenGL的调试层验证,尤其是在尝试所有这些随机函数时。与此相关的是,您需要检查您的帧缓冲区设置(glCheckFrameBufferStatusEXT),我敢打赌您没有,但您没有显示您的代码。

    您没有显示帧缓冲区绑定,因此我无法判断您是否正在执行此操作,但是您需要在读取帧缓冲区之前将其绑定为“read”(GL_READ_FRAMEBUFFER)。我只看到“绘制”帧缓冲区绑定,而您只是随机清除它。

    最后,在从视频内存读取操作时,永远不要让CPU暂停,尤其是当您有一些事情要做时,比如视频编码。以循环方式使用像素缓冲区对象来对传输进行两倍或三倍缓冲,因此不会出现停滞。

  •  类似资料:
    • 最近,我决定重温一些LWJGL渲染代码,这些代码是我根据LWJGLWiki上的教程使用索引VBOs编写的。在我的台式电脑上,一切正常,但当我切换到学校笔记本电脑时,它拒绝渲染任何内容。 我有以下渲染代码: GL20.glUseProgram(pId);System.out.println(“NO Error? ” (GL11.glGetError() == GL11.GL_NO_ERROR));

    • 我正在使用spring boot尝试建立自己的迷你网站。 我有控制器 还有一个html文件resources/templates/index,我正试图呈现它,但我只呈现了文本“index”。如何返回html文件而不是文本?

    • 在讲述有关list的时候,提到做游戏的事情,后来这个事情一直没有接续。不是忘记了,是在想在哪个阶段做最合适。经过一段时间学习,看官已经不是纯粹小白了,已经属于python初级者了。现在就是开始做那个游戏的时候了。 游戏内容:猜数字游戏 太简单了吧。是的,游戏难度不大,不过这个游戏中蕴含的东西可是值得玩味的。 游戏过程描述 程序运行起来,随机在某个范围内选择一个整数。 提示用户输入数字,也就是猜程序

    • 下面的代码完整展示了通过three.js引擎创建的一个三维场景,在场景中绘制并渲染了一个立方体的效果,为了大家更好的宏观了解three.js引擎, 尽量使用了一段短小但完整的代码实现一个实际的三维效果图。 学习建议 刚一开始学习,不需要完全看懂下面的代码,能够修改增删部分代码就可以,随着时间的推移就能够很好的使用三维引擎three.js。 本课程风格和大多数课程风格不同,注意一定要结合案例代码学习

    • 下面的LWJGL代码将在屏幕中心呈现一个蓝色正方形。相反,我得到了一个空白的白色屏幕。就像渲染根本不工作,或者我在屏幕外渲染。 我是OpenGL和LWJGL的新手,所以我力不从心。我浏览了所有内容,但似乎找不到任何可能与代码有关的问题。 OpenGLTest.scala VertexArray.scala