glDrawArrays 仅在我将“错误”数据传递给它时才有效
Posted
技术标签:
【中文标题】glDrawArrays 仅在我将“错误”数据传递给它时才有效【英文标题】:glDrawArrays only works when I pass it the "wrong" data 【发布时间】:2014-06-13 23:19:41 【问题描述】:我正在编写一个程序来使用从顶点数组获取数据的着色器在屏幕上绘制简单的块。顶点数组是一个浮点数组,它按以下顺序将 x,y,z 位置值与 u,v 纹理值组合在一起:
[x1, y1, z1, u1, v1, x2, y2, z2, u2, v2, ...]
我是这样创建缓冲区的(数据是我之前用数据填充的向量对象):
glGenBuffers(1, &data_buffer);
glBindBuffer(GL_ARRAY_BUFFER, data_buffer);
glBufferData(GL_ARRAY_BUFFER, data.size() * sizeof(float), &(data[0]), GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
后来我画成这样:
glUseProgram(city_shader);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glActiveTexture(GL_TEXTURE0);
glUniformMatrix4fv(mvpMatrixID, 1, GL_FALSE, &mvp_matrix[0][0]);
glBindTexture(GL_TEXTURE_2D, texture.tex);
glUniform1i(textureID, 0);
glBindBuffer(GL_ARRAY_BUFFER, data_buffer);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GL_FLOAT), (void*)0);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GL_FLOAT), (void*)(3 * sizeof(GL_FLOAT)));
glDrawArrays(GL_QUADS, 0, data.size()/5);
glBindTexture(GL_TEXTURE_2D, 0);
glUseProgram(0);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
但这只会产生一个空白屏幕:
http://imgur.com/IrinBKc
起初,我认为我的着色器有问题。但是,当我像这样将步幅改变为 glVertexAttribPointer 时,我注意到了:
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 4 * sizeof(GL_FLOAT), (void*)0); //Stride is now only 4, when there are 5 elements per vertex
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GL_FLOAT), (void*)(3 * sizeof(GL_FLOAT)));
我得到以下(损坏的)图像:
http://imgur.com/EXJaJWi
这让我相信我的着色器和其他绘图调用实际上工作正常(也就是说,它们正确地应用了纹理并转换了顶点),但只有当提供给它们的数据在某种程度上是错误的时。当我破坏缓冲区的顶点属性的步幅时,我只能得到一些绘制的东西。有什么建议吗?
编辑:另外,我插入了对 glGetError() 的调用,但无济于事。
EDIT2:根据 Peppe 的要求,这是我的着色器的代码:
顶点着色器:
#version 430 core
layout(location = 0) in vec3 pos;
layout(location = 1) in vec2 uv_coords;
uniform mat4 mvpMatrix;
out vec2 vs_uv;
void main()
vs_uv = uv_coords;
gl_Position = mvpMatrix * vec4(pos,1.0);
片段着色器:
#version 430 core
in vec2 vs_uv;
uniform sampler2D tex;
out vec4 fs_color;
void main()
fs_color = vec4(texture(tex,vs_uv));
以及填充我的缓冲区的代码子集:
//West wall - x-axis increases
float base_x_texture_coord = gen_random_x_texture_coord();
float base_y_texture_coord = gen_random_y_texture_coord();
data.push_back(segment_pos_x + half_x_width); data.push_back(0.0f); data.push_back(segment_pos_z + half_z_width);
data.push_back(base_x_texture_coord); data.push_back(base_y_texture_coord);
data.push_back(segment_pos_x + half_x_width); data.push_back(height); data.push_back(segment_pos_z + half_z_width);
data.push_back(base_x_texture_coord); data.push_back(base_y_texture_coord + height);
data.push_back(segment_pos_x + half_x_width); data.push_back(height); data.push_back(segment_pos_z - half_z_width);
data.push_back(base_x_texture_coord + z_width); data.push_back(base_y_texture_coord + height);
data.push_back(segment_pos_x + half_x_width); data.push_back(0.0f); data.push_back(segment_pos_z - half_z_width);
data.push_back(base_x_texture_coord + z_width); data.push_back(base_y_texture_coord);
【问题讨论】:
您是否确定属性 0 与顶点着色器的位置输入相关联,而属性 1 与纹理坐标的输入相关联?您可以在着色器代码中使用glGetAttribLocation()
或 glBindAttribLocation()
或 layout (location=..)
指令等调用。
在大多数平台上这应该不是问题,但是您真的,真的想写sizeof(GLfloat)
,而不是sizeof(GL_FLOAT)
。 (这不是问题,因为对于单精度浮点数和整数,这两种大小都是 4 字节——GL_FLOAT
宏的扩展)。
另外,请停止使用四边形绘图。 Core 配置文件不再支持这一点。
RetoKoradi:我已经确认属性设置正确,在着色器中它们被定义为 vec3 pos 中的 layout(location = 0); vec2 uv_coords 中的布局(位置 = 1); peppe:感谢您的提示,我已将代码修改为使用 GLfloat 而不是 GL_FLOAT,但没有解决方案。将来,我会将我的渲染器转换为使用三角形,但我想先弄清楚这一点。
我不确定sizeof (GL_FLOAT)
一定是 32 位的。 GLenum
是 32 位类型,但是 OpenGL 使用的常量值都限制在低 16 位。整数文字通常是 32 位的,但不一定是。无论常量的大小是多少,您都不想使用它:P
【参考方案1】:
想通了!事实证明,我的绘图代码工作正常,但是我为正方形的位置生成的坐标太远了,所以没有绘制正方形。无论如何感谢您的帮助。
【讨论】:
以上是关于glDrawArrays 仅在我将“错误”数据传递给它时才有效的主要内容,如果未能解决你的问题,请参考以下文章
OpenGL 3.3 - glDrawArrays 后的无效操作错误 (1282)
调用 glDrawArrays() 时的 OpenGL VBO Segfault
Firebase 消息传递 onMessage 仅在窗口中可用
尝试从帧缓冲区传递纹理会导致 L_INVALID_OPERATION:glDrawArrays:绘制的源纹理和目标纹理相同