I'm learning to use OpenGL in Qt with the QOpenGLFramebufferObject, and tried to draw a triangle using the following code:
In render() :
glUseProgram(m_program);
GLfloat vertices[] = {
-1.0f, -1.0f, // first
0.0f, -1.0f, // second
0.0f, 1.0f // third
};
unsigned int VAO;
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), vertices);
glBindVertexArray(0);
glDisable(GL_DEPTH_TEST);
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glBindVertexArray(VAO);
glDrawArrays(GL_TRIANGLES, 0, 3);
And the shaders are in initShader() :
const GLchar* vfSource[] = {
"#version 330 core\n"
"layout (location = 0) in vec2 aPos;\n"
"void main()\n"
"{\n"
" gl_Position = vec4(aPos.x, aPos.y, 0.0, 1.0);\n"
"}\n\0"
};
const GLchar* fsSource[] = {
"#version 330 core\n"
"out vec4 FragColor;\n"
"void main()\n"
"{\n"
" FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n"
"}\n\0"
};
Only the first and third vertex rendered correctly. The second vertex were located in the center of my screen.
And if I changed the vertices[] to
-1.0f, -1.0f, // 1
0.0f, -1.0f, // 2
0.0f, 1.0f // 3
1.0f, 1.0f, // 4
1.0f, 0.0f // 5
and the last line to
glDrawArrays(GL_TRIANGLES, 0, 5);
The output is a triangle produced by the data in line 1 3 and 5.
I have no idea about what's wrong with this code. Anyone can help me?
If more code is needed, just let me know.
The OpenGL 3.3 Core Profile (which your shaders are targeting) doesn't allow you to draw directly from client memory. The last parameter of glVertexAttribPointer is a offset into the currently bound GL_ARRAY_BUFFER. Setting it to something else than zero should trigger a GL_INVALID_OPERATION when no GL_ARRAY_BUFFER is bound.
In order to get your example working your need to generate a Vertex Buffer Object (VBO) and attach it to the VAO.
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), 0);
glBindVertexArray(0);
Related
I want to draw different figures using triangle fans but I am not sure how to make the program draw the second figure. Do I need a second vertexShaderSource and a second fragmentShaderSource each time I want to change the color or draw a new figure?
Here is the code:
#include <GL/glew.h>
#include <GL/glut.h>
#include <stdio.h>
const char* vertexShaderSource = "#version 330 core\n"
"layout (location = 0) in vec3 aPos;\n"
"void main()\n"
"{\n"
" gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
"}\0";
const char* fragmentShaderSource = "#version 330 core\n"
"out vec4 FragColor;\n""void main()\n"
"{\n"
" FragColor = vec4(1.0f, 0.0f, 0.0f, 0.0f);\n" // To set the color.
"}\n\0";
// Set of vertices for the different figures that make up the drawing.
float vertices[] = {
-0.8f, 0.6f, 0.0f, // Center.
-0.8f, 0.4f, 0.0f,
-0.83f, 0.44f, 0.0f,
-0.87f, 0.51f, 0.0f,
-0.9f, 0.57f, 0.0f,
-0.93f, 0.63f, 0.0f,
-0.95f, 0.69f, 0.0f,
-0.97f, 0.75f, 0.0f,
-0.98f, 0.8f, 0.0f,
-0.91f, 0.8f, 0.0f,
-0.85f, 0.79f, 0.0f,
-0.8f, 0.77f, 0.0f,
};
unsigned int VBO, VAO;
GLuint vertexShader;
GLuint fragmentShader;
GLuint shaderProgram;
void display(void){
// Background color.
glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(shaderProgram);
glBindVertexArray(VAO);
glDrawArrays(GL_TRIANGLE_FAN, 0, 12);
glBindVertexArray(0);
glFlush();
}
// Main.
int main(int argc, char** argv){
glutInit(&argc, argv);
// Color mode.
glutInitDisplayMode(GLUT_RGBA);
// Window size.
glutInitWindowSize(500, 500);
// Title.
glutCreateWindow("Tarea 3: Figura con curvas");
GLenum err = glewInit();
if(err!=GLEW_OK) {
printf("glewInit failed: %s",glewGetErrorString(err));
exit(1);
}
vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
glCompileShader(vertexShader);
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
glCompileShader(fragmentShader);
shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
glutDisplayFunc(display);
glutMainLoop();
}
No is not necessary (or recommended) to use different shaders for the meshes. If you want to draw multiple objects, then you can put the vertex attributes of the meshes to separate Vertex Buffer Objects:
GLuint VBOs[2];
glGenBuffers(2, VBOs);
glBindBuffer(GL_ARRAY_BUFFER, VBOs[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices_1, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, VBOs[1]);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices_2, GL_STATIC_DRAW);
Specify a Vertex Array Object for each mesh:
GLuint VAOs[2];
glGenVertexArrays(2, VAOs);
glBindVertexArray(VAOs[0]);
glBindBuffer(GL_ARRAY_BUFFER, VBOs[0]);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
glBindVertexArray(VAOs[1]);
glBindBuffer(GL_ARRAY_BUFFER, VBOs[1]);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
Bind the VAO, before the draw call:
glBindVertexArray(VAOs[0]);
glDrawArrays(GL_TRIANGLE_FAN, 0, 12);
glBindVertexArray(VAOs[1]);
glDrawArrays(...);
Of course it is also possible to put all the vertex attributes of the different meshes consecutively in the data store of one VBO. If the vertex specification is identically, then it is event possible to use one single VAO.
Different locations of different meshes can be achieved by vertex transformation in the vertex shader. Use a Uniform of type mat4, to transform the vertices of a mesh:
#version 330 core
layout (location = 0) in vec3 aPos;
uniform mat4 u_model;
void main()
{
gl_Position = u_model * vec4(aPos.xyz, 1.0);
}
See further LearnOpenGL - Transformations.
If the 2 figures are identical, but have just a different location, then you can draw the same mesh twice, but you have to change the model transformation u_model.
You are looking for Uniform buffer objects.
If you have only a single value for a whole draw call, then your shader should be parametrized. The obvious thing you want to parametrize first is the color in the fragment shader, followed by adding a projection matrix to the vertex shader.
From that point onwards it's just alternating between setting new values to uniforms and draw-calls as long as it is the same 3D model.
For different models refer to #rabbid76's answer.
I've a simple OpenGL program running on macOS:
glUseProgram(program);
glViewport(0, 0, mWidth, mHeight);
glClearColor(0.25f, 0.25f, 0.25f, 1.0f);
// Rendering Loop
while (glfwWindowShouldClose(mWindow) == false) {
if (glfwGetKey(mWindow, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
glfwSetWindowShouldClose(mWindow, true);
}
// why can't view port here?
glViewport(0, 0, mWidth, mHeight);
// Background Fill Color
glClear(GL_COLOR_BUFFER_BIT);
glBindVertexArray(vao);
glDrawArrays(GL_TRIANGLES, 0, 3);
// Flip Buffers and Draw
glfwSwapBuffers(mWindow);
glfwPollEvents();
}
If I comment out the glViewport call inside the loop, it works well, the triangle is rendered in the center of the window, but if I uncomment it, the triangle shows in the left bottom corner of the window.
Below is my shader and vertex data code:
const int mWidth = 1280;
const int mHeight = 800;
auto mWindow = glfwCreateWindow(mWidth, mHeight, "OpenGL", nullptr, nullptr);
const GLchar* vertex_shader_src =
"#version 330 core\n"
"layout (location = 0) in vec3 aPos;\n"
"void main()\n"
"{\n"
" gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
"}";
const GLchar* fragment_shader_src =
"#version 330 core\n"
"out vec4 FragColor;\n"
"void main()\n"
"{\n"
" FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n"
"}";
GLfloat vertices[] = {
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.0f, 0.5f, 0.0f
};
GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
GLuint vbo;
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float),
(void*)0);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
Could somebody help me?
As #httpdigest commented, it is because macOS has 2x larger frame buffer size, if I query it with glfwGetFramebufferSize and use it as view port size, it works well!
This question already has an answer here:
Can't set uniform value in OpenGL shader
(1 answer)
Closed 6 years ago.
I have a simple vertex array that draws a quad to the screen.
glViewport(0, 0, screenWidth, screenHeight);
// Load shaders
...
GLfloat vertices[] = {
0.0f, 1.0f,
1.0f, 0.0f,
0.0f, 0.0f,
0.0f, 1.0f,
1.0f, 1.0f,
1.0f, 0.0f
};
GLuint vao, vbo;
glGenVertexArrays(1, &vao);
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glBindVertexArray(vao);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), (GLvoid*)0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
...
glUseProgram(program);
glUniform3f(glGetUniformLocation(program, "spriteColour"), colour.x, colour.y, colour.z);
glBindVertexArray(vao);
glDrawArrays(GL_TRIANGLES, 0, 6);
glBindVertexArray(0);
Using the below simple vertex and fragment shaders.
#version 330 core
layout (location = 0) in vec2 vertex;
void main()
{
gl_Position = vec4(vertex.xy, 0.0, 1.0);
}
#version 330 core
out vec4 color;
uniform vec3 spriteColour;
void main()
{
color = vec4(spriteColour, 1.0);
}
This works exactly how I expect. It renders a rectangle to the upper right corner of the window.
Now I want to add a simple model and projection matrix. I am using an orthographic projection matrix and my model matrix just scales the quad to 100 x 100.
glm::mat4 projection = glm::ortho(0.0f, (GLfloat)screenWidth, (GLfloat)screenHeight, 0.0f, -1.0f, 1.0f);
glUniformMatrix4fv(glGetUniformLocation(shader, "projection"), 1, GL_FALSE, glm::value_ptr(projection));
...
glm::mat4 model;
model = glm::scale(model, glm::vec3(100.0f, 100.0f, 1.0f));
glUniformMatrix4fv(glGetUniformLocation(program, "model"), 1, GL_FALSE, glm::value_ptr(model));
...
// Update vertex shader
#version 330 core
layout (location = 0) in vec2 vertex;
uniform mat4 model;
uniform mat4 projection;
void main()
{
gl_Position = projection * model * vec4(vertex.xy, 0.0, 1.0);
}
I would expect this to render a 100 x 100 quad at the top left of the screen however I don't see anything.
I can only assume that somehow my transformations are causing the quad to be drawn off screen and clipped? I am pretty new at Open GL so I am not entirely sure what is wrong here. I've been over it numerous times and based on the tutorials I am using (http://learnopengl.com/) it seems correct.
Does anyone have any ideas as to what I've done wrong?
Turns out you need to activate the program before setting uniforms.
Can't set uniform value in OpenGL shader
So I finally set up opengl window properly and got triangles to show up using vaos, vbos and glDrawElements() etc.
Here is the what i have
But now I have new problem - can't get shaders to work. I don't quite understand them yet. I want fragment shader to show vertex colors which I put into a separate buffer object.
Example code:
const char* vertexShaderSource =
"#program 330\n"
"layout(location = 0) in vec2 position;\n"
"layout(location = 1) in vec3 color;\n"
"out vec4 fragColor;\n"
"void main(void){\n"
"gl_Position = vec4(position, 0.0, 1.0);\n"
"fragColor = vec4(color, 1.0);\n"
"}";
const char* fragShaderSource =
"#program 330\n"
"in vec4 fragColor;\n"
"out vec4 outColor;\n"
"void main(void){\n"
"outColor = fragColor;\n"
"}";
GLuint programID = glCreateProgram();
GLuint vertexShaderID = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShaderID, 1, &vertexShaderSource, NULL);
glCompileShader(vertexShaderID);
GLuint fragShaderID = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragShaderID, 1, &fragShaderSource, NULL);
glCompileShader(fragShaderID);
glAttachShader(programID, vertexShaderID);
glAttachShader(programID, fragShaderID);
glLinkProgram(programID);
glValidateProgram(programID);
GLfloat vertexPositions[8] =
{
-0.5f, 0.5f,
0.5f, 0.5f,
-0.5f, -0.5f,
0.5f, -0.5f,
};
GLfloat colors[18] =
{
1.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 1.0f,
0.0f, 1.0f, 0.0f,
1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f,
};
GLushort indices[6] =
{
0, 1, 2,
1, 3, 2
};
GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
GLuint vbo; //Vertices
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 8, vertexPositions, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0);
GLuint cbo; //Colors
glGenBuffers(1, &cbo);
glBindBuffer(GL_ARRAY_BUFFER, cbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 18, colors, GL_STATIC_DRAW);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, 0);
GLuint ibo; //Indexes
glGenBuffers(1, &ibo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLushort) * 6, indices, GL_STATIC_DRAW);
And render:
while(..)
{
..clear
glBindVertexArray(vao);
glUseProgram(programID);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, (void*)(0));
..update
}
Everything seems to work fine except for shaders. Any help is appreciated :)
Thanks.
In each of the shaders, change "#program 330\n" to "#version 330\n". That is how you specify which GLSL version to use.
So i have a couple classes. A renderer and box2drenderer. Now both use their own vertex buffer and their own vertex array object. The Renderer is instantiated first with the following code:
glGenBuffers(1, &ebo);
glGenBuffers(1, &vbo);
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
GLfloat vertices[] = {
// Position(2) Color(3) Texcoords(2)
0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, // Top-left
1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, // Top-right
1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, // Bottom-right
0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f // Bottom-left
};
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_DYNAMIC_DRAW);
GLuint elements[] = {
0, 1, 2,
2, 3, 0
};
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(elements), elements, GL_STATIC_DRAW);
GLint posAttrib = glGetAttribLocation(shaderProgram, "position");
glEnableVertexAttribArray(posAttrib);
glVertexAttribPointer(posAttrib, 2, GL_FLOAT, GL_FALSE, 7 * sizeof(GLfloat), 0);
GLint colAttrib = glGetAttribLocation(shaderProgram, "color");
glEnableVertexAttribArray(colAttrib);
glVertexAttribPointer(colAttrib, 3, GL_FLOAT, GL_FALSE, 7 * sizeof(GLfloat), (void*)(2 * sizeof(GLfloat)));
GLint texAttrib = glGetAttribLocation(shaderProgram, "texcoord");
glEnableVertexAttribArray(texAttrib);
glVertexAttribPointer(texAttrib, 2, GL_FLOAT, GL_FALSE, 7 * sizeof(GLfloat), (void*)(5 * sizeof(GLfloat)));
glBindVertexArray(0);
glUseProgram(shaderProgram);
projection = glm::ortho(0.0f, width, height, 0.0f);
glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "projection"), 1, GL_FALSE, glm::value_ptr(projection));
glUseProgram(0);
Then I call the setup function for the box2d:
void Box2DRenderer::setRenderer(Renderer * r) {
this->renderer = r;
const GLchar * fragSource =
"#version 150 core\n\
precision mediump float;\n\
uniform vec4 u_color;\n\
out vec4 Color;\n\
\n\
void main()\n\
{\n\
Color = u_color;\n\
}";
const GLchar * vertSource =
"#version 150 core\n\
uniform mediump mat4 u_projection;\n\
uniform mediump float u_pointSize;\n\
in vec2 a_position;\n\
\n\
void main()\n\
{\n\
gl_PointSize = u_pointSize;\n\
gl_Position = u_projection * vec4(a_position, 0.0, 1.0);\n\
}";
this->renderer->compileProgram(vertSource, fragSource, vertShader, fragShader, shaderProgram);
glUseProgram(shaderProgram);
glGenBuffers(1, &vbo);
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_DYNAMIC_DRAW);
glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "u_projection"), 1, GL_FALSE, glm::value_ptr(this->renderer->getProjectionMatrix()));
GLuint positionLocation = glGetAttribLocation(shaderProgram, "a_position");
glEnableVertexAttribArray(positionLocation);
glVertexAttribPointer(positionLocation, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), 0);
glBindVertexArray(0);
colorLocation = glGetUniformLocation(shaderProgram, "u_color");
pointSizeLocation = glGetUniformLocation(shaderProgram, "u_pointSize");
glUseProgram(0);
}
The Renderer for now just draws textures. So i draw the player via the method:
void Renderer::renderTexture(sf::FloatRect &bounds, Texture &texture, Region *region) {
glm::mat4 model;
model = glm::translate(model, glm::vec3(bounds.left, bounds.top, 0.0f));
model = glm::scale(model, glm::vec3(bounds.width, bounds.height, 0.0f));
GLint modelMat = glGetUniformLocation(shaderProgram, "mMatrix");
glUniformMatrix4fv(modelMat, 1, GL_FALSE, glm::value_ptr(model));
float x = region->pos.x / texture.getWidth();
float y = region->pos.y / texture.getHeight();
float rx = (region->width + region->pos.x) / texture.getWidth();
float ry = (region->height + region->pos.y) / texture.getHeight();
GLfloat vertices[] = {
// Position(2) Color(3) Texcoords(2)
0.0f, 0.0f, 1.0f, 1.0f, 1.0f, x, y, // Top-left
1.0f, 0.0f, 1.0f, 1.0f, 1.0f, rx, y, // Top-right
1.0f, 1.0f, 1.0f, 1.0f, 1.0f, rx, ry, // Bottom-right
0.0f, 1.0f, 1.0f, 1.0f, 1.0f, x, ry // Bottom-left
};
glBindTexture(GL_TEXTURE_2D, texture.getTextureId());
glBindVertexArray(vao);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
glBindTexture(GL_TEXTURE_2D, 0);
}
Now, if i don't initialize the box2d renderer, it works fine. If i have the box2d renderer, the texture coords are getting messed up. The whole texture seems to get drawn across the screen instead of regions at their correct place.
Given i'm turning on and off the BindVertexArray, I feel like I shouldn't have an issue, but for the life of me I can't figure it out. I can post screenshots of the difference if you'd like.
You probably fell victim to a fairly common misconception: Contrary to what you might have expected, the GL_ARRAY_BUFFER binding is not part of the VAO state.
At the tail end of the posted code you have this sequence:
glBindVertexArray(vao);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
The glBufferSubData() call will modify data in the currently bound GL_ARRAY_BUFFER, which is the buffer that you last made a glBindBuffer(GL_ARRAY_BUFFER, ...) call for. This is unrelated to the buffer you had bound when you previously used the VAO.
For additional illustration, here is a typical call sequence:
glBindVertexArray(vaoA);
glBindBuffer(GL_ARRAY_BUFFER, vboA);
glBindVertexArray(vaoB);
glBindBuffer(GL_ARRAY_BUFFER, vboB);
glBindVertexArray(vaoA);
The current GL_ARRAY_BUFFER binding at the end of this sequence is vboB. Since the binding is not part of the VAO state, it is simply based on the most recent glBindBuffer() call.
All you need to do to fix this is to add the glBindBuffer() call before glBufferSubData().
Note that the GL_ELEMENT_ARRAY_BUFFER binding is part of the VAO state. This may seem inconsistent, but it's not. The VAO bundles all the vertex setup state that is used by draw commands. The GL_ELEMENT_ARRAY_BUFFER binding controls which index buffer is used by draw commands, so it is part of this state. On the other hand, the current GL_ARRAY_BUFFER binding has no effect on the draw command, and is therefore not part of the VAO state.