OpenGL 减慢 5k 点
OpenGL slows for 5k points
我正在编写一个 SLAM 库并希望使用 OpenGL 可视化它的工作。我需要绘制大约 10 万个点和几百个矩形,我希望 OpenGL 可以轻松处理它。但是,在点数达到 5k 后,我的程序变慢了。
我是 OpenGL 的新手,所以我想我做事的方式不对。我用 this tutorial 来学习。
随着程序的运行,它吐出某些事件,其中只有少数相关:
- 创建点(size_t id, float x,y,z;)
- 点更新 (szie_t id, float x,y,z;)
- 位置估计(四元数 Q,Vector3D T)
可视化这些事件(简化)的程序部分的工作方式如下。
我们给每个点分配一个GL_ARRAY_BUFFER。为了不在每次获得新点时都分配新的缓冲区,我决定保留一个缓冲区存储库。当一个新点到达时,我们从存储库中为其分配一个“空闲”缓冲区。仅当 repo 为空时,我们才使用 glGenBuffers
.
分配一个新缓冲区
std::stack<GLuint> point_buffer_stack;
std::map<size_t, GLuint> active_points;
void OnPointCreated(size_t id, float x, float y, float z ){
GLuint point_buffer_id;
if(point_buffer_stack.empty()){
glGenBuffers(1, &point_buffer_id);
}
else {
point_buffer_id = point_buffer_stack.top();
point_buffer_stack.pop();
}
active_points[id] = point_buffer_id;
OnPointUpdated(id, x, y, z);
}
void OnPointUpdated(size_t id, float x, float y, float z){
GLuint point_buffer_id = active_points[id];
float buffer[3] = {x,y,z};
glBindBuffer(GL_ARRAY_BUFFER, point_buffer_id);
glBufferData(GL_ARRAY_BUFFER, sizeof(buffer), buffer, GL_STATIC_DRAW);
}
void OnPointDeleted(size_t id){
GLuint point_buffer_id = active_points[id];
point_buffer_stack.push(point_buffer_id);
active_points.erase(id);
}
仅在位置更新时绘制边框:
void OnPositionUpdated (const glm::mat4 & projection){
glm::mat4 model_view_projection;
/* Compute model_view_projection and set the corresponding UniformMatrix4fv for using in the vertex shader */
// Draw points
glEnableVertexAttribArray(0);
for(const auto & id_vertex: active_points){
glBindBuffer(GL_ARRAY_BUFFER, id_vertex.second);
glVertexAttribPointer(
0, // layout from vertex shader.
3, // 3D
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void *) 0 // array buffer offset
);
glDrawArrays(GL_POINTS, 0, 1);
}
glDisableVertexAttribArray(0);
/*Draw a rectangle that shows the current position by drawing two triangles */
glfwSwapBuffers(window);
glfwPollEvents();
}
在我的带有英特尔® Xe 显卡的华硕 Zenbook 上,Ubuntu 20.04,OpenGL 开始落后于相机约 5k 点。一段时间后,我从 OpenCV(使用 OpenGL 支持构建)收到内存不足错误。
这是预期的吗?我究竟做错了什么?如何解决这个问题?
供参考,OpenGL的初始化如下:
glfwInit();
glfwWindowHint(GLFW_SAMPLES, 4);
glfwWindowHint(GLFW_DOUBLEBUFFER, GLFW_TRUE);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // To make MacOS happy; should not be needed
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
window = glfwCreateWindow(1920, 1080, "SLAM 3D visualization", NULL, NULL);
We assign a GL_ARRAY_BUFFER to each point.
那是你的问题。这意味着您正在为所有 12 字节的内存分配一个完整的缓冲区对象。将每个点放入其自己的缓冲区 也 意味着您必须使用单独的绘制调用渲染每个点。
None 是性能的秘诀。
为您打算使用的所有点创建一个大缓冲区,并通过一次绘制调用渲染它们。如果您需要更改点之间的参数或其他内容,请将它们设为单独的顶点属性。或者失败了,让它们统一到你的着色器并渲染所有使用一组参数的点,改变统一,然后渲染下一个使用新参数的点,等等。
我正在编写一个 SLAM 库并希望使用 OpenGL 可视化它的工作。我需要绘制大约 10 万个点和几百个矩形,我希望 OpenGL 可以轻松处理它。但是,在点数达到 5k 后,我的程序变慢了。
我是 OpenGL 的新手,所以我想我做事的方式不对。我用 this tutorial 来学习。
随着程序的运行,它吐出某些事件,其中只有少数相关:
- 创建点(size_t id, float x,y,z;)
- 点更新 (szie_t id, float x,y,z;)
- 位置估计(四元数 Q,Vector3D T)
可视化这些事件(简化)的程序部分的工作方式如下。
我们给每个点分配一个GL_ARRAY_BUFFER。为了不在每次获得新点时都分配新的缓冲区,我决定保留一个缓冲区存储库。当一个新点到达时,我们从存储库中为其分配一个“空闲”缓冲区。仅当 repo 为空时,我们才使用 glGenBuffers
.
std::stack<GLuint> point_buffer_stack;
std::map<size_t, GLuint> active_points;
void OnPointCreated(size_t id, float x, float y, float z ){
GLuint point_buffer_id;
if(point_buffer_stack.empty()){
glGenBuffers(1, &point_buffer_id);
}
else {
point_buffer_id = point_buffer_stack.top();
point_buffer_stack.pop();
}
active_points[id] = point_buffer_id;
OnPointUpdated(id, x, y, z);
}
void OnPointUpdated(size_t id, float x, float y, float z){
GLuint point_buffer_id = active_points[id];
float buffer[3] = {x,y,z};
glBindBuffer(GL_ARRAY_BUFFER, point_buffer_id);
glBufferData(GL_ARRAY_BUFFER, sizeof(buffer), buffer, GL_STATIC_DRAW);
}
void OnPointDeleted(size_t id){
GLuint point_buffer_id = active_points[id];
point_buffer_stack.push(point_buffer_id);
active_points.erase(id);
}
仅在位置更新时绘制边框:
void OnPositionUpdated (const glm::mat4 & projection){
glm::mat4 model_view_projection;
/* Compute model_view_projection and set the corresponding UniformMatrix4fv for using in the vertex shader */
// Draw points
glEnableVertexAttribArray(0);
for(const auto & id_vertex: active_points){
glBindBuffer(GL_ARRAY_BUFFER, id_vertex.second);
glVertexAttribPointer(
0, // layout from vertex shader.
3, // 3D
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void *) 0 // array buffer offset
);
glDrawArrays(GL_POINTS, 0, 1);
}
glDisableVertexAttribArray(0);
/*Draw a rectangle that shows the current position by drawing two triangles */
glfwSwapBuffers(window);
glfwPollEvents();
}
在我的带有英特尔® Xe 显卡的华硕 Zenbook 上,Ubuntu 20.04,OpenGL 开始落后于相机约 5k 点。一段时间后,我从 OpenCV(使用 OpenGL 支持构建)收到内存不足错误。
这是预期的吗?我究竟做错了什么?如何解决这个问题?
供参考,OpenGL的初始化如下:
glfwInit();
glfwWindowHint(GLFW_SAMPLES, 4);
glfwWindowHint(GLFW_DOUBLEBUFFER, GLFW_TRUE);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // To make MacOS happy; should not be needed
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
window = glfwCreateWindow(1920, 1080, "SLAM 3D visualization", NULL, NULL);
We assign a GL_ARRAY_BUFFER to each point.
那是你的问题。这意味着您正在为所有 12 字节的内存分配一个完整的缓冲区对象。将每个点放入其自己的缓冲区 也 意味着您必须使用单独的绘制调用渲染每个点。
None 是性能的秘诀。
为您打算使用的所有点创建一个大缓冲区,并通过一次绘制调用渲染它们。如果您需要更改点之间的参数或其他内容,请将它们设为单独的顶点属性。或者失败了,让它们统一到你的着色器并渲染所有使用一组参数的点,改变统一,然后渲染下一个使用新参数的点,等等。