在开发过程中,基于OpenGL的点云渲染器遇到了一个非常令人不安的问题。
我的第一种方法是直接可视化点云 - 在一个DrawArrays()命令中,我渲染了超过1500万点云。一切都很好,直到我的VRAM上有足够的内存来存储整点云 - 如果不是我从Nvidia OpenGL驱动程序收到错误,告诉我我的计算机不符合应用程序规范。
所以我已经搜索了一下,我已经知道我必须将我的点云划分为多个块并为每个块调用DrawArray()。因此,为了测试它,我创建了一个包含大约60 000个点的点云,我正在加载数百次以模拟前面描述的行为。
在调用次数而不是OpenGL驱动程序错误后,我的opengl窗口变为黑色。当我将一个块中的点数更改为40 000时,我设法加载并显示超过600万个没有黑屏的点。
所以我有很多问题:
为什么会出现这样的事情?
我该如何避免这种行为?
我如何预测这种行为?
为什么会出现这样的事情时没有opengl错误(是的,我已经检查过)?
我的点云基本上是:
std::vector<Point3D<float>> vfLXYZ;
std::vector<Point4D<unsigned char>> vucRGBA;
其中:
template <class T>
union Point4D
{
T data[4];
struct{
T R;
T G;
T B;
T A;
};
};
template <class T>
union Point3D
{
T data[3];
struct{
T x;
T y;
T z;
};
};
OpenGL上下文创建:
bool OpenGLContext::create30Context(HDC hdc) {
this->hdc = hdc;
PIXELFORMATDESCRIPTOR pfd;
memset(&pfd, 0, sizeof(PIXELFORMATDESCRIPTOR));
pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
pfd.dwFlags = PFD_DOUBLEBUFFER | PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 32;
pfd.cDepthBits = 32;
pfd.iLayerType = PFD_MAIN_PLANE;
int nPixelFormat = ChoosePixelFormat(hdc, &pfd);
if (nPixelFormat == 0)
return false;
bool bResult = SetPixelFormat(hdc, nPixelFormat, &pfd);
if (!bResult)
return false;
HGLRC tempOpenGLContext = wglCreateContext(hdc);
wglMakeCurrent(hdc, tempOpenGLContext); /
GLenum error = glewInit();
if (error != GLEW_OK)
return false;
int attributes[] = {
WGL_CONTEXT_MAJOR_VERSION_ARB, 4,
WGL_CONTEXT_MINOR_VERSION_ARB, 2,
WGL_CONTEXT_FLAGS_ARB,WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB,
WGL_CONTEXT_PROFILE_MASK_ARB,WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
0
};
if (wglewIsSupported("WGL_ARB_create_context") == 1) {
hrc = wglCreateContextAttribsARB(hdc, NULL, attributes);
wglMakeCurrent(NULL, NULL);
wglDeleteContext(tempOpenGLContext);
wglMakeCurrent(hdc, hrc);
}
else {
hrc = tempOpenGLContext;
return false;
}
int glVersion[2] = { -1, -1 }; /
glGetIntegerv(GL_MAJOR_VERSION, &glVersion[0]);
glGetIntegerv(GL_MINOR_VERSION, &glVersion[1]);
return true;
}
缓冲区初始化(遍历所有点云):
glBindVertexArray(pxCloudHeader.uiVBA);
glBindBuffer(GL_ARRAY_BUFFER, pxCloudHeader.xVBOs.uiVBO_XYZ);
glBufferData(GL_ARRAY_BUFFER, iPointCount * sizeof(GLfloat) * 3, &p3DfXYZ->data[0], GL_STREAM_DRAW);
glVertexAttribPointer((GLuint)0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, pxCloudHeader.xVBOs.uiVBO_RGBA);
glBufferData(GL_ARRAY_BUFFER, iPointCount * sizeof(GLubyte) * 4, &p4DfRGBA->data[0], GL_STREAM_DRAW);
glVertexAttribPointer((GLuint)1, 4, GL_UNSIGNED_BYTE, GL_FALSE, 0, 0);
glEnableVertexAttribArray(1);
glBindVertexArray(0);
点云渲染(遍历所有点云):
glBindVertexArray(pxCloudHeader.uiVBA);
// iLOD is a Level Of Detail
glBindBuffer(GL_ARRAY_BUFFER, pxCloudHeader.xVBOs.uiVBO_XYZ);
glVertexAttribPointer((GLuint)0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float) * iLOD, 0);
glBindBuffer(GL_ARRAY_BUFFER, pxCloudHeader.xVBOs.uiVBO_RGBA);
glVertexAttribPointer((GLuint)1, 4, GL_UNSIGNED_BYTE, GL_FALSE, 4 * sizeof(unsigned char)*iLOD, 0);
glDrawArrays(GL_POINTS, 0, pxCloudHeader.iPointsCount / iLOD);
glBindVertexArray(0);
主要渲染功能:
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
glClearDepth(fFar);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
RenderPointCloud();
SwapBuffers(hdc);
我的渲染代码很简单,所以我发布了一些我认为可以解决问题的东西。如果你想了解更多(着色器代码等),请写评论,我将编辑我的帖子。我向你保证,除了这个问题,渲染效果还不错。
另外我注意到当我的opengl窗口黑色应用程序没有停止工作时 - 点云渲染循环正在执行bu MUCH SLOWER而不是预期。此外,我的单线程应用程序开始表现得像双线程 - 它消耗的CPU使用率是黑窗口崩溃前的两倍。
其他一些信息:
我正在使用VS2013和x64编译器,
拥有32GB内存,
拥有2 GB VRAM(GeForce GTX 760M),
拥有最新的图形卡驱动程序