调用glDrawArrays后出现SegFault

SegFault after calling glDrawArrays

本文关键字:SegFault glDrawArrays 调用      更新时间:2023-10-16

我正在尝试编写一个sprite批处理程序。最初,我将以下数据上传到openGL,以查看是否可以在屏幕上显示任何内容:

static GLfloat const vertexData[] = {
//Position                  //Color                 //UV Coords
0.5f, 0.5f,             1.0f, 1.0f, 1.0f, 1.0f,     1.0f, 1.0f,
-0.5f, 0.5f,            1.0f, 1.0f, 1.0f, 1.0f,     0.0f, 1.0f,
0.5f, -0.5f,            1.0f, 1.0f, 1.0f, 1.0f,     1.0f, 0.0f,
-0.5f, -0.5f,           1.0f, 1.0f, 1.0f, 1.0f,     0.0f, 0.0f,
-0.5f, 0.5f,            1.0f, 1.0f, 1.0f, 1.0f,     0.0f, 1.0f,
0.5f, -0.5f,            1.0f, 1.0f, 1.0f, 1.0f,     1.0f, 0.0f
};

这些是我的顶点和片段着色器:

const char* vert = "#version 330 coren"
"layout (location = 0) in vec2 vPos;n"
"layout (location = 1) in vec4 vColor;n"
"layout (location = 2) in vec2 vTexPos;n"
"n"
"out vec4 fColor;n"
"out vec2 fTexPos;n"
"n"
"void main() {n"
"    gl_Position = vec4(vPos.xy, 0.0, 1.0);n"
"    fColor = vColor;n"
"    fTexPos = vec2(vTexPos.s, 1.0 - vTexPos.t);n"
"}";


const char* frag = "#version 330 coren"
"in vec4 fColor;n"
"in vec2 fTexPos;n"
"out vec4 finalColor;n"
"n"
"uniform sampler2D textureUniform;n"
"n"
"void main() {n"
"  vec4 textureColor = texture(textureUniform, fTexPos);"
"  finalColor = fColor * textureColor;n"
"}";

我这样设置VAO和VBO:

auto vaoID_ = 0;
auto vboID_ = 0;
glGenVertexArrays(1, &vaoID_);
glGenBuffers(1, &vboID_);
glBindVertexArray(vaoID_);
glBindBuffer(GL_ARRAY_BUFFER, vboID_);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 8, (void*)0); // Screen Position
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 8, (void*)(2 *sizeof(GL_FLOAT)); //Color
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8, (void*)(6 * sizeof(GL_FLOAT)); //UV

最后,在每个循环中,我都会孤立缓冲区,然后将数据放入

glBufferData(GL_ARRAY_BUFFER, sizeof(vertexData), nullptr, GL_DYNAMIC_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertexData), vertexData);
glDrawArrays(GL_TRIANGLES, 0, 6);

这很好!因此,我尝试开始编写一个基本的sprite批处理。我将顶点数据分组到POD结构中:

struct VertexData {
struct {
GLfloat screenx;
GLfloat screeny;
} position;
struct {
GLfloat r;
GLfloat g;
GLfloat b;
GLfloat a;
} color;
struct {
GLfloat texu;
GLfloat texv;
} uv;
}

并使用一个向量将所有内容批处理在一起:std::vector<VertexData> spritebatch_

我更改了对glVertexAttribPointer的调用以匹配此结构(尽管我认为此更改是不必要的?)

glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(VertexData), (void*)offsetof(VertexData, position)); // Screen Position
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, sizeof(VertexData), (void*)offsetof(VertexData, color)); //Color
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(VertexData), (void*)offsetof(VertexData, uv)); //UV

为了测试它,在每个循环中,我都会向它提供与静态GLfloat阵列中相同的数据:

spritebatch_.push_back({0.5f, 0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,   1.0f});
spritebatch_.push_back({-0.5f, 0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f});
spritebatch_.push_back({0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f});
spritebatch_.push_back({-0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f});
spritebatch_.push_back({-0.5f, 0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f});
spritebatch_.push_back({0.5f, -0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f});

然后尝试孤立缓冲区并将数据放入:

glBufferData(GL_VERTEX_ARRAY, spritebatch_.size() * sizeof(VertexData), nullptr, GL_DYNAMIC_DRAW);
glBufferSubData(GL_VERTEX_ARRAY, 0, spritebatch_.size() * sizeof(VertexData), spritebatch_.data());
glDrawArrays(GL_TRIANGLES, 0, spritebatch_.size());

最后,我将重置spritebatch_:spritebatch_.clear();

然而,这是错误的。当我孤立缓冲区并将数据放入时,我是否做了不正确的事情?数据格式仍然匹配(VertexDataPOD成员仍然都是GLfloat),spritebatch_的大小仍然是6(6个顶点组成一个正方形),并且数据在每个顶点内的位置仍然相同。

glVertexAttribPointer的第五个参数是"步幅",即连续通用顶点属性之间的字节偏移

所以的变化

glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 8, (void*)0); // Screen Position
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 8, (void*)(2 *sizeof(GL_FLOAT)); //Color
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8, (void*)(6 * sizeof(GL_FLOAT)); //UV

glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(VertexData), (void*)offsetof(VertexData, position)); // Screen Position
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, sizeof(VertexData), (void*)offsetof(VertexData, color)); //Color
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(VertexData), (void*)offsetof(VertexData, uv)); //UV

很重要,因为sizeof(VertexData)不是8,而是8*sizeof(GL_FLOAT)


glBufferDataglBufferSubData的第一个参数必须是目标的枚举器常数,它是GL_ARRAY_BUFFERGL_ELEMENT_ARRAY_BUFFER、…之一
GL_VERTEX_ARRAY标识固定功能客户端功能的顶点数组-请参见glEnableClientState

更改:

glBufferData(GL_VERTEX_ARRAY, ...);
glBufferData(GL_ARRAY_BUFFER, ...);

glBufferSubData(GL_VERTEX_ARRAY, ...);
glBufferSubData(GL_ARRAY_BUFFER, ...);

注意,如果要检查OpenGL错误(glGetError或调试输出),则会得到GL_INVALID_ENUM错误
未创建数组缓冲区的数据存储,这会导致段故障。