/*************************************************************************/ /* soft_body_bullet.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ /* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ /* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ /* "Software"), to deal in the Software without restriction, including */ /* without limitation the rights to use, copy, modify, merge, publish, */ /* distribute, sublicense, and/or sell copies of the Software, and to */ /* permit persons to whom the Software is furnished to do so, subject to */ /* the following conditions: */ /* */ /* The above copyright notice and this permission notice shall be */ /* included in all copies or substantial portions of the Software. */ /* */ /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "soft_body_bullet.h" #include "bullet_types_converter.h" #include "bullet_utilities.h" #include "scene/3d/immediate_geometry.h" #include "space_bullet.h" /** @author AndreaCatania */ SoftBodyBullet::SoftBodyBullet() : CollisionObjectBullet(CollisionObjectBullet::TYPE_SOFT_BODY), mass(1), simulation_precision(5), stiffness(0.5f), pressure_coefficient(50), damping_coefficient(0.005), drag_coefficient(0.005), bt_soft_body(NULL), soft_shape_type(SOFT_SHAPETYPE_NONE), isScratched(false), soft_body_shape_data(NULL) { test_geometry = memnew(ImmediateGeometry); red_mat = Ref(memnew(SpatialMaterial)); red_mat->set_flag(SpatialMaterial::FLAG_UNSHADED, true); red_mat->set_line_width(20.0); red_mat->set_feature(SpatialMaterial::FEATURE_TRANSPARENT, true); red_mat->set_flag(SpatialMaterial::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); red_mat->set_flag(SpatialMaterial::FLAG_SRGB_VERTEX_COLOR, true); red_mat->set_albedo(Color(1, 0, 0, 1)); test_geometry->set_material_override(red_mat); test_is_in_scene = false; } SoftBodyBullet::~SoftBodyBullet() { bulletdelete(soft_body_shape_data); } void SoftBodyBullet::reload_body() { if (space) { space->remove_soft_body(this); space->add_soft_body(this); } } void SoftBodyBullet::set_space(SpaceBullet *p_space) { if (space) { isScratched = false; // Remove this object from the physics world space->remove_soft_body(this); } space = p_space; if (space) { space->add_soft_body(this); } reload_soft_body(); } void SoftBodyBullet::dispatch_callbacks() { if (!bt_soft_body) { return; } if (!test_is_in_scene) { test_is_in_scene = true; SceneTree::get_singleton()->get_current_scene()->add_child(test_geometry); } test_geometry->clear(); test_geometry->begin(Mesh::PRIMITIVE_LINES, NULL); bool first = true; Vector3 pos; for (int i = 0; i < bt_soft_body->m_nodes.size(); ++i) { const btSoftBody::Node &n = bt_soft_body->m_nodes[i]; B_TO_G(n.m_x, pos); test_geometry->add_vertex(pos); if (!first) { test_geometry->add_vertex(pos); } else { first = false; } } test_geometry->end(); } void SoftBodyBullet::on_collision_filters_change() { } void SoftBodyBullet::on_collision_checker_start() { } void SoftBodyBullet::on_enter_area(AreaBullet *p_area) { } void SoftBodyBullet::on_exit_area(AreaBullet *p_area) { } void SoftBodyBullet::set_trimesh_body_shape(PoolVector p_indices, PoolVector p_vertices, int p_triangles_num) { TrimeshSoftShapeData *shape_data = bulletnew(TrimeshSoftShapeData); shape_data->m_triangles_indices = p_indices; shape_data->m_vertices = p_vertices; shape_data->m_triangles_num = p_triangles_num; set_body_shape_data(shape_data, SOFT_SHAPE_TYPE_TRIMESH); reload_soft_body(); } void SoftBodyBullet::set_body_shape_data(SoftShapeData *p_soft_shape_data, SoftShapeType p_type) { bulletdelete(soft_body_shape_data); soft_body_shape_data = p_soft_shape_data; soft_shape_type = p_type; } void SoftBodyBullet::set_transform(const Transform &p_transform) { transform = p_transform; if (bt_soft_body) { // TODO the softbody set new transform considering the current transform as center of world // like if it's local transform, so I must fix this by setting nwe transform considering the old btTransform bt_trans; G_TO_B(transform, bt_trans); //bt_soft_body->transform(bt_trans); } } const Transform &SoftBodyBullet::get_transform() const { return transform; } void SoftBodyBullet::get_first_node_origin(btVector3 &p_out_origin) const { if (bt_soft_body && bt_soft_body->m_nodes.size()) { p_out_origin = bt_soft_body->m_nodes[0].m_x; } else { p_out_origin.setZero(); } } void SoftBodyBullet::set_activation_state(bool p_active) { if (p_active) { bt_soft_body->setActivationState(ACTIVE_TAG); } else { bt_soft_body->setActivationState(WANTS_DEACTIVATION); } } void SoftBodyBullet::set_mass(real_t p_val) { if (0 >= p_val) { p_val = 1; } mass = p_val; if (bt_soft_body) { bt_soft_body->setTotalMass(mass); } } void SoftBodyBullet::set_stiffness(real_t p_val) { stiffness = p_val; if (bt_soft_body) { mat0->m_kAST = stiffness; mat0->m_kLST = stiffness; mat0->m_kVST = stiffness; } } void SoftBodyBullet::set_simulation_precision(int p_val) { simulation_precision = p_val; if (bt_soft_body) { bt_soft_body->m_cfg.piterations = simulation_precision; } } void SoftBodyBullet::set_pressure_coefficient(real_t p_val) { pressure_coefficient = p_val; if (bt_soft_body) { bt_soft_body->m_cfg.kPR = pressure_coefficient; } } void SoftBodyBullet::set_damping_coefficient(real_t p_val) { damping_coefficient = p_val; if (bt_soft_body) { bt_soft_body->m_cfg.kDP = damping_coefficient; } } void SoftBodyBullet::set_drag_coefficient(real_t p_val) { drag_coefficient = p_val; if (bt_soft_body) { bt_soft_body->m_cfg.kDG = drag_coefficient; } } void SoftBodyBullet::reload_soft_body() { destroy_soft_body(); create_soft_body(); if (bt_soft_body) { // TODO the softbody set new transform considering the current transform as center of world // like if it's local transform, so I must fix this by setting nwe transform considering the old btTransform bt_trans; G_TO_B(transform, bt_trans); bt_soft_body->transform(bt_trans); bt_soft_body->generateBendingConstraints(2, mat0); mat0->m_kAST = stiffness; mat0->m_kLST = stiffness; mat0->m_kVST = stiffness; bt_soft_body->m_cfg.piterations = simulation_precision; bt_soft_body->m_cfg.kDP = damping_coefficient; bt_soft_body->m_cfg.kDG = drag_coefficient; bt_soft_body->m_cfg.kPR = pressure_coefficient; bt_soft_body->setTotalMass(mass); } if (space) { // TODO remove this please space->add_soft_body(this); } } void SoftBodyBullet::create_soft_body() { if (!space || !soft_body_shape_data) { return; } ERR_FAIL_COND(!space->is_using_soft_world()); switch (soft_shape_type) { case SOFT_SHAPE_TYPE_TRIMESH: { TrimeshSoftShapeData *trimesh_data = static_cast(soft_body_shape_data); Vector indices; Vector vertices; int i; const int indices_size = trimesh_data->m_triangles_indices.size(); const int vertices_size = trimesh_data->m_vertices.size(); indices.resize(indices_size); vertices.resize(vertices_size * 3); PoolVector::Read i_r = trimesh_data->m_triangles_indices.read(); for (i = 0; i < indices_size; ++i) { indices[i] = i_r[i]; } i_r = PoolVector::Read(); PoolVector::Read f_r = trimesh_data->m_vertices.read(); for (int j = i = 0; i < vertices_size; ++i, j += 3) { vertices[j + 0] = f_r[i][0]; vertices[j + 1] = f_r[i][1]; vertices[j + 2] = f_r[i][2]; } f_r = PoolVector::Read(); bt_soft_body = btSoftBodyHelpers::CreateFromTriMesh(*space->get_soft_body_world_info(), vertices.ptr(), indices.ptr(), trimesh_data->m_triangles_num); } break; default: ERR_PRINT("Shape type not supported"); return; } setupBulletCollisionObject(bt_soft_body); bt_soft_body->getCollisionShape()->setMargin(0.001f); bt_soft_body->setCollisionFlags(bt_soft_body->getCollisionFlags() & (~(btCollisionObject::CF_KINEMATIC_OBJECT | btCollisionObject::CF_STATIC_OBJECT))); mat0 = bt_soft_body->appendMaterial(); } void SoftBodyBullet::destroy_soft_body() { if (space) { /// This step is required to assert that the body is not into the world during deletion /// This step is required since to change the body shape the body must be re-created. /// Here is handled the case when the body is assigned into a world and the body /// shape is changed. space->remove_soft_body(this); } destroyBulletCollisionObject(); bt_soft_body = NULL; }