0
votes

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.

cubes and rope soft body

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);
1
I tried and I still get a segmentation fault, thanks for the fast answer though !user10085369

1 Answers

0
votes

It sounds like you're trying to push more vertices in your buffer than you allocated space for. You can update a buffer at will only as long as it's the same size, if you want to increase the number of vertices you have to reallocate it.