diff options
Diffstat (limited to 'modules/bullet/soft_body_bullet.cpp')
-rw-r--r-- | modules/bullet/soft_body_bullet.cpp | 303 |
1 files changed, 303 insertions, 0 deletions
diff --git a/modules/bullet/soft_body_bullet.cpp b/modules/bullet/soft_body_bullet.cpp new file mode 100644 index 0000000000..64ef7bfad2 --- /dev/null +++ b/modules/bullet/soft_body_bullet.cpp @@ -0,0 +1,303 @@ +/*************************************************************************/ +/* soft_body_bullet.cpp */ +/* Author: AndreaCatania */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 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 "space_bullet.h" + +#include "scene/3d/immediate_geometry.h" + +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<SpatialMaterial>(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<int> p_indices, PoolVector<Vector3> 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<TrimeshSoftShapeData *>(soft_body_shape_data); + + Vector<int> indices; + Vector<btScalar> 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<int>::Read i_r = trimesh_data->m_triangles_indices.read(); + for (i = 0; i < indices_size; ++i) { + indices[i] = i_r[i]; + } + i_r = PoolVector<int>::Read(); + + PoolVector<Vector3>::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<Vector3>::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; +} |