0

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

例如,点击纯红色给了我(-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 并测试点击了哪个像素颜色。提前感谢任何可以提供帮助的人!

4

2 回答 2

1

终于找到问题所在了!

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

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

感谢您的帮助和想法!

于 2018-08-25T11:21:45.903 回答
0

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

编辑

1) 您已要求提供GL_UNSIGNED_BYTE来自 的数据glReadPixels(),但您正在以签名格式打印出来。GL_UNSIGNED_BYTE有 0-256 的值,所以不可能有负值!尝试格式化您的打印​​输出UNSIGNED_BYTE并查看其导致的位置。(从您的代码中我可以看到现在已修复)。

2) 正如 derhass 在他的评论中指出的那样,你不应该使用 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

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

于 2018-08-24T07:20:33.370 回答