我不知道是否有可能
我进行了很多搜索,但是我看到的所有解决方案都使用memcpy,如下所示:
m_vboPos.bind();
GLfloat* PosBuffer = (GLfloat*) (m_vboPos.map(QOpenGLBuffer::WriteOnly));
if (PosBuffer != (GLfloat*) NULL) {
memcpy(PosBuffer, m_Vertices.constData(), m_Vertices.size() * sizeof(QVector3D));
m_vboPos.unmap();
m_vboPos.release();
但这是要复制个数据块。
我不认为使用memcpy在每个相关顶点中仅更改1个浮点值会非常有效(我在VBO中拥有数百万个顶点)。
我想进行优化,因为复制数百万个顶点需要(太)长时间:是否有一种方法可以实现我的目标(没有memcpy?),因为这里和那里只有一个浮点数? (已经尝试过但无法做到,我必须丢失一些东西)
答案 0 :(得分:1)
此电话
GLfloat* PosBuffer = (GLfloat*) (m_vboPos.map(QOpenGLBuffer::WriteOnly));
将在内部调用glMapBuffer
,这意味着它只是将缓冲区内容映射到进程的地址空间中(另请参见OpenGL Wiki on Buffer Object Mapping。
由于您将其映射为只写,因此您可以根据需要简单地覆盖缓冲区的每一位。无需使用memcpy
,您可以使用任何方式写入内存,例如你可以直接做
PosBuffer[3*vertex_id + 2] = 42.0f; // assuming 3 floats per vertex
我不认为使用
memcpy
在每个相关顶点中仅更改1个浮点值会非常有效(我在VBO中拥有数百万个顶点)。
是的,对每个4个字节分别进行一百万次memcpy()
调用不是一个好主意。一个现代的编译器实际上可以内联它,因此,它可能仅等效于单个分配。但是您也可以直接进行分配,因为memcpy
在这里没有给您带来任何好处。
但是,尚不清楚所有这些对性能的影响。 glMapBuffer
可能会返回指向的指针
映射本身也不是免费的,它涉及更改页表,GL驱动程序可能必须同步其线程,或者在最坏的情况下,与GPU同步(以防止覆盖GPU的内容)仍在用于仍在进行中的上一个抽奖电话中。
有时我只想修改(x1,y1)和(x2,y2)值之间的一系列顶点的z值-有关顶点严格遵循彼此
因此,您有一个要修改的缓冲区的连续子区域。我建议看一下两种选择:
使用glMapBufferRange
(如果在OpenGL版本中可用)来仅映射您关心的区域。
完全忘记缓冲区映射,请尝试glBufferSubData()
。不是单独出现在每个顶点的每个z
组件上,而是整个修改顶点范围内的一大垃圾。这将意味着您在某个位置的内存中有缓冲区内容的本地副本,只需进行更新,然后将结果发送到GL。
哪种选择更好,将取决于许多不同的因素,如果您不关心实际方案中的基准,我也不会排除其中一个因素,而是取决于您关心的实际实现。还可以查看Buffer Object Streaming in OpenGL的一般策略。对于您的用例,persistently mapped buffer可能不是一个好的选择。
答案 1 :(得分:1)
glMap方法效果很好,而且非常快!
非常感谢genpfault,速度增益是如此之大,以至于3D渲染不再是断断续续的。
这是我的新代码,经过简化以提供易于理解的答案:
vertexbuffer.bind();
GLfloat* posBuffer = (GLfloat*) (vertexbuffer.map(QOpenGLBuffer::WriteOnly));
if (posBuffer != (GLfloat*) NULL) {
int index = NumberOfVertices(area.y + 1, image.cols); // index of first vertex on line area.y
for (row = ...) for (col = ...) {
if (mask.at<uchar>(row, col) != 0)
posBuffer[3 * index + 2] = depthmap.at<uchar>(row, col) * depth;
index++;
}
}
vertexbuffer.unmap();
vertexbuffer.release();