我正在编写一个SLAM库,并希望使用 OpenGL 可视化其工作。我需要绘制大约 100k 个点和几百个矩形,我希望 OpenGL 可以轻松处理它。然而,当点数达到 5k 后,我的程序速度变慢。
\n我是 OpenGL 新手,所以我想我没有以正确的方式做事。我使用这个教程来学习。
\n当程序运行时,它会输出某些事件,其中只有少数是相关的:
\n程序中可视化这些事件的部分(简化)的工作原理如下。
\n我们为每个点分配一个 GL_ARRAY_BUFFER。为了不在每次获得新点时分配新的缓冲区,我决定保留一个缓冲区存储库。当新点到达时,我们从存储库中为其分配一个“空闲”缓冲区。仅当存储库为空时,我们才分配一个新的缓冲区glGenBuffers。
std::stack<GLuint> point_buffer_stack;\nstd::map<size_t, GLuint> active_points;\n\nvoid OnPointCreated(size_t id, float x, float y, float z ){\n GLuint point_buffer_id;\n if(point_buffer_stack.empty()){\n glGenBuffers(1, &point_buffer_id);\n }\n else {\n point_buffer_id = point_buffer_stack.top();\n point_buffer_stack.pop(); \n }\n active_points[id] = point_buffer_id;\n\n OnPointUpdated(id, x, y, z);\n \n}\n\nvoid OnPointUpdated(size_t id, float x, float y, float z){\n GLuint point_buffer_id = active_points[id];\n float buffer[3] = {x,y,z};\n glBindBuffer(GL_ARRAY_BUFFER, point_buffer_id);\n glBufferData(GL_ARRAY_BUFFER, sizeof(buffer), buffer, GL_STATIC_DRAW); \n}\n\nvoid OnPointDeleted(size_t id){\n GLuint point_buffer_id = active_points[id];\n point_buffer_stack.push(point_buffer_id);\n active_points.erase(id);\n}\n \nRun Code Online (Sandbox Code Playgroud)\n仅在位置更新时绘制框架:
\nvoid OnPositionUpdated (const glm::mat4 & projection){\n glm::mat4 model_view_projection;\n /* Compute model_view_projection and set the corresponding UniformMatrix4fv for using in the vertex shader */\n\n // Draw points \n glEnableVertexAttribArray(0);\n for(const auto & id_vertex: active_points){\n glBindBuffer(GL_ARRAY_BUFFER, id_vertex.second);\n glVertexAttribPointer(\n 0, // layout from vertex shader.\n 3, // 3D\n GL_FLOAT, // type\n GL_FALSE, // normalized?\n 0, // stride\n (void *) 0 // array buffer offset\n );\n glDrawArrays(GL_POINTS, 0, 1);\n }\n glDisableVertexAttribArray(0);\n\n /*Draw a rectangle that shows the current position by drawing two triangles */\n\n glfwSwapBuffers(window);\n glfwPollEvents();\n}\nRun Code Online (Sandbox Code Playgroud)\n在我的配备 Intel\xc2\xae Xe Graphics、Ubuntu 20.04 的 Asus Zenbook 上,OpenGL 开始落后于相机大约 5k 点。一段时间后,我从 OpenCV(使用 OpenGL 支持构建)收到内存不足的错误。
\n这是预期的吗?我究竟做错了什么?如何解决这个问题?
\n作为参考,OpenGL的初始化如下:
\nglfwInit();\nglfwWindowHint(GLFW_SAMPLES, 4);\nglfwWindowHint(GLFW_DOUBLEBUFFER, GLFW_TRUE);\nglfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);\nglfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);\nglfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // To make MacOS happy; should not be needed\nglfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);\n\nwindow = glfwCreateWindow(1920, 1080, "SLAM 3D visualization", NULL, NULL);\nRun Code Online (Sandbox Code Playgroud)\n
我们为每个点分配一个 GL_ARRAY_BUFFER。
那是你的问题。这意味着您正在为所有 12 字节内存分配整个缓冲区对象。将每个点放入其自己的缓冲区中还意味着您必须使用单独的绘制调用来渲染每个点。
这些都不是提高绩效的秘诀。
为您想要使用的所有点创建一个大缓冲区,并通过一次绘制调用渲染它们。如果您需要更改点之间的参数或某些内容,请将它们设为单独的顶点属性。或者如果失败,请将它们设置为着色器的制服,并渲染使用一组参数的所有点,更改制服,然后渲染使用新参数的下一个点,等等。