Основы создания btSoftBody - PullRequest
       68

Основы создания btSoftBody

0 голосов
/ 05 апреля 2020

Я пытаюсь создать базовое c мягкое тело, используя физический движок пули в программе на C ++. Итак, я получил 3D-модель Suzanne от Blender, которую я импортировал в свою программу и объявил как btSoftBody.

Когда я запускаю симуляцию, она падает на землю, но как только она сталкивается с ней, мягкое тело становится совершенно плоским, и вся геометрия разрушается.

Я проверил SoftDemo. cpp, но я не смог выяснить, где были основы создания мягкого тела, добавив ему некоторое внутреннее давление и построить его так, чтобы каждая грань была прикреплена к окружающим.

Я попытался поиграть со свойствами материала жесткости, но безуспешно:

/* Material             */ 
struct  Material : Element
{
    btScalar m_kLST;            // Linear stiffness coefficient [0,1]
    btScalar m_kAST;            // Area/Angular stiffness coefficient [0,1]
    btScalar m_kVST;            // Volume stiffness coefficient [0,1]
    int m_flags;                // Flags
};

Я также попытался поэкспериментировать с кластерами. и другие вещи, которые остаются довольно загадочными для меня. Я просто хочу понять, как мы должны создать базовое c мягкое тело с некоторой жесткостью и внутренним давлением.

Буду признателен за помощь.

Вот мой полный main. cpp:

#include <SDL2/SDL.h>
#include <GL/glew.h>
#include "object.hpp"
#include "mesh.hpp"
#include "shader.hpp"
#include "camera.hpp"
#include "debugDraw.hpp"
#include <iostream>
#include <cmath>
#include <omp.h>
#include <string>
#include <btBulletDynamicsCommon.h>
#include <BulletSoftBody/btSoftRigidDynamicsWorld.h>
#include <BulletSoftBody/btSoftBodyHelpers.h>
#include <BulletSoftBody/btSoftBodyRigidBodyCollisionConfiguration.h>

#define SCREEN_W 1560
#define SCREEN_H 780

// -----global-----
struct UserActions user_actions;
bool app = true;

// -----prototypes-----
SDL_Window* createWindow(int w, int h, const std::string & title);
void check_events(SDL_Event& event, const Uint8* keyboardState, Uint32& mouseButtonBitMask, int& mouseX_rel, int& mouseY_rel);
glm::mat4 bullet2glmMatrix(btScalar* matrix);
btScalar* vertex_list_2_btScalarArray(std::vector<Vertex> const & vertices);
void draw_line(glm::vec3 from, glm::vec3 to, Shader & shader, GLuint & lineVAO, GLuint & lineVBO);

// -----functions-----
SDL_Window* createWindow(int w, int h, const std::string & title)
{
    SDL_Window* window = nullptr;

    if(SDL_Init(SDL_INIT_VIDEO) < 0)
    {
        std::cerr << SDL_GetError() << std::endl;
        return nullptr;
    }

    // OpenGL Version
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 6);

    // Double Buffer
    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);

    window = SDL_CreateWindow(title.c_str(), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, w, h, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);

    if(window == nullptr)
    {
        std::cerr << SDL_GetError() << std::endl;
        return nullptr;
    }

    return window;
}

void check_events(SDL_Event& event, const Uint8* keyboardState, Uint32& mouseButtonBitMask, int& mouseX_rel, int& mouseY_rel)
{
    keyboardState = SDL_GetKeyboardState(nullptr);
    mouseButtonBitMask = SDL_GetRelativeMouseState(&mouseX_rel, &mouseY_rel);

    while(SDL_PollEvent(&event))
    {
        if(event.type == SDL_QUIT)
        {
           app = false; 
        }
        if(event.type == SDL_MOUSEWHEEL)
        {
            user_actions.mouse_scroll = true;
            user_actions.scroll_direction = event.wheel.y;
        }
        else
        {
            user_actions.mouse_scroll = false;
            user_actions.scroll_direction = 0;
        }
        if(event.type == SDL_MOUSEMOTION)
        {
            user_actions.mouseX = event.motion.x;
            user_actions.mouseY = event.motion.y;
        }
    }

    if(SDL_BUTTON(mouseButtonBitMask) == SDL_BUTTON_MIDDLE)
    {
        user_actions.xRel = mouseX_rel;
        user_actions.yRel = mouseY_rel;
        user_actions.mouse_middle = true;
    }
    else
    {
        user_actions.xRel = 0;
        user_actions.yRel = 0;
        user_actions.mouse_middle = false;
    }
    if(SDL_BUTTON(mouseButtonBitMask) == SDL_BUTTON_LEFT)
        user_actions.mouse_left = true;
    else
        user_actions.mouse_left = false;

    if(keyboardState[SDL_SCANCODE_LSHIFT])
        user_actions.key_shift = true;
    else
        user_actions.key_shift = false;
    if(keyboardState[SDL_SCANCODE_DOWN])
        user_actions.key_down = true;
    else
        user_actions.key_down = false;
    if(keyboardState[SDL_SCANCODE_UP])
        user_actions.key_up = true;
    else
        user_actions.key_up = false;
    if(keyboardState[SDL_SCANCODE_LEFT])
        user_actions.key_left = true;
    else
        user_actions.key_left = false;
    if(keyboardState[SDL_SCANCODE_RIGHT])
        user_actions.key_right = true;
    else
        user_actions.key_right = false;
    if(keyboardState[SDL_SCANCODE_SPACE])
        user_actions.key_space = true;
    else
        user_actions.key_space = false;
}

glm::mat4 bullet2glmMatrix(btScalar* matrix)
{
    return glm::mat4(
            matrix[0], matrix[1], matrix[2], matrix[3],
            matrix[4], matrix[5], matrix[6], matrix[7],
            matrix[8], matrix[9], matrix[10], matrix[11],
            matrix[12], matrix[13], matrix[14], matrix[15]);
}

void draw_line(glm::vec3 from, glm::vec3 to, Shader & shader, GLuint & lineVAO, GLuint & lineVBO)
{
    shader.use();
    float vertices[] = {from.x, from.y, from.z, to.x, to.y, to.z};

    glBindVertexArray(lineVAO);
    glBindBuffer(GL_ARRAY_BUFFER, lineVBO);
    glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices);
    glDrawArrays(GL_LINES, 0, 2);
    glBindVertexArray(0);
}

btScalar* vertex_list_2_btScalarArray(std::vector<Vertex> const & vertices)
{
    int nb_vertices = vertices.size();
    int alloc_size = nb_vertices * 3;
    btScalar * v = new btScalar[alloc_size];

    for(int i = 0; i < nb_vertices; i++)
    {
        glm::vec3 pos = vertices.at(i).position;
        v[i*3] = pos.x;
        v[i*3 + 1] = pos.y;
        v[i*3 + 2] = pos.z;
    }

    return v;
}

// -----main-----

int main(int argc, char* argv[])
{
    // create an opengl window
    SDL_Window * window = createWindow(SCREEN_W, SCREEN_H, "test bullet-physics");

    // create OpenGL context
    SDL_GLContext glContext = SDL_GL_CreateContext(window);

    // Glew init
    glewExperimental = true;
    GLenum err = glewInit();
    if(err != GLEW_OK)
    {
        std::cerr << glewGetErrorString(err) << std::endl;
        SDL_GL_DeleteContext(glContext);
        SDL_DestroyWindow(window);
        SDL_Quit();
        std::exit(-1);
    }

    // OpenGL states
    glViewport(0, 0, SCREEN_W, SCREEN_H);
    glEnable(GL_DEPTH_TEST);
    glLineWidth(2.5f);
    SDL_GL_SetSwapInterval(1);

    // lineVAO and lineVBO
    GLuint lineVAO, lineVBO;
    glGenVertexArrays(1, &lineVAO);
    glBindVertexArray(lineVAO);

    glGenBuffers(1, &lineVBO);
    glBindBuffer(GL_ARRAY_BUFFER, lineVBO);
    glBufferData(GL_ARRAY_BUFFER, 6 * sizeof(float), nullptr, GL_DYNAMIC_DRAW);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);

    // create camera
    Camera* cam = new Camera(60.0f, SCREEN_W, SCREEN_H);

    // sunshine
    glm::vec3 sun_dir(1.0f, -1.0f, 1.0f);
    glm::vec3 sun_color(1.0, 1.0, 1.0);

    // line shader
    Shader* line_shader = new Shader("../shaders/line/vertex.glsl", "../shaders/line/fragment.glsl", "../shaders/line/geometry.glsl");
    line_shader->use();
    line_shader->set_Matrix("model", glm::mat4(1.0f));

    // basic shader
    Shader* basic = new Shader("../shaders/vertex.glsl", "../shaders/fragment.glsl", "../shaders/geometry.glsl");
    basic->use();
    basic->set_Matrix("model", glm::mat4(1.0f));
    basic->set_Matrix("view", cam->get_view());
    basic->set_Matrix("proj", cam->get_projection());
    basic->set_vec3f("sun.dir", sun_dir);
    basic->set_vec3f("sun.color", sun_color);

    // load ground
    Object* ground = new Object("../assets/ground.obj", true);

    // load rope
    Object* rope_obj = new Object("../assets/suzy.obj", true, true);
    Mesh* rope_mesh = rope_obj->get_mesh_collection().at(0);

    // ----- bullet initialization start -----
    btDefaultCollisionConfiguration* collisionConfiguration = new btSoftBodyRigidBodyCollisionConfiguration();
    btCollisionDispatcher* dispatcher = new btCollisionDispatcher(collisionConfiguration);
    btBroadphaseInterface* overlappingPairCache = new btDbvtBroadphase();
    btSequentialImpulseConstraintSolver* solver = new btSequentialImpulseConstraintSolver();
    btSoftRigidDynamicsWorld* dynamicsWorld = new btSoftRigidDynamicsWorld(dispatcher, overlappingPairCache, solver, collisionConfiguration);
    dynamicsWorld->setGravity(btVector3(0, -10, 0));

    btIDebugDraw * debug = new DebugDraw();
    dynamicsWorld->setDebugDrawer(debug);

    // ----- bullet initialization end -----

    // array of rigid bodies
    btAlignedObjectArray<btCollisionShape*> collisionShapes;

    // ----- ground static rigid body
    {
        std::vector<Mesh*> meshes = ground->get_mesh_collection();
        for(int i = 0; i < meshes.size(); i++)
        {
            Mesh* m = meshes.at(i);
            const std::vector<Vertex> & vertices = m->get_vertex_list();
            const std::vector<int> & indices = m->get_index_list();

            btConvexHullShape * shape = new btConvexHullShape();
            for(int j = 0; j < indices.size(); j += 3)
            {
                btVector3 v0(vertices.at(indices.at(j)).position.x, vertices.at(indices.at(j)).position.y, vertices.at(indices.at(j)).position.z);
                btVector3 v1(vertices.at(indices.at(j+1)).position.x, vertices.at(indices.at(j+1)).position.y, vertices.at(indices.at(j+1)).position.z);
                btVector3 v2(vertices.at(indices.at(j+2)).position.x, vertices.at(indices.at(j+2)).position.y, vertices.at(indices.at(j+2)).position.z);

                shape->addPoint(v0);
                shape->addPoint(v1);
                shape->addPoint(v2);
            }
            collisionShapes.push_back(shape);

            btTransform trans;
            trans.setIdentity();
            trans.setOrigin(btVector3(0, 0, 0));

            btScalar mass(0.0);
            btVector3 localInertia(0, 0, 0);
            btDefaultMotionState* myMotionState = new btDefaultMotionState(trans);
            btRigidBody::btRigidBodyConstructionInfo rbInfo(mass, myMotionState, shape, localInertia);
            btRigidBody* body = new btRigidBody(rbInfo);

            // add the body to the dynamics world
            dynamicsWorld->addRigidBody(body);
        }
    }

    // rope soft body
    btSoftBodyWorldInfo * worldInfo = new btSoftBodyWorldInfo();
    worldInfo->m_broadphase = overlappingPairCache;
    worldInfo->m_dispatcher = dispatcher;
    worldInfo->m_sparsesdf.Initialize();
    btScalar * rope_vertices = vertex_list_2_btScalarArray(rope_mesh->get_vertex_list());
    int num_triangles = rope_mesh->get_index_list().size() / 3;
    btSoftBody * rope = btSoftBodyHelpers::CreateFromTriMesh(*worldInfo, rope_vertices, rope_mesh->get_index_list().data(), num_triangles);

    dynamicsWorld->addSoftBody(rope);

    // main loop
    glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
    SDL_Event event;
    const Uint8 * keyboardState = nullptr;
    Uint32 mouseButtonBitMask;
    int mouseX_rel = 0, mouseY_rel = 0;
    double delta = 0.0;
    double current_time = 0.0;
    double last_time = 0.0;

    std::vector<Vertex> updated_vertices;
    while(app)
    {
        // compute delta
        last_time = current_time;
        current_time = omp_get_wtime();
        delta = current_time - last_time;

        // update camera data
        check_events(event, keyboardState, mouseButtonBitMask, mouseX_rel, mouseY_rel);
        cam->update_view(user_actions, delta);

        // clear screen
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        // physics simulations
        dynamicsWorld->stepSimulation(1.0f/60.0f, 10);

        // draw
        basic->use();
        basic->set_Matrix("model", glm::mat4(1.0f));
        basic->set_Matrix("view", cam->get_view());
        basic->set_Matrix("proj", cam->get_projection());
        ground->draw(*basic);
        //rope_obj->draw(*basic);

        // draw faces
        line_shader->use();
        line_shader->set_Matrix("model", glm::mat4(1.0f));
        line_shader->set_Matrix("view", cam->get_view());
        line_shader->set_Matrix("proj", cam->get_projection());

        btSoftBody::tFaceArray faces = rope->m_faces;
        updated_vertices.clear();
        for(int i = 0; i < faces.size(); i++)
        {
            glm::vec3 v1(faces[i].m_n[0]->m_x.x(), faces[i].m_n[0]->m_x.y(), faces[i].m_n[0]->m_x.z());
            glm::vec3 v2(faces[i].m_n[1]->m_x.x(), faces[i].m_n[1]->m_x.y(), faces[i].m_n[1]->m_x.z());
            glm::vec3 v3(faces[i].m_n[2]->m_x.x(), faces[i].m_n[2]->m_x.y(), faces[i].m_n[2]->m_x.z());

            glm::vec3 v1_n(faces[i].m_n[0]->m_n.x(), faces[i].m_n[0]->m_n.y(), faces[i].m_n[0]->m_n.z());
            glm::vec3 v2_n(faces[i].m_n[1]->m_n.x(), faces[i].m_n[1]->m_n.y(), faces[i].m_n[1]->m_n.z());
            glm::vec3 v3_n(faces[i].m_n[2]->m_n.x(), faces[i].m_n[2]->m_n.y(), faces[i].m_n[2]->m_n.z());

            //draw_line(v1, v2, *line_shader, lineVAO, lineVBO);
            //draw_line(v1, v3, *line_shader, lineVAO, lineVBO);
            //draw_line(v2, v3, *line_shader, lineVAO, lineVBO);

            Vertex vert1(v1, v1_n, glm::vec2(0.5f, 0.5f), glm::vec2(0.0f, 0.0f), glm::vec2(0.0f, 0.0f));
            Vertex vert2(v2, v2_n, glm::vec2(0.5f, 0.5f), glm::vec2(0.0f, 0.0f), glm::vec2(0.0f, 0.0f));
            Vertex vert3(v3, v3_n, glm::vec2(0.5f, 0.5f), glm::vec2(0.0f, 0.0f), glm::vec2(0.0f, 0.0f));
            updated_vertices.push_back(vert1);
            updated_vertices.push_back(vert2);
            updated_vertices.push_back(vert3);
        }
        rope_mesh->update_VBO(updated_vertices);

        // draw
        basic->use();
        rope_obj->draw(*basic);

        SDL_GL_SwapWindow(window);
    }

    // clean
    delete(rope_vertices);
    SDL_GL_DeleteContext(glContext);
    SDL_DestroyWindow(window);
    SDL_Quit();

    return 0;
}

Спасибо.

1 Ответ

0 голосов
/ 07 апреля 2020

Хорошо, я исправил это. Мне просто пришлось удалить несколько дублированных вершин в me sh.

...