Я пытаюсь создать базовое 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;
}
Спасибо.