I got a soft body simulation running with the bullet physics engine, thus I have to update the mesh vertices' position each frame. To do so I use the following function :
void Mesh::update_VBO(std::vector<Vertex> const & updated_vertices)
{
indices.clear();
for(int i = 0; i < updated_vertices.size(); i++)
{
indices.push_back(i);
}
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
void * VBO_ptr = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
void * EBO_ptr = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY);
memcpy(VBO_ptr, updated_vertices.data(), updated_vertices.size() * sizeof(Vertex));
memcpy(EBO_ptr, indices.data(), indices.size() * sizeof(int));
glUnmapBuffer(GL_ARRAY_BUFFER);
glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
vertices.clear();
vertices = updated_vertices;
}
Now, the problem is that sometimes I got a segmentation fault, and sometimes it runs without errors. I'm sure the issue comes from that function because when I replace the above code by the following one, all of a sudden, no errors, everything runs well (the only drawback with the recreate function that i call instead, is that it induces some really bad performances because I delete the former VAO and create a new set of VAO VBO and EBO):
void Mesh::update_VBO(std::vector<Vertex> const & updated_vertices)
{
indices.clear();
for(int i = 0; i < updated_vertices.size(); i++)
{
indices.push_back(i);
}
recreate(updated_vertices, indices);
/*
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
void * VBO_ptr = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
void * EBO_ptr = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY);
memcpy(VBO_ptr, updated_vertices.data(), updated_vertices.size() * sizeof(Vertex));
memcpy(EBO_ptr, indices.data(), indices.size() * sizeof(int));
glUnmapBuffer(GL_ARRAY_BUFFER);
glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
vertices.clear();
vertices = updated_vertices;
*/
}
One more thing is that the update_VBO function was a function I did for a simpler program with two cubes linked by a rope, the whole thing falling on the ground, and everything worked fine for that small program.
But now that I merged that function into my main project, it fails.
What am I missing?
EDIT : here is the code that fixed my problem as stated in the comment section below
// recreate cable left mesh
prev_c_left_vertices = init_previous_vertices(vertices, fixed_left_vertices);
g->pod->cable_left->get_mesh_collection().at(0)->recreate(prev_c_left_vertices, fixed_left_indices);
// recreate cable right mesh
prev_c_right_vertices = init_previous_vertices(vertices, fixed_right_vertices);
g->pod->cable_right->get_mesh_collection().at(0)->recreate(prev_c_right_vertices, fixed_right_indices);
And here is the full code where I create the soft bodies :
// ----------********** CABLES CREATION
// step simulation
dynamicsWorld->stepSimulation(1.0f/60.0f, 10);
// chariot model
btTransform transform_chariot;
if(chariot_body && chariot_body->getMotionState())
chariot_body->getMotionState()->getWorldTransform(transform_chariot);
transform_chariot.getOpenGLMatrix(glm::value_ptr(chariot_model));
// -----***** create cable left soft body
Mesh* cable_left_mesh = g->pod->cable_left->get_mesh_collection().at(0);
// get rid of duplicated vertices
std::vector<Vertex> vertices = cable_left_mesh->get_vertex_list();
for(int i = 0; i < vertices.size(); i++)
{
glm::vec3 before = vertices.at(i).position;
glm::vec4 before2(before.x, before.y, before.z, 1.0f);
glm::vec4 after = chariot_model * glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, -0.02f, 0.3f)) * before2;
vertices.at(i).position = glm::vec3(after.x, after.y, after.z);
}
std::vector<int> indices = cable_left_mesh->get_index_list();
std::vector<Vertex> fixed_left_vertices;
std::vector<int> fixed_left_indices;
std::vector<std::pair<glm::vec3, int>> couple;
for(int i = 0; i < indices.size(); i += 3) // for each face
{
// get the 3 couples of the current face
glm::vec3 a_pos = vertices.at(indices.at(i)).position;
int a_index = indices.at(i);
glm::vec3 b_pos = vertices.at(indices.at(i+1)).position;
int b_index = indices.at(i+1);
glm::vec3 c_pos = vertices.at(indices.at(i+2)).position;
int c_index = indices.at(i+2);
// check for each couple if its position is already defined by another couple in the clean array
int a_def_index = get_vertex_defined_index(a_pos, a_index, couple);
int b_def_index = get_vertex_defined_index(b_pos, b_index, couple);
int c_def_index = get_vertex_defined_index(c_pos, c_index, couple);
if(a_def_index == -1)
couple.push_back(std::make_pair(a_pos, a_index));
if(b_def_index == -1)
couple.push_back(std::make_pair(b_pos, b_index));
if(c_def_index == -1)
couple.push_back(std::make_pair(c_pos, c_index));
}
for(int i = 0; i < couple.size(); i++)
{
int couple_index = couple.at(i).second;
fixed_left_vertices.push_back(vertices.at(couple_index));
}
for(int i = 0; i < indices.size(); i += 3)
{
glm::vec3 a_pos = vertices.at(indices.at(i)).position;
glm::vec3 b_pos = vertices.at(indices.at(i+1)).position;
glm::vec3 c_pos = vertices.at(indices.at(i+2)).position;
fixed_left_indices.push_back(retrieve_correct_index(a_pos, couple));
fixed_left_indices.push_back(retrieve_correct_index(b_pos, couple));
fixed_left_indices.push_back(retrieve_correct_index(c_pos, couple));
}
// create left soft body
cable_left = btSoftBodyHelpers::CreateFromTriMesh(*softBody_worldInfo, vertex_list_2_btScalarArray(fixed_left_vertices), fixed_left_indices.data(), fixed_left_indices.size() / 3);
// create left soft body material
btSoftBody::Material* left_material = cable_left->appendMaterial();
left_material->m_kLST = 0.75f;
left_material->m_kAST = 0.0f;
left_material->m_kVST = 1.0f;
cable_left->generateBendingConstraints(5, left_material);
cable_left->generateClusters(32);
cable_left->setPose(true, false);
cable_left->setTotalMass(0.65f, true);
cable_left->m_cfg.piterations = 10;
cable_left->randomizeConstraints();
// add left soft body to the dynamics world
dynamicsWorld->addSoftBody(cable_left);
initial_c_left_vertices = fixed_left_vertices;
prev_c_left_vertices = fixed_left_vertices;
// attach left soft body to chariot and reactors
btSoftBody::tNodeArray left_nodes = cable_left->m_nodes;
std::qsort(fixed_left_vertices.data(), fixed_left_vertices.size(), sizeof(Vertex), cmp_vertex);
for(int i = 0; i < left_nodes.size(); i++)
{
btVector3 pos = left_nodes.at(i).m_x;
for(int j = 0; j < 21; j++)
{
glm::vec3 v_pos = fixed_left_vertices.at(j).position;
if(pos.x() == v_pos.x && pos.y() == v_pos.y && pos.z() && v_pos.z)
{
cable_left->appendAnchor(i, chariot_body);
}
}
}
for(int i = 0; i < left_nodes.size(); i++)
{
btVector3 pos = left_nodes.at(i).m_x;
for(int j = fixed_left_vertices.size() - 1; j > fixed_left_vertices.size() - 22; j--)
{
glm::vec3 v_pos = fixed_left_vertices.at(j).position;
if(pos.x() == v_pos.x && pos.y() == v_pos.y && pos.z() && v_pos.z)
{
cable_left->appendAnchor(i, reactors_body);
}
}
}
// recreate cable left mesh
prev_c_left_vertices = init_previous_vertices(vertices, fixed_left_vertices);
g->pod->cable_left->get_mesh_collection().at(0)->recreate(prev_c_left_vertices, fixed_left_indices);
// -----***** create cable right soft body
Mesh* cable_right_mesh = g->pod->cable_right->get_mesh_collection().at(0);
// get rid of duplicated vertices
vertices.clear(); indices.clear();
vertices = cable_right_mesh->get_vertex_list();
for(int i = 0; i < vertices.size(); i++)
{
glm::vec3 before = vertices.at(i).position;
glm::vec4 before2(before.x, before.y, before.z, 1.0f);
glm::vec4 after = chariot_model * glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, -0.02f, 0.3f)) * before2;
vertices.at(i).position = glm::vec3(after.x, after.y, after.z);
}
indices = cable_right_mesh->get_index_list();
std::vector<Vertex> fixed_right_vertices;
std::vector<int> fixed_right_indices;
couple.clear();
for(int i = 0; i < indices.size(); i += 3) // for each face
{
// get the 3 couples of the current face
glm::vec3 a_pos = vertices.at(indices.at(i)).position;
int a_index = indices.at(i);
glm::vec3 b_pos = vertices.at(indices.at(i+1)).position;
int b_index = indices.at(i+1);
glm::vec3 c_pos = vertices.at(indices.at(i+2)).position;
int c_index = indices.at(i+2);
// check for each couple if its position is already defined by another couple in the clean array
int a_def_index = get_vertex_defined_index(a_pos, a_index, couple);
int b_def_index = get_vertex_defined_index(b_pos, b_index, couple);
int c_def_index = get_vertex_defined_index(c_pos, c_index, couple);
if(a_def_index == -1)
couple.push_back(std::make_pair(a_pos, a_index));
if(b_def_index == -1)
couple.push_back(std::make_pair(b_pos, b_index));
if(c_def_index == -1)
couple.push_back(std::make_pair(c_pos, c_index));
}
for(int i = 0; i < couple.size(); i++)
{
int couple_index = couple.at(i).second;
fixed_right_vertices.push_back(vertices.at(couple_index));
}
for(int i = 0; i < indices.size(); i += 3)
{
glm::vec3 a_pos = vertices.at(indices.at(i)).position;
glm::vec3 b_pos = vertices.at(indices.at(i+1)).position;
glm::vec3 c_pos = vertices.at(indices.at(i+2)).position;
fixed_right_indices.push_back(retrieve_correct_index(a_pos, couple));
fixed_right_indices.push_back(retrieve_correct_index(b_pos, couple));
fixed_right_indices.push_back(retrieve_correct_index(c_pos, couple));
}
// create right soft body
cable_right = btSoftBodyHelpers::CreateFromTriMesh(*softBody_worldInfo, vertex_list_2_btScalarArray(fixed_right_vertices), fixed_right_indices.data(), fixed_right_indices.size() / 3);
// create right soft body material
btSoftBody::Material* right_material = cable_right->appendMaterial();
right_material->m_kLST = 0.75f;
right_material->m_kAST = 0.0f;
right_material->m_kVST = 1.0f;
cable_right->generateBendingConstraints(5, right_material); // 2
cable_right->generateClusters(32);
cable_right->setPose(true, false);
cable_right->setTotalMass(0.65f, true);
cable_right->m_cfg.piterations = 10;
cable_right->randomizeConstraints();
// add right soft body to the dynamics world
dynamicsWorld->addSoftBody(cable_right);
initial_c_right_vertices = fixed_right_vertices;
prev_c_right_vertices = fixed_right_vertices;
// attach right soft body to chariot and reactors
btSoftBody::tNodeArray right_nodes = cable_right->m_nodes;
std::qsort(fixed_right_vertices.data(), fixed_right_vertices.size(), sizeof(Vertex), cmp_vertex);
for(int i = 0; i < right_nodes.size(); i++)
{
btVector3 pos = right_nodes.at(i).m_x;
for(int j = 0; j < 21; j++)
{
glm::vec3 v_pos = fixed_right_vertices.at(j).position;
if(pos.x() == v_pos.x && pos.y() == v_pos.y && pos.z() && v_pos.z)
{
cable_right->appendAnchor(i, chariot_body);
}
}
}
for(int i = 0; i < right_nodes.size(); i++)
{
btVector3 pos = right_nodes.at(i).m_x;
for(int j = fixed_right_vertices.size() - 1; j > fixed_right_vertices.size() - 22; j--)
{
glm::vec3 v_pos = fixed_right_vertices.at(j).position;
if(pos.x() == v_pos.x && pos.y() == v_pos.y && pos.z() && v_pos.z)
{
cable_right->appendAnchor(i, reactors_body);
}
}
}
// recreate cable right mesh
prev_c_right_vertices = init_previous_vertices(vertices, fixed_right_vertices);
g->pod->cable_right->get_mesh_collection().at(0)->recreate(prev_c_right_vertices, fixed_right_indices);