【问题标题】:Update a mesh VBO更新网格 VBO
【发布时间】:2020-05-12 18:30:24
【问题描述】:

我使用子弹物理引擎运行了一个软体模拟,因此我必须在每一帧更新网格顶点的位置。为此,我使用以下函数:

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;
}

现在,问题是有时我遇到了分段错误,有时它运行时没有错误。 我确定问题出在那个函数上,因为当我用下面的代码替换上面的代码时,突然之间,没有错误,一切运行良好(recreate 函数的唯一缺点是我相反,是否会导致一些非常糟糕的性能,因为我删除了以前的 VAO 并创建了一组新的 VAO VBO 和 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;
*/
}

还有一件事是 update_VBO 函数是我为一个更简单的程序所做的函数,该程序有两个由绳索连接的立方体,整个物体掉在地上,对于那个小程序来说一切正常程序。

但是现在我将该功能合并到我的主项目中,它失败了。

我错过了什么?

编辑: 这是解决我的问题的代码,如下面的评论部分所述

// 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);

这是我创建软体的完整代码:

    // ----------********** 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);

【问题讨论】:

  • 我试过了,但仍然遇到分段错误,不过感谢您的快速回答!

标签: c++ opengl bullet


【解决方案1】:

听起来您试图在缓冲区中推送比分配空间更多的顶点。只要缓冲区大小相同,就可以随意更新缓冲区,如果要增加必须重新分配的顶点数。

【讨论】:

  • 是的,我在用两个立方体编写程序时想到了这一点,因为我有一个由该问题引起的段错误,所以我将初始缓冲区大小乘以 100 来防止这种情况。所以我想这不是问题所在,因为我在另一个失败的程序中也使用了这个技巧。
  • “我猜”——这让我很担心,是不是有问题?您在memcpy 之一上看到的错误是访问冲突吗?查看保存您正在复制的数据大小的变量,它们有意义吗?它们是否小于您为缓冲区分配的大小?
  • 此外,如果您的索引只是从 0 开始顺序排列,那么您就是在浪费性能,而没有从中获得任何收益。只是不要使用索引缓冲区。
  • 谢谢,你给了我一个提示,我插入了一些用于 VBO 大小的打印,一个打印没有被调用,被调用的打印在 update_VBO 函数中,其他的是在重新创建功能中。子弹物理引擎创建了一个充满重复顶点的柔体网格,所以在我使用构造函数加载 obj 网格之后,我必须删除由柔体创建产生的所有重复顶点,这就是为什么我然后调用 recreate 函数生成一个干净的网格,然后对于每一帧,我调用 update_VBO。
  • 谢谢盲人!
猜你喜欢
  • 1970-01-01
  • 2011-05-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-05
  • 2023-03-13
  • 2020-11-10
相关资源
最近更新 更多