I am using glBufferSubData to change positions of vertices. Everything works fine, when I call the code below once. If I run this whole code two times to add two pointclouds the vertex positions is updated only for the last geometry.
Please look at only following methods of the class, because the rest of the code is just a constructor to initialize the clouds:
void opengl_init()
void opengl_draw()
I think something is wrong with winding to the vao buffer.
Question: How can I correctly update vertex positions glBufferSubData so that both pointclouds would move?
class pointcloud {
public:
int id = 0;
std::vector<vertex> vertices;
std::vector<unsigned int> indices;//pairs
unsigned int vao, vbo, ibo;
//individual polylines
pointcloud(const std::vector<float>& coord, const std::vector<float>& colors)//, std::vector<Texture> textures
{
vertices.reserve(coord.size());
indices.reserve((coord.size() - 1) * 2);
for (int i = 0; i < coord.size(); i = 3) {
vertex vertex;
vertex.position = glm::vec3(coord[i 0], coord[i 1], coord[i 2]);
vertex.color = glm::vec3(colors[i 0], colors[i 1], colors[i 2]);
vertices.emplace_back(vertex);
}
for (int i = 0; i < (coord.size() / 3) - 1; i ) {
indices.emplace_back(i 0);
indices.emplace_back(i 1);
}
// now that we have all the required data, set the vertex buffers and its attribute pointers.
//setup_polyline();
}
//merged polylines
pointcloud(const std::vector<std::vector<float>>& coord, const std::vector<std::vector<float>>& colors)//, std::vector<Texture> textures
{
//reserve memory
int v_count = 0;
int i_count = 0;
for (int i = 0; i < coord.size(); i ) {
v_count = coord[i].size();
i_count = coord[i].size() - 1;
}
vertices.reserve(v_count);
indices.reserve(i_count);
//fill vertics and indices lists
for (int i = 0; i < coord.size(); i ) {
for (int j = 0; j < coord[i].size(); j = 3) {
vertex vertex;
vertex.position = glm::vec3(coord[i][j 0], coord[i][j 1], coord[i][j 2]);
vertex.color = glm::vec3(colors[i][j 0], colors[i][j 1], colors[i][j 2]);
vertices.emplace_back(vertex);
}
}
v_count = 0;
for (int i = 0; i < coord.size(); i ) {
for (int j = 0; j < (coord[i].size() / 3) - 1; j ) {
//std::cout << v_count j 0 << " " << v_count j 1 << std::endl;
indices.emplace_back(v_count j 0);
indices.emplace_back(v_count j 1);
}
v_count = (coord[i].size() / 3);
}
//std::cout << vertices.size() << std::endl;
// now that we have all the required data, set the vertex buffers and its attribute pointers.
//setup_polyline();
}
//// initializes all the buffer objects/arrays
void opengl_init(bool draw_dynamic = true, int _id = 0)
{
id = _id 1;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// init vertex-array and vertex-array-buffer
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//vertex array
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
//bind vertex-array-buffer to the vertex-array
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//declare array with data or empty array depending how data will be displayed
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
auto type = !draw_dynamic ? GL_STATIC_DRAW : GL_STREAM_DRAW;
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(vertex), &vertices[0], type); // target | size | data (poinnting to first element e.g. glm::value_ptr(vertices[0])) | usage
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// set attributes that corresponds to layout id in the vertex shader
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// vertex Positions
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(vertex), (void*)0);
// vertex normals
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(vertex), (void*)offsetof(vertex, color));
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//bind buffers vao | vbo | ibo
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//glBindVertexArray(0);
}
// render the mesh
void opengl_draw(opengl_shaders::shader& shader, bool draw_dynamic = true)
{
//update
//https://learnopengl.com/Advanced-OpenGL/Advanced-Data
if (draw_dynamic) {
for (auto& v : vertices)
v.position.y = 0.001;
glBufferSubData(GL_ARRAY_BUFFER, 0, vertices.size() * sizeof(vertex), &vertices[0]);
}
//draw
glBindVertexArray(vao);
glDrawArrays(GL_POINTS, 0, vertices.size());
//glBindVertexArray(0);
}
void opengl_clear(opengl_shaders::shader& shader) {
glDeleteVertexArrays(1, &vao);
glDeleteBuffers(1, &vbo);
shader.delete_shader();
}
};
CodePudding user response:
glBufferSubData
updates a subset of the data store of a buffer object that is currently bound to the specified target. You must bind the buffer before you can modify its data:
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferSubData(GL_ARRAY_BUFFER, 0, vertices.size() * sizeof(vertex), &vertices[0]);
The GL_ARRAY_BUFFER
binding is a global state. This binding is maintained until it is changed. As for your code it works for 1 pointcloud, but it doesn't work if you have more than 1 pointcloud and vertex buffer.