glBufferData 和 glBufferSubData 偏移量
glBufferData and glBufferSubData Offset
我正在尝试在 OpenGL 3.3 中渲染 Suzanne(来自 Blender),但缓冲区数据似乎不正确。我明白了:
https://gyazo.com/ab82f9acb6854a49fccc527ed96cc4e8
我也尝试渲染一个简单纹理的球体:
https://gyazo.com/85c1e87fcc4eab128ca37b1a0cb1deaa
我的导入器将顶点数据作为单个浮点数插入到 std::vector 中:
if(line.substr(0,2) == "v ")
{
/** Vertex position */
std::istringstream s(line.substr(2));
float v[3];
s >> v[0]; s >> v[1]; s >> v[2];
this->vertices.push_back(v[0]);
this->vertices.push_back(v[1]);
this->vertices.push_back(v[2]);
}
我按如下方式设置数组缓冲区:
glGenBuffers(1, &this->vbo);
glBindBuffer(GL_ARRAY_BUFFER, this->vbo);
glBufferData(GL_ARRAY_BUFFER,
sizeof(float)*(this->vertices.size()+this->textures.size()+this->normals.size()),
NULL,
GL_STATIC_DRAW);
然后我使用 glBufferSubData
插入实际数据
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*this->vertices.size(), this->vertices.data());
glBufferSubData(GL_ARRAY_BUFFER, sizeof(float)*this->vertices.size(), sizeof(float)*this->textures.size(), this->textures.data());
glBufferSubData(GL_ARRAY_BUFFER, sizeof(float)*(this->vertices.size()+this->textures.size()), sizeof(float)*this->normals.size(), this->normals.data());
我也以同样的方式插入索引(当然是GL_ELEMENT_ARRAY_BUFFER)。
我再点资料:
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3*sizeof(float), (GLvoid*)0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3*sizeof(float), (GLvoid*)(sizeof(float)*this->v.size()));
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3*sizeof(float), (GLvoid*)(sizeof(float)*this->v.size()+this->vt.size()));
我的顶点着色器接收这样的数据:
layout(location = 0) in vec3 position;
layout(location = 1) in vec2 texCoord;
layout(location = 2) in vec3 normals;
我是不是搞砸了偏移量?
编辑:
我发现了最大的问题!我编写了一个外部 Lua 程序来将 obj 文件转换为更易于导入的格式,但它最终弄乱了数据并复制了 "f #/#/# #/#/# #/#/#" 上的索引,因此文件看起来像这样( x->y->x) 而不是 (x->y->z)
由于以下回复,还修复了一些其他错误!
没有看到你的着色器,我不能 100% 确定你对 glVertexAttribPointer
的调用是否合法。我也不知道你是否想要在单个 VBO 中交错顶点数据。你目前拥有的首先是所有的顶点位置,然后是所有的纹理坐标,最后是所有的法线。
要交错数据,您首先要将所有数据放入一个数组(或向量)中,以便每个顶点重复 PPPTTNNN
模式。其中 PPP
是三个位置浮动,TT
是两个 texcoord 浮动,NNN
是三个普通浮动。
它看起来像这样(使用伪造的类型、值和间距来帮助说明模式):
float[] vertices = {
/* pX, pY, pZ, tX, tY, nX, nY, nZ */
1, 1, 1, 0, 0, 1, 1, 1, // vertex 1
0, 0, 0, 1, 1, 0, 0, 0, // vertex 2
1, 1, 1, 0, 0, 1, 1, 1, // vertex 3
...
};
假设您将其全部放入一个名为 vertices
的矢量中,然后您可以使用一个命令上传它:
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * this->vertices.size(), this->vertices.data(), GL_STATIC_DRAW);
您也可以将每个属性放入其自己的 VBO 中。您决定如何将数据存储在 GPU 上最终取决于您。如果您故意按照自己的方式存储数据,请在评论中告诉我,我会更新答案。
好的,现在是着色器位。
假设您有一个如下所示的顶点着色器:
in vec3 position;
in vec2 texcoord;
in vec3 normal;
out vec2 uv;
void main() {
gl_Position = vec4(position, 1);
uv = texcoord;
}
还有一个看起来像这样的片段着色器:
in vec2 uv;
uniform sampler2D image;
out vec4 color;
void main() {
color = texture(image, uv);
}
那么您需要以下 glVertexAttribPointer
个调用:
int stride = (3 + 2 + 3) * sizeof(float);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, stride, (GLvoid*)0);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, stride, (GLvoid*)3);
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, stride, (GLvoid*)5);
注意每次调用的第一个参数是不同的数字。这分别对应顶点着色器中的position
、texcoord
、normal
此外,纹理坐标通常只是一对浮点数(例如 vec2 texcoord
),因此我将第二个参数更改为 2
以用于 texcoord 调用。
最后一个参数,使用交错数组时,只需要指定每个顶点的偏移量。因此我们得到 0
、3
和 5
分别用于位置偏移、纹理坐标偏移和法线偏移。
希望这能让你到达你想去的地方。
查看 docs.gl page on glVertexAttribPointer 了解更多信息。
我正在尝试在 OpenGL 3.3 中渲染 Suzanne(来自 Blender),但缓冲区数据似乎不正确。我明白了:
https://gyazo.com/ab82f9acb6854a49fccc527ed96cc4e8
我也尝试渲染一个简单纹理的球体:
https://gyazo.com/85c1e87fcc4eab128ca37b1a0cb1deaa
我的导入器将顶点数据作为单个浮点数插入到 std::vector 中:
if(line.substr(0,2) == "v ")
{
/** Vertex position */
std::istringstream s(line.substr(2));
float v[3];
s >> v[0]; s >> v[1]; s >> v[2];
this->vertices.push_back(v[0]);
this->vertices.push_back(v[1]);
this->vertices.push_back(v[2]);
}
我按如下方式设置数组缓冲区:
glGenBuffers(1, &this->vbo);
glBindBuffer(GL_ARRAY_BUFFER, this->vbo);
glBufferData(GL_ARRAY_BUFFER,
sizeof(float)*(this->vertices.size()+this->textures.size()+this->normals.size()),
NULL,
GL_STATIC_DRAW);
然后我使用 glBufferSubData
插入实际数据glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*this->vertices.size(), this->vertices.data());
glBufferSubData(GL_ARRAY_BUFFER, sizeof(float)*this->vertices.size(), sizeof(float)*this->textures.size(), this->textures.data());
glBufferSubData(GL_ARRAY_BUFFER, sizeof(float)*(this->vertices.size()+this->textures.size()), sizeof(float)*this->normals.size(), this->normals.data());
我也以同样的方式插入索引(当然是GL_ELEMENT_ARRAY_BUFFER)。
我再点资料:
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3*sizeof(float), (GLvoid*)0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3*sizeof(float), (GLvoid*)(sizeof(float)*this->v.size()));
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3*sizeof(float), (GLvoid*)(sizeof(float)*this->v.size()+this->vt.size()));
我的顶点着色器接收这样的数据:
layout(location = 0) in vec3 position;
layout(location = 1) in vec2 texCoord;
layout(location = 2) in vec3 normals;
我是不是搞砸了偏移量?
编辑: 我发现了最大的问题!我编写了一个外部 Lua 程序来将 obj 文件转换为更易于导入的格式,但它最终弄乱了数据并复制了 "f #/#/# #/#/# #/#/#" 上的索引,因此文件看起来像这样( x->y->x) 而不是 (x->y->z)
由于以下回复,还修复了一些其他错误!
没有看到你的着色器,我不能 100% 确定你对 glVertexAttribPointer
的调用是否合法。我也不知道你是否想要在单个 VBO 中交错顶点数据。你目前拥有的首先是所有的顶点位置,然后是所有的纹理坐标,最后是所有的法线。
要交错数据,您首先要将所有数据放入一个数组(或向量)中,以便每个顶点重复 PPPTTNNN
模式。其中 PPP
是三个位置浮动,TT
是两个 texcoord 浮动,NNN
是三个普通浮动。
它看起来像这样(使用伪造的类型、值和间距来帮助说明模式):
float[] vertices = {
/* pX, pY, pZ, tX, tY, nX, nY, nZ */
1, 1, 1, 0, 0, 1, 1, 1, // vertex 1
0, 0, 0, 1, 1, 0, 0, 0, // vertex 2
1, 1, 1, 0, 0, 1, 1, 1, // vertex 3
...
};
假设您将其全部放入一个名为 vertices
的矢量中,然后您可以使用一个命令上传它:
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * this->vertices.size(), this->vertices.data(), GL_STATIC_DRAW);
您也可以将每个属性放入其自己的 VBO 中。您决定如何将数据存储在 GPU 上最终取决于您。如果您故意按照自己的方式存储数据,请在评论中告诉我,我会更新答案。
好的,现在是着色器位。
假设您有一个如下所示的顶点着色器:
in vec3 position;
in vec2 texcoord;
in vec3 normal;
out vec2 uv;
void main() {
gl_Position = vec4(position, 1);
uv = texcoord;
}
还有一个看起来像这样的片段着色器:
in vec2 uv;
uniform sampler2D image;
out vec4 color;
void main() {
color = texture(image, uv);
}
那么您需要以下 glVertexAttribPointer
个调用:
int stride = (3 + 2 + 3) * sizeof(float);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, stride, (GLvoid*)0);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, stride, (GLvoid*)3);
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, stride, (GLvoid*)5);
注意每次调用的第一个参数是不同的数字。这分别对应顶点着色器中的position
、texcoord
、normal
此外,纹理坐标通常只是一对浮点数(例如 vec2 texcoord
),因此我将第二个参数更改为 2
以用于 texcoord 调用。
最后一个参数,使用交错数组时,只需要指定每个顶点的偏移量。因此我们得到 0
、3
和 5
分别用于位置偏移、纹理坐标偏移和法线偏移。
希望这能让你到达你想去的地方。
查看 docs.gl page on glVertexAttribPointer 了解更多信息。