【问题标题】:What does the PBO buffer content mean?PBO 缓冲区内容是什么意思?
【发布时间】:2019-01-30 12:27:35
【问题描述】:

我试图通过使用 PBO(使用 OpenGL 的像素缓冲区对象)来实现颜色拾取系统,当我完成时,我意识到映射时从 PBO 出来的数字根本没有任何意义。我让我的应用程序渲染不同颜色的大方块,结果DID在这些不同颜色之间变化,但即使分析了数字,我也无法理解。

例如,点击纯红色给了我字节 (-1,0,0),虽然纯蓝色给出 (0,0,-1),但违反所有逻辑,纯绿色给出 (-1,0,-1),青色也给出 (-1,0,0 ),黄色给出 (76,-1,0)。

显然这些数字是错误的,因为两种不同的颜色会导致相同的字节结构。完全红色不应该是 (127,0,0) 吗?

这是我用于初始化的代码,大小为 3,因为我只读取一个像素。

pboid = glGenBuffersARB(); //Initialize buffer for pbo
glBindBufferARB(GL_PIXEL_PACK_BUFFER_EXT, pboid); //bind buffer
glBufferDataARB(GL_PIXEL_PACK_BUFFER_EXT, 3,GL_DYNAMIC_READ); //create a pbo with 3 slots
glBindBufferARB(GL_PIXEL_PACK_BUFFER_EXT, 0); //unbind buffer

这是我用来读取像素的代码

glBindBufferARB(GL_PIXEL_PACK_BUFFER_EXT, pboid); //Bind the pbo
glReadPixels((int)lastMousePosition.x,(int)lastMousePosition.y,1,1, GL_RGB, GL_UNSIGNED_BYTE, 0); //Read 1 pixel
ByteBuffer colorBuffer = glMapBufferARB(GL_PIXEL_PACK_BUFFER_EXT, GL_READ_ONLY_ARB); //Map the buffer so we can read it
for(int x = 0; x < colorBuffer.limit(); x++)
{
    System.out.println("color byte: " + colorBuffer.get(x)); //Print out the color byte
}
glUnmapBufferARB(GL_PIXEL_PACK_BUFFER_EXT); //Unmap the buffer so it can be used again
glBindBufferARB(GL_PIXEL_PACK_BUFFER_EXT, 0); //Unbind the pbo

如果我所做的任何假设有误,请纠正我。我可能计划使用这个系统来判断哪个 gui 元素被点击,方法是将它们中的每一个渲染到具有唯一颜色的 fbo 并测试点击了哪个像素颜色。提前感谢任何可以提供帮助的人!

【问题讨论】:

  • 我发送了一些想法。此外,如果您发现我的回答有帮助,您可以考虑通过单击答案左侧的赞成/反对箭头下方的“勾选”来接受答案:-)。这样做可以鼓励响应者提供帮助 - 但您没有义务接受
  • glReadPixels 会产生 GL 错误吗?你确定你的颜色应该在读取位置,而不是在读取和缓冲区交换之间绘制吗?你可以吗?从前端缓冲区读取? -1 值看起来是正确的,因为您从 GL 请求无符号字节,但 java 只有有符号字节(但应该有将其转换为无符号 int 的函数)。
  • 我的猜测是您忘记将鼠标坐标从默认窗口系统约定(原点在左上角)转换为 GL 约定(原点在左下角)。此外,正如答案中已经指出的那样,将无符号值打印为有符号会导致一些混乱。但我还有其他问题:您为什么要使用古老的 ARB 和 EXT 扩展?十年前,这些东西就在核心 GL 中。但这也是一个有争议的问题,因为:你为什么要使用 PBO?你使用它的方式只会增加巨大的开销,而且你仍然会强制 CPU-GPU 完全同步。

标签: java opengl pbo


【解决方案1】:

有几种可能性,但我没有设置我的 openGL 系统来测试 - 但无论如何你都可以尝试这些。另外我不太了解 Java(C、C++ 等是我的领域)

编辑

1) 您已从glReadPixels() 请求GL_UNSIGNED_BYTE 数据,但您正在以签名格式打印出来。 GL_UNSIGNED_BYTE 的值是 0-256,所以不可能有负值!尝试将您的打印输出格式化为UNSIGNED_BYTE,然后看看它会导致什么。 (从您的代码中我可以看到现在已修复)。

2) 正如 derhass 在他的 cmets 中指出的那样,您不应该使用 OpenGL 缓冲区函数的 ARB(架构审查委员会)扩展版本,因为它们在很长一段时间内都是 OpenGL 核心的一部分。有关版本历史记录,请参阅 https://www.khronos.org/opengl/wiki/History_of_OpenGL。从这里我可以看到 glBindBufferARB(例如)在 2003 年被弃用。它可能会或不会影响您的特定问题,但是将 glXXXXXARB() 彻底替换为 glXXXXX(),并确保您的 OpenGL 库是最新的(v4 或更高版本)。

3) 还归功于derhass,并阅读您的GitHub代码,您的getMousePosition() 通过glfwGetCursorPos 返回屏幕坐标(0,0 是窗口的左上角),因此您需要转换为视口坐标(0,0 是左下角) 读取帧缓冲区。您在 GitHub 上的代码似乎没有进行转换。

4) 还要归功于derhass,您根本不需要使用 PBO 来进行基本的颜色选择。 glReadPixels() 默认目标是帧缓冲区,因此您可以安全地省去 VBO 并直接从帧缓冲区获取颜色、深度和模板数据。 (您需要启用深度和模板缓冲区)。

5) 如果您在 3D 场景上进行选择,您还需要将视口坐标和深度转换(取消投影)回世界坐标,以便能够识别您单击了哪个对象。有关选择的一些想法,请参阅https://en.wikibooks.org/wiki/OpenGL_Programming/Object_selection。

我希望这一切都能有所帮助,尽管这对我们俩来说都是一种学习体验。

【讨论】:

  • @keltar Ah 不知道这个 - 有一段时间了.. 这是在哪里记录的?
  • 第 1 点已经被其他人反驳了,至于第 3 点,缓冲区不为空,如果是,Java 会给出 NullPointerException,我正在通过方法从中获取数据。
  • 嗯,我们正在寻找线索.... 我使用的可靠策略 1) 是制作尽可能小的程序来重现问题 2) 知道如果一切正确,它将起作用。还要检查 khronos.org/opengl/wiki/Common_Mistakes> 因为这也说明了 glGetPixels 的打包问题。有时调试是纯粹的持久性,记住第 2 点)。
【解决方案2】:

终于找到问题了!

首先,使用 Byte.toUnsignedInt(byte),您可以将 pbo 为您提供的颜色转换为传统的 0-255 范围 rgb 数字。

其次,这是主要问题,当 OpenGL 要求像素坐标来填充 pbo 时,它是相对于右下角的。我的问题是我使用的是 GLFW,它给出了相对于右上角的坐标,这意味着在屏幕垂直中间的颜色选择是准确的,但是当我在其他地方选择颜色时,它得到了我正在寻找的屏幕的反面部分。要解决此问题,只需从窗口高度中减去鼠标单击的 y 坐标即可。

感谢您的帮助和想法!

【讨论】:

  • 特别看一下 VBO 和 ARB 扩展上的 cmets
猜你喜欢
  • 2010-10-13
  • 2013-02-09
  • 1970-01-01
  • 2021-11-19
  • 2014-06-11
  • 2020-07-21
  • 1970-01-01
  • 2014-03-27
  • 1970-01-01
相关资源
最近更新 更多