OpenGL - 告诉顶点着色器 VBO 已经改变

Posted

技术标签:

【中文标题】OpenGL - 告诉顶点着色器 VBO 已经改变【英文标题】:OpenGL - tell vertex shader that VBO has changed 【发布时间】:2016-07-07 21:06:05 【问题描述】:

我目前正在编写一个需要不断更新我的 VBO 数据的程序。 但是,我发现如果在初始化缓冲区后调用glBindBuffer(GL_ARRAY_BUFFER, 0),窗口会以某种方式自行关闭。 下面是我的代码 sn-p:

 glGenBuffers(1, &vertex_buffer);
 glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
 glBufferData(GL_ARRAY_BUFFER, sizeof(pts[0]) * pts.size(), NULL, GL_DYNAMIC_DRAW);
 glBindBuffer(GL_ARRAY_BUFFER, 0); 

 vertex_shader = glCreateShader(GL_VERTEX_SHADER);
 glShaderSource(vertex_shader, 1, &vertex_shader_text, NULL);
 glCompileShader(vertex_shader);

 fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
 glShaderSource(fragment_shader, 1, &fragment_shader_text, NULL);
 glCompileShader(fragment_shader);

 program = glCreateProgram();
 glAttachShader(program, vertex_shader);
 glAttachShader(program, fragment_shader);
 glLinkProgram(program);

 mvp_location = glGetUniformLocation(program, "MVP");
 vpos_location = glGetAttribLocation(program, "vPos");

 glEnableVertexAttribArray(vpos_location);
 glVertexAttribPointer(vpos_location, 3, GL_FLOAT, GL_FALSE,
      sizeof(float) * 3, (void*) 0);

 while(!glfwWindowShouldClose(window)) 
    glUseProgram(program);

    glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
    glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(pts[0]) * pts.size(), &pts);
    glBindBuffer(GL_ARRAY_BUFFER, 0);

    mat4x4_mul(mvp, m, p);

    glUniformMatrix4fv(mvp_location, 1, GL_FALSE, (const GLfloat*) mvp);

    glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
    glDrawArrays(GL_POINTS, 0, pts.size());
    glBindBuffer(GL_ARRAY_BUFFER, 0);

    glfwSwapBuffers(window);
    glfwPollEvents();

仅供参考:pts 会不断更新。

有没有办法告诉顶点着色器 VBO 数据已更新?

编辑:更新了代码 sn-p

编辑:我应该每次绘制pts.size()个顶点,但屏幕上只出现一个点

【问题讨论】:

为什么在画之前要调用glBindBuffer 我只是按照一些教程说glBindBuffer 会刷新缓冲区中的数据 提供本教程的链接;我怀疑要么您误解了它所说的内容,要么该教程很愚蠢。无论哪种方式,您仍然需要提供minimal reproducible example,而上面的 sn-p 缺少太多东西,无法知道发生了什么。 你不需要告诉顶点着色器。顶点着色器在绘制时使用 VBO 中的任何内容。这是使用 glBufferSubData 上传的任何内容 【参考方案1】:

就在你的绘图调用之前,你有 glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);您需要实际设置属性指针(glVertexAttribPointer())。次要注意是 GlVertexAttribPointer() 将 GL_ARRAY_BUFFER 绑定到指定的属性指针。目前你调用它的地方没有绑定到 GL_ARRAY_BUFFER。

供参考 GLEnum error = glGetError() 将返回openGL的错误状态,是一个强大的调试工具。如果您使用 glew,glewGetErrorString() 将获取任何非零错误代码的字符串,该字符串会更详细地解释错误。

附言对不起,我的写作能力很差。

【讨论】:

大部分都是错误的。顶点属性状态完全独立于活动程序,因此在哪里调用glUseProgram()与它无关。此外,步幅值 12 看起来是正确的,因为如果它由 3 个浮点值组成,那么它就是顶点的字节大小。步幅是一个顶点的 start 和下一个顶点的开始之间的字节数。这个答案中唯一正确的部分是 GL_ARRAY_BUFFER 绑定需要在调用 glVertexAttribPointer() 时有效。 那这就是我要离开的部分 啊我的困惑是你设置步幅为零然后假设顶点是紧密排列的,但零只是表示假设 拨打glBufferSubData()后需要再拨打glVertexAttibPointer()吗? 由于目前屏幕上只有一个点绘制

以上是关于OpenGL - 告诉顶点着色器 VBO 已经改变的主要内容,如果未能解决你的问题,请参考以下文章

是否可以在顶点着色器内持续更改 iPhone OpenGL ES 2.0 上的 VBO 值?

OpenGL 基本 IBO/VBO 不工作

OpenGL - 如何理解 VAO 与 VBO 之间的关系

Opengl顶点着色器为每个顶点设置布尔值(glVertexAttribPointer)

OpenGL - 动画是由着色器完成的吗?

OpenGL Instancing VBO - 每个顶点,每个实例的属性