OpenGL glBufferSubData 偏移问题
Posted
技术标签:
【中文标题】OpenGL glBufferSubData 偏移问题【英文标题】:OpenGL glBufferSubData Offset issue 【发布时间】:2020-06-13 04:46:38 【问题描述】:我在使用 glBufferSubData() 将所有数据复制/上传到缓冲区时遇到问题。我想逐块复制到缓冲区。所以我使用了这种方法。当我尝试渲染时,我看到一个空白屏幕。请在下面找到我的代码。您在计算缓冲区偏移量时看到任何问题吗?或者这不是将数据复制到缓冲区的方法吗?
下面是数据结构
struct DisplayIndexID
int idx;
DrawStateT drawState;
//Every display Index ID has its own draw models.
std::vector<std::unique_ptr<vertexModel>> readytoDrawModels;
;
void initVboData(std::vector<DisplayIndexID> & v)
glBindBuffer(GL_ARRAY_BUFFER, geomVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(QVector3D) * 4096, NULL, GL_DYNAMIC_DRAW);
std::vector<QVector3D> vecToDraw;
GLintptr offset = 0;
for (int i = 0; i < v.size(); i++)
for (auto& vModel : v[i].readytoDrawModels)
if (vModel)
vecToDraw = vModel->getVertices();
glBufferSubData(GL_ARRAY_BUFFER, offset, sizeof(QVector3D) * vecToDraw.size(), &vecToDraw[0]);
offset += sizeof(QVector3D) * vecToDraw.size(); // is this offset calculation fine?
//Below is my draw function
void drawDisplayLists(std::vector<DisplayIndexID> & v)
initVboData(v);
for (int i = 0; i < v.size(); i++)
//Make context current
makeCurrent();
bool isTextureUsed = false;
//Apply Projection Matrix.
GLint mvp_mat = 0;
GLint mvp_matText = 0;
///***********PRINT AREA***********************/
for (auto& vModel : v[i].readytoDrawModels)
// Code related to Shaders
......
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(QVector3D), nullptr); how to get the offset and add offset here.
switch (vModel->getDrawMode())
case 0: //GL_POINTS
glDrawArrays(GL_POINTS, 0, vModel->getVertices().size());
break;
case 1: //GL_LINES
glDrawArrays(GL_LINES, 0, vModel->getVertices().size());
break;
case 2: //GL_LINE_LOOP
glDrawArrays(GL_LINE_LOOP, 0, vModel->getVertices().size());
break;
【问题讨论】:
您的drawDisplayLists()
与 initVboData()
不匹配 - 您突然在方法中使用了 vModel
变量 undefined。如果drawDisplayLists()
以与初始化相同的方式迭代v
,则应在循环中使用偏移量调用glVertexAttribPointer()
。请在报价中添加缺失的代码。
非常感谢。我已经在编辑部分更新了我的代码。是的,甚至 drawDisplayLists() 以与初始化相同的方式迭代 v。请让我知道如何为 glVertexAttribPointer() 调用添加偏移量。谢谢,非常感谢。
@gkv311 “那么 glVertexAttribPointer() 应该在循环中使用偏移量调用” - 抱歉,这是错误的。只有顶点坐标,所以不需要偏移。如果要绘制网格的特定区域,则必须在 glDrawArrays
处指定偏移量和不同的大小
谢谢大家。如果我将 glBufferSubData() 移动到 for 循环下的 drawDisplayList() 内,它就可以工作。但我不想每帧都复制块。这可能会影响性能。所以我想到了之前复制它并在框架开始之前准备好它。有什么办法可以做到这一点吗?因为我的顶点不会改变。一切都存储在向量中。我还尝试使用 glBufferData() 复制整个缓冲区。这没有用。如何解决这个问题?非常感谢。
@Rabbid76 glVertexAttribPointer()
和 glDrawArrays()
都可用于指定偏移量 - 执行此操作的位置取决于条件。如果可能,将偏移量传递给glDrawArrays()
可能会减少一点开销。
【参考方案1】:
考虑到您已经像这样初始化了持久 VBO:
GLintptr offset = 0;
for (int i = 0; i < v.size(); i++)
for (auto& vModel : v[i].readytoDrawModels)
if (vModel)
vecToDraw = vModel->getVertices();
glBufferSubData(GL_ARRAY_BUFFER, offset, sizeof(QVector3D) * vecToDraw.size(), &vecToDraw[0]);
offset += sizeof(QVector3D) * vecToDraw.size();
那么您应该在绘图循环中复制相同的偏移量。
这可以通过将字节偏移量传递给glVertexAttribPointer()
来完成,其计算方式与 VBO 初始化期间完全相同:
GLintptr offset = 0;
for (int i = 0; i < v.size(); i++)
for (auto& vModel : v[i].readytoDrawModels)
if (vModel)
vecToDraw = vModel->getVertices();
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(QVector3D), offset);
glDrawArrays(GL_LINES, 0, vecToDraw.size());
offset += sizeof(QVector3D) * vecToDraw.size();
或通过将顶点数量的偏移量传递给glDrawArrays()
,以防所有模型具有与您的代码 sn-p (in vec3 Position
) 中相同的顶点定义:
GLintptr aFirstIndex = 0;
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(QVector3D), nullptr);
for (int i = 0; i < v.size(); i++)
for (auto& vModel : v[i].readytoDrawModels)
if (vModel)
vecToDraw = vModel->getVertices();
glDrawArrays(GL_LINES, aFirstIndex, vecToDraw.size());
aFirstIndex += vecToDraw.size();
确保分配的 VBO 具有适当的大小,并将 4096 替换为实际大小:
glBufferData(GL_ARRAY_BUFFER, sizeof(QVector3D) * 4096, NULL, GL_DYNAMIC_DRAW);
顺便说一句,按GL_POINTS
/GL_LINES
数组类型和相同的表示属性(颜色/材质/等)对模型进行分组将允许使用单个glDrawArrays()
调用来渲染每个组,而不是大量的glDrawArrays()
对于每个模型,从性能的角度来看,这将是更优化的。
【讨论】:
非常感谢@gkv311。有效。惊人的 !性能也有所提升。以上是关于OpenGL glBufferSubData 偏移问题的主要内容,如果未能解决你的问题,请参考以下文章
在 OpenGL ES Android 中使用 glBufferSubData 和 glMultiDrawArrays
OpenGL glBufferSubData - 无法让它工作
为啥 glBufferSubData 需要等到 glDrawElements 不使用 VBO?