Implemented Soft body

- Soft Body Physics node
- Soft Body Rendering
- Soft body Editor
- Soft body importer
This commit is contained in:
AndreaCatania 2017-11-21 01:36:32 +01:00 committed by Andrea Catania
parent fbf3ad2841
commit 17ebbfb56d
32 changed files with 2086 additions and 274 deletions

View file

@ -169,7 +169,7 @@ real_t BulletPhysicsServer::shape_get_custom_solver_bias(RID p_shape) const {
}
RID BulletPhysicsServer::space_create() {
SpaceBullet *space = bulletnew(SpaceBullet(false));
SpaceBullet *space = bulletnew(SpaceBullet);
CreateThenReturnRID(space_owner, space);
}
@ -567,9 +567,6 @@ void BulletPhysicsServer::body_clear_shapes(RID p_body) {
void BulletPhysicsServer::body_attach_object_instance_id(RID p_body, uint32_t p_ID) {
CollisionObjectBullet *body = get_collisin_object(p_body);
if (!body) {
body = soft_body_owner.get(p_body);
}
ERR_FAIL_COND(!body);
body->set_instance_id(p_ID);
@ -867,6 +864,13 @@ RID BulletPhysicsServer::soft_body_create(bool p_init_sleeping) {
CreateThenReturnRID(soft_body_owner, body);
}
void BulletPhysicsServer::soft_body_update_visual_server(RID p_body, class SoftBodyVisualServerHandler *p_visual_server_handler) {
SoftBodyBullet *body = soft_body_owner.get(p_body);
ERR_FAIL_COND(!body);
body->update_visual_server(p_visual_server_handler);
}
void BulletPhysicsServer::soft_body_set_space(RID p_body, RID p_space) {
SoftBodyBullet *body = soft_body_owner.get(p_body);
ERR_FAIL_COND(!body);
@ -893,11 +897,11 @@ RID BulletPhysicsServer::soft_body_get_space(RID p_body) const {
return space->get_self();
}
void BulletPhysicsServer::soft_body_set_trimesh_body_shape(RID p_body, PoolVector<int> p_indices, PoolVector<Vector3> p_vertices, int p_triangles_num) {
void BulletPhysicsServer::soft_body_set_mesh(RID p_body, const REF &p_mesh) {
SoftBodyBullet *body = soft_body_owner.get(p_body);
ERR_FAIL_COND(!body);
body->set_trimesh_body_shape(p_indices, p_vertices, p_triangles_num);
body->set_soft_mesh(p_mesh);
}
void BulletPhysicsServer::soft_body_set_collision_layer(RID p_body, uint32_t p_layer) {
@ -975,14 +979,16 @@ void BulletPhysicsServer::soft_body_set_transform(RID p_body, const Transform &p
SoftBodyBullet *body = soft_body_owner.get(p_body);
ERR_FAIL_COND(!body);
body->set_transform(p_transform);
body->set_soft_transform(p_transform);
}
Transform BulletPhysicsServer::soft_body_get_transform(RID p_body) const {
Vector3 BulletPhysicsServer::soft_body_get_vertex_position(RID p_body, int vertex_index) const {
const SoftBodyBullet *body = soft_body_owner.get(p_body);
ERR_FAIL_COND_V(!body, Transform());
Vector3 pos;
ERR_FAIL_COND_V(!body, pos);
return body->get_transform();
body->get_node_position(vertex_index, pos);
return pos;
}
void BulletPhysicsServer::soft_body_set_ray_pickable(RID p_body, bool p_enable) {
@ -997,6 +1003,154 @@ bool BulletPhysicsServer::soft_body_is_ray_pickable(RID p_body) const {
return body->is_ray_pickable();
}
void BulletPhysicsServer::soft_body_set_simulation_precision(RID p_body, int p_simulation_precision) {
SoftBodyBullet *body = soft_body_owner.get(p_body);
ERR_FAIL_COND(!body);
body->set_simulation_precision(p_simulation_precision);
}
int BulletPhysicsServer::soft_body_get_simulation_precision(RID p_body) {
SoftBodyBullet *body = soft_body_owner.get(p_body);
ERR_FAIL_COND_V(!body, 0.f);
return body->get_simulation_precision();
}
void BulletPhysicsServer::soft_body_set_total_mass(RID p_body, real_t p_total_mass) {
SoftBodyBullet *body = soft_body_owner.get(p_body);
ERR_FAIL_COND(!body);
body->set_total_mass(p_total_mass);
}
real_t BulletPhysicsServer::soft_body_get_total_mass(RID p_body) {
SoftBodyBullet *body = soft_body_owner.get(p_body);
ERR_FAIL_COND_V(!body, 0.f);
return body->get_total_mass();
}
void BulletPhysicsServer::soft_body_set_linear_stiffness(RID p_body, real_t p_stiffness) {
SoftBodyBullet *body = soft_body_owner.get(p_body);
ERR_FAIL_COND(!body);
body->set_linear_stiffness(p_stiffness);
}
real_t BulletPhysicsServer::soft_body_get_linear_stiffness(RID p_body) {
SoftBodyBullet *body = soft_body_owner.get(p_body);
ERR_FAIL_COND_V(!body, 0.f);
return body->get_linear_stiffness();
}
void BulletPhysicsServer::soft_body_set_areaAngular_stiffness(RID p_body, real_t p_stiffness) {
SoftBodyBullet *body = soft_body_owner.get(p_body);
ERR_FAIL_COND(!body);
body->set_areaAngular_stiffness(p_stiffness);
}
real_t BulletPhysicsServer::soft_body_get_areaAngular_stiffness(RID p_body) {
SoftBodyBullet *body = soft_body_owner.get(p_body);
ERR_FAIL_COND_V(!body, 0.f);
return body->get_areaAngular_stiffness();
}
void BulletPhysicsServer::soft_body_set_volume_stiffness(RID p_body, real_t p_stiffness) {
SoftBodyBullet *body = soft_body_owner.get(p_body);
ERR_FAIL_COND(!body);
body->set_volume_stiffness(p_stiffness);
}
real_t BulletPhysicsServer::soft_body_get_volume_stiffness(RID p_body) {
SoftBodyBullet *body = soft_body_owner.get(p_body);
ERR_FAIL_COND_V(!body, 0.f);
return body->get_volume_stiffness();
}
void BulletPhysicsServer::soft_body_set_pressure_coefficient(RID p_body, real_t p_pressure_coefficient) {
SoftBodyBullet *body = soft_body_owner.get(p_body);
ERR_FAIL_COND(!body);
body->set_pressure_coefficient(p_pressure_coefficient);
}
real_t BulletPhysicsServer::soft_body_get_pressure_coefficient(RID p_body) {
SoftBodyBullet *body = soft_body_owner.get(p_body);
ERR_FAIL_COND_V(!body, 0.f);
return body->get_pressure_coefficient();
}
void BulletPhysicsServer::soft_body_set_pose_matching_coefficient(RID p_body, real_t p_pose_matching_coefficient) {
SoftBodyBullet *body = soft_body_owner.get(p_body);
ERR_FAIL_COND(!body);
return body->set_pose_matching_coefficient(p_pose_matching_coefficient);
}
real_t BulletPhysicsServer::soft_body_get_pose_matching_coefficient(RID p_body) {
SoftBodyBullet *body = soft_body_owner.get(p_body);
ERR_FAIL_COND_V(!body, 0.f);
return body->get_pose_matching_coefficient();
}
void BulletPhysicsServer::soft_body_set_damping_coefficient(RID p_body, real_t p_damping_coefficient) {
SoftBodyBullet *body = soft_body_owner.get(p_body);
ERR_FAIL_COND(!body);
body->set_damping_coefficient(p_damping_coefficient);
}
real_t BulletPhysicsServer::soft_body_get_damping_coefficient(RID p_body) {
SoftBodyBullet *body = soft_body_owner.get(p_body);
ERR_FAIL_COND_V(!body, 0.f);
return body->get_damping_coefficient();
}
void BulletPhysicsServer::soft_body_set_drag_coefficient(RID p_body, real_t p_drag_coefficient) {
SoftBodyBullet *body = soft_body_owner.get(p_body);
ERR_FAIL_COND(!body);
body->set_drag_coefficient(p_drag_coefficient);
}
real_t BulletPhysicsServer::soft_body_get_drag_coefficient(RID p_body) {
SoftBodyBullet *body = soft_body_owner.get(p_body);
ERR_FAIL_COND_V(!body, 0.f);
return body->get_drag_coefficient();
}
void BulletPhysicsServer::soft_body_move_point(RID p_body, int p_point_index, const Vector3 &p_global_position) {
SoftBodyBullet *body = soft_body_owner.get(p_body);
ERR_FAIL_COND(!body);
body->set_node_position(p_point_index, p_global_position);
}
Vector3 BulletPhysicsServer::soft_body_get_point_global_position(RID p_body, int p_point_index) {
SoftBodyBullet *body = soft_body_owner.get(p_body);
ERR_FAIL_COND_V(!body, Vector3(0., 0., 0.));
Vector3 pos;
body->get_node_position(p_point_index, pos);
return pos;
}
Vector3 BulletPhysicsServer::soft_body_get_point_offset(RID p_body, int p_point_index) const {
SoftBodyBullet *body = soft_body_owner.get(p_body);
ERR_FAIL_COND_V(!body, Vector3());
Vector3 res;
body->get_node_offset(p_point_index, res);
return res;
}
void BulletPhysicsServer::soft_body_remove_all_pinned_points(RID p_body) {
SoftBodyBullet *body = soft_body_owner.get(p_body);
ERR_FAIL_COND(!body);
body->reset_all_node_mass();
}
void BulletPhysicsServer::soft_body_pin_point(RID p_body, int p_point_index, bool p_pin) {
SoftBodyBullet *body = soft_body_owner.get(p_body);
ERR_FAIL_COND(!body);
body->set_node_mass(p_point_index, p_pin ? 0 : 1);
}
bool BulletPhysicsServer::soft_body_is_point_pinned(RID p_body, int p_point_index) {
SoftBodyBullet *body = soft_body_owner.get(p_body);
ERR_FAIL_COND_V(!body, 0.f);
return body->get_node_mass(p_point_index);
}
PhysicsServer::JointType BulletPhysicsServer::joint_get_type(RID p_joint) const {
JointBullet *joint = joint_owner.get(p_joint);
ERR_FAIL_COND_V(!joint, JOINT_PIN);

View file

@ -262,10 +262,12 @@ public:
virtual RID soft_body_create(bool p_init_sleeping = false);
virtual void soft_body_update_visual_server(RID p_body, class SoftBodyVisualServerHandler *p_visual_server_handler);
virtual void soft_body_set_space(RID p_body, RID p_space);
virtual RID soft_body_get_space(RID p_body) const;
virtual void soft_body_set_trimesh_body_shape(RID p_body, PoolVector<int> p_indices, PoolVector<Vector3> p_vertices, int p_triangles_num);
virtual void soft_body_set_mesh(RID p_body, const REF &p_mesh);
virtual void soft_body_set_collision_layer(RID p_body, uint32_t p_layer);
virtual uint32_t soft_body_get_collision_layer(RID p_body) const;
@ -280,12 +282,49 @@ public:
virtual void soft_body_set_state(RID p_body, BodyState p_state, const Variant &p_variant);
virtual Variant soft_body_get_state(RID p_body, BodyState p_state) const;
/// Special function. This function has bad performance
virtual void soft_body_set_transform(RID p_body, const Transform &p_transform);
virtual Transform soft_body_get_transform(RID p_body) const;
virtual Vector3 soft_body_get_vertex_position(RID p_body, int vertex_index) const;
virtual void soft_body_set_ray_pickable(RID p_body, bool p_enable);
virtual bool soft_body_is_ray_pickable(RID p_body) const;
virtual void soft_body_set_simulation_precision(RID p_body, int p_simulation_precision);
virtual int soft_body_get_simulation_precision(RID p_body);
virtual void soft_body_set_total_mass(RID p_body, real_t p_total_mass);
virtual real_t soft_body_get_total_mass(RID p_body);
virtual void soft_body_set_linear_stiffness(RID p_body, real_t p_stiffness);
virtual real_t soft_body_get_linear_stiffness(RID p_body);
virtual void soft_body_set_areaAngular_stiffness(RID p_body, real_t p_stiffness);
virtual real_t soft_body_get_areaAngular_stiffness(RID p_body);
virtual void soft_body_set_volume_stiffness(RID p_body, real_t p_stiffness);
virtual real_t soft_body_get_volume_stiffness(RID p_body);
virtual void soft_body_set_pressure_coefficient(RID p_body, real_t p_pressure_coefficient);
virtual real_t soft_body_get_pressure_coefficient(RID p_body);
virtual void soft_body_set_pose_matching_coefficient(RID p_body, real_t p_pose_matching_coefficient);
virtual real_t soft_body_get_pose_matching_coefficient(RID p_body);
virtual void soft_body_set_damping_coefficient(RID p_body, real_t p_damping_coefficient);
virtual real_t soft_body_get_damping_coefficient(RID p_body);
virtual void soft_body_set_drag_coefficient(RID p_body, real_t p_drag_coefficient);
virtual real_t soft_body_get_drag_coefficient(RID p_body);
virtual void soft_body_move_point(RID p_body, int p_point_index, const Vector3 &p_global_position);
virtual Vector3 soft_body_get_point_global_position(RID p_body, int p_point_index);
virtual Vector3 soft_body_get_point_offset(RID p_body, int p_point_index) const;
virtual void soft_body_remove_all_pinned_points(RID p_body);
virtual void soft_body_pin_point(RID p_body, int p_point_index, bool p_pin);
virtual bool soft_body_is_point_pinned(RID p_body, int p_point_index);
/* JOINT API */
virtual JointType joint_get_type(RID p_joint) const;

View file

@ -111,6 +111,8 @@ void CollisionObjectBullet::setupBulletCollisionObject(btCollisionObject *p_coll
void CollisionObjectBullet::add_collision_exception(const CollisionObjectBullet *p_ignoreCollisionObject) {
exceptions.insert(p_ignoreCollisionObject->get_self());
if (!bt_collision_object)
return;
bt_collision_object->setIgnoreCollisionCheck(p_ignoreCollisionObject->bt_collision_object, true);
if (space)
space->get_broadphase()->getOverlappingPairCache()->cleanProxyFromPairs(bt_collision_object->getBroadphaseHandle(), space->get_dispatcher());

View file

@ -32,6 +32,7 @@
#include "bullet_physics_server.h"
#include "class_db.h"
#include "project_settings.h"
/**
@author AndreaCatania
@ -47,6 +48,9 @@ void register_bullet_types() {
#ifndef _3D_DISABLED
PhysicsServerManager::register_server("Bullet", &_createBulletPhysicsCallback);
PhysicsServerManager::set_default_server("Bullet", 1);
GLOBAL_DEF("physics/3d/active_soft_world", true);
ProjectSettings::get_singleton()->set_custom_property_info("physics/3d/active_soft_world", PropertyInfo(Variant::BOOL, "physics/3d/active_soft_world"));
#endif
}

View file

@ -32,42 +32,24 @@
#include "bullet_types_converter.h"
#include "bullet_utilities.h"
#include "scene/3d/immediate_geometry.h"
#include "scene/3d/soft_body.h"
#include "space_bullet.h"
/**
@author AndreaCatania
*/
SoftBodyBullet::SoftBodyBullet() :
CollisionObjectBullet(CollisionObjectBullet::TYPE_SOFT_BODY),
mass(1),
total_mass(1),
simulation_precision(5),
stiffness(0.5f),
pressure_coefficient(50),
damping_coefficient(0.005),
drag_coefficient(0.005),
linear_stiffness(0.5),
areaAngular_stiffness(0.5),
volume_stiffness(0.5),
pressure_coefficient(0.),
pose_matching_coefficient(0.),
damping_coefficient(0.01),
drag_coefficient(0.),
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;
}
isScratched(false) {}
SoftBodyBullet::~SoftBodyBullet() {
bulletdelete(soft_body_shape_data);
}
void SoftBodyBullet::reload_body() {
@ -80,8 +62,6 @@ void SoftBodyBullet::reload_body() {
void SoftBodyBullet::set_space(SpaceBullet *p_space) {
if (space) {
isScratched = false;
// Remove this object from the physics world
space->remove_soft_body(this);
}
@ -90,86 +70,181 @@ void SoftBodyBullet::set_space(SpaceBullet *p_space) {
if (space) {
space->add_soft_body(this);
}
reload_soft_body();
}
void SoftBodyBullet::dispatch_callbacks() {
if (!bt_soft_body) {
void SoftBodyBullet::dispatch_callbacks() {}
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::update_visual_server(SoftBodyVisualServerHandler *p_visual_server_handler) {
if (!bt_soft_body)
return;
/// Update visual server vertices
const btSoftBody::tNodeArray &nodes(bt_soft_body->m_nodes);
const int nodes_count = nodes.size();
Vector<int> *vs_indices;
const void *vertex_position;
const void *vertex_normal;
for (int vertex_index = 0; vertex_index < nodes_count; ++vertex_index) {
vertex_position = reinterpret_cast<const void *>(&nodes[vertex_index].m_x);
vertex_normal = reinterpret_cast<const void *>(&nodes[vertex_index].m_n);
vs_indices = &indices_table[vertex_index];
const int vs_indices_size(vs_indices->size());
for (int x = 0; x < vs_indices_size; ++x) {
p_visual_server_handler->set_vertex((*vs_indices)[x], vertex_position);
p_visual_server_handler->set_normal((*vs_indices)[x], vertex_normal);
}
}
/// Generate AABB
btVector3 aabb_min;
btVector3 aabb_max;
bt_soft_body->getAabb(aabb_min, aabb_max);
btVector3 size(aabb_max - aabb_min);
AABB aabb;
B_TO_G(aabb_min, aabb.position);
B_TO_G(size, aabb.size);
p_visual_server_handler->set_aabb(aabb);
}
void SoftBodyBullet::set_soft_mesh(const Ref<Mesh> &p_mesh) {
if (p_mesh.is_null() || !p_mesh->surface_is_softbody_friendly(0))
soft_mesh.unref();
else
soft_mesh = p_mesh;
if (soft_mesh.is_null()) {
destroy_soft_body();
return;
}
if (!test_is_in_scene) {
test_is_in_scene = true;
SceneTree::get_singleton()->get_current_scene()->add_child(test_geometry);
Array arrays = soft_mesh->surface_get_arrays(0);
ERR_FAIL_COND(!(soft_mesh->surface_get_format(0) & VS::ARRAY_FORMAT_INDEX));
set_trimesh_body_shape(arrays[VS::ARRAY_INDEX], arrays[VS::ARRAY_VERTEX]);
}
void SoftBodyBullet::destroy_soft_body() {
if (!bt_soft_body)
return;
if (space) {
/// Remove from world before deletion
space->remove_soft_body(this);
}
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;
destroyBulletCollisionObject();
bt_soft_body = NULL;
}
void SoftBodyBullet::set_soft_transform(const Transform &p_transform) {
reset_all_node_positions();
move_all_nodes(p_transform);
}
void SoftBodyBullet::move_all_nodes(const Transform &p_transform) {
if (!bt_soft_body)
return;
btTransform bt_transf;
G_TO_B(p_transform, bt_transf);
bt_soft_body->transform(bt_transf);
}
void SoftBodyBullet::set_node_position(int p_node_index, const Vector3 &p_global_position) {
btVector3 bt_pos;
G_TO_B(p_global_position, bt_pos);
set_node_position(p_node_index, bt_pos);
}
void SoftBodyBullet::set_node_position(int p_node_index, const btVector3 &p_global_position) {
if (bt_soft_body) {
bt_soft_body->m_nodes[p_node_index].m_x = p_global_position;
}
}
void SoftBodyBullet::get_node_position(int p_node_index, Vector3 &r_position) const {
if (bt_soft_body) {
B_TO_G(bt_soft_body->m_nodes[p_node_index].m_x, r_position);
}
}
void SoftBodyBullet::get_node_offset(int p_node_index, Vector3 &r_offset) const {
if (soft_mesh.is_null())
return;
Array arrays = soft_mesh->surface_get_arrays(0);
PoolVector<Vector3> vertices(arrays[VS::ARRAY_VERTEX]);
if (0 <= p_node_index && vertices.size() > p_node_index) {
r_offset = vertices[p_node_index];
}
}
void SoftBodyBullet::get_node_offset(int p_node_index, btVector3 &r_offset) const {
Vector3 off;
get_node_offset(p_node_index, off);
G_TO_B(off, r_offset);
}
void SoftBodyBullet::set_node_mass(int node_index, btScalar p_mass) {
if (0 >= p_mass) {
pin_node(node_index);
} else {
unpin_node(node_index);
}
if (bt_soft_body) {
bt_soft_body->setMass(node_index, p_mass);
}
}
btScalar SoftBodyBullet::get_node_mass(int node_index) const {
if (bt_soft_body) {
return bt_soft_body->getMass(node_index);
} else {
return -1 == search_node_pinned(node_index) ? 1 : 0;
}
}
void SoftBodyBullet::reset_all_node_mass() {
if (bt_soft_body) {
for (int i = pinned_nodes.size() - 1; 0 <= i; --i) {
bt_soft_body->setMass(pinned_nodes[i], 1);
}
}
test_geometry->end();
pinned_nodes.resize(0);
}
void SoftBodyBullet::on_collision_filters_change() {
}
void SoftBodyBullet::reset_all_node_positions() {
if (soft_mesh.is_null())
return;
void SoftBodyBullet::on_collision_checker_start() {
}
Array arrays = soft_mesh->surface_get_arrays(0);
PoolVector<Vector3> vs_vertices(arrays[VS::ARRAY_VERTEX]);
PoolVector<Vector3>::Read vs_vertices_read = vs_vertices.read();
void SoftBodyBullet::on_enter_area(AreaBullet *p_area) {
}
for (int vertex_index = bt_soft_body->m_nodes.size() - 1; 0 <= vertex_index; --vertex_index) {
void SoftBodyBullet::on_exit_area(AreaBullet *p_area) {
}
G_TO_B(vs_vertices_read[indices_table[vertex_index][0]], bt_soft_body->m_nodes[vertex_index].m_x);
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();
bt_soft_body->m_nodes[vertex_index].m_q = bt_soft_body->m_nodes[vertex_index].m_x;
bt_soft_body->m_nodes[vertex_index].m_v = btVector3(0, 0, 0);
bt_soft_body->m_nodes[vertex_index].m_f = btVector3(0, 0, 0);
}
}
@ -181,22 +256,34 @@ void SoftBodyBullet::set_activation_state(bool p_active) {
}
}
void SoftBodyBullet::set_mass(real_t p_val) {
void SoftBodyBullet::set_total_mass(real_t p_val) {
if (0 >= p_val) {
p_val = 1;
}
mass = p_val;
total_mass = p_val;
if (bt_soft_body) {
bt_soft_body->setTotalMass(mass);
bt_soft_body->setTotalMass(total_mass);
}
}
void SoftBodyBullet::set_stiffness(real_t p_val) {
stiffness = p_val;
void SoftBodyBullet::set_linear_stiffness(real_t p_val) {
linear_stiffness = p_val;
if (bt_soft_body) {
mat0->m_kAST = stiffness;
mat0->m_kLST = stiffness;
mat0->m_kVST = stiffness;
mat0->m_kLST = linear_stiffness;
}
}
void SoftBodyBullet::set_areaAngular_stiffness(real_t p_val) {
areaAngular_stiffness = p_val;
if (bt_soft_body) {
mat0->m_kAST = areaAngular_stiffness;
}
}
void SoftBodyBullet::set_volume_stiffness(real_t p_val) {
volume_stiffness = p_val;
if (bt_soft_body) {
mat0->m_kVST = volume_stiffness;
}
}
@ -204,6 +291,9 @@ void SoftBodyBullet::set_simulation_precision(int p_val) {
simulation_precision = p_val;
if (bt_soft_body) {
bt_soft_body->m_cfg.piterations = simulation_precision;
bt_soft_body->m_cfg.viterations = simulation_precision;
bt_soft_body->m_cfg.diterations = simulation_precision;
bt_soft_body->m_cfg.citerations = simulation_precision;
}
}
@ -214,6 +304,13 @@ void SoftBodyBullet::set_pressure_coefficient(real_t p_val) {
}
}
void SoftBodyBullet::set_pose_matching_coefficient(real_t p_val) {
pose_matching_coefficient = p_val;
if (bt_soft_body) {
bt_soft_body->m_cfg.kMT = pose_matching_coefficient;
}
}
void SoftBodyBullet::set_damping_coefficient(real_t p_val) {
damping_coefficient = p_val;
if (bt_soft_body) {
@ -228,89 +325,156 @@ void SoftBodyBullet::set_drag_coefficient(real_t p_val) {
}
}
void SoftBodyBullet::reload_soft_body() {
void SoftBodyBullet::set_trimesh_body_shape(PoolVector<int> p_indices, PoolVector<Vector3> p_vertices) {
/// Assert the current soft body is destroyed
destroy_soft_body();
create_soft_body();
if (bt_soft_body) {
/// Parse visual server indices to physical indices.
/// Merge all overlapping vertices and create a map of physical vertices to visual server
// 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);
{
/// This is the map of visual server indices to physics indices (So it's the inverse of idices_map), Thanks to it I don't need make a heavy search in the indices_map
Vector<int> vs_indices_to_physics_table;
bt_soft_body->generateBendingConstraints(2, mat0);
mat0->m_kAST = stiffness;
mat0->m_kLST = stiffness;
mat0->m_kVST = stiffness;
{ // Map vertices
indices_table.resize(0);
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);
int index = 0;
Map<Vector3, int> unique_vertices;
const int vs_vertices_size(p_vertices.size());
PoolVector<Vector3>::Read p_vertices_read = p_vertices.read();
for (int vs_vertex_index = 0; vs_vertex_index < vs_vertices_size; ++vs_vertex_index) {
Map<Vector3, int>::Element *e = unique_vertices.find(p_vertices_read[vs_vertex_index]);
int vertex_id;
if (e) {
// Already rxisting
vertex_id = e->value();
} else {
// Create new one
unique_vertices[p_vertices_read[vs_vertex_index]] = vertex_id = index++;
indices_table.push_back(Vector<int>());
}
indices_table[vertex_id].push_back(vs_vertex_index);
vs_indices_to_physics_table.push_back(vertex_id);
}
}
const int indices_map_size(indices_table.size());
Vector<btScalar> bt_vertices;
{ // Parse vertices to bullet
bt_vertices.resize(indices_map_size * 3);
PoolVector<Vector3>::Read p_vertices_read = p_vertices.read();
for (int i = 0; i < indices_map_size; ++i) {
bt_vertices[3 * i + 0] = p_vertices_read[indices_table[i][0]].x;
bt_vertices[3 * i + 1] = p_vertices_read[indices_table[i][0]].y;
bt_vertices[3 * i + 2] = p_vertices_read[indices_table[i][0]].z;
}
}
Vector<int> bt_triangles;
const int triangles_size(p_indices.size() / 3);
{ // Parse indices
bt_triangles.resize(triangles_size * 3);
PoolVector<int>::Read p_indices_read = p_indices.read();
for (int i = 0; i < triangles_size; ++i) {
bt_triangles[3 * i + 0] = vs_indices_to_physics_table[p_indices_read[3 * i + 2]];
bt_triangles[3 * i + 1] = vs_indices_to_physics_table[p_indices_read[3 * i + 1]];
bt_triangles[3 * i + 2] = vs_indices_to_physics_table[p_indices_read[3 * i + 0]];
}
}
btSoftBodyWorldInfo fake_world_info;
bt_soft_body = btSoftBodyHelpers::CreateFromTriMesh(fake_world_info, &bt_vertices[0], &bt_triangles[0], triangles_size, false);
setup_soft_body();
}
}
void SoftBodyBullet::setup_soft_body() {
if (!bt_soft_body)
return;
// Soft body setup
setupBulletCollisionObject(bt_soft_body);
bt_soft_body->m_worldInfo = NULL; // Remove fake world info
bt_soft_body->getCollisionShape()->setMargin(0.01);
bt_soft_body->setCollisionFlags(bt_soft_body->getCollisionFlags() & (~(btCollisionObject::CF_KINEMATIC_OBJECT | btCollisionObject::CF_STATIC_OBJECT)));
// Space setup
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();
// Assign soft body data
bt_soft_body->generateBendingConstraints(2, mat0);
mat0->m_kLST = linear_stiffness;
mat0->m_kAST = areaAngular_stiffness;
mat0->m_kVST = volume_stiffness;
// Clusters allow to have Soft vs Soft collision but doesn't work well right now
//bt_soft_body->m_cfg.kSRHR_CL = 1;// Soft vs rigid hardness [0,1] (cluster only)
//bt_soft_body->m_cfg.kSKHR_CL = 1;// Soft vs kinematic hardness [0,1] (cluster only)
//bt_soft_body->m_cfg.kSSHR_CL = 1;// Soft vs soft hardness [0,1] (cluster only)
//bt_soft_body->m_cfg.kSR_SPLT_CL = 1; // Soft vs rigid impulse split [0,1] (cluster only)
//bt_soft_body->m_cfg.kSK_SPLT_CL = 1; // Soft vs kinematic impulse split [0,1] (cluster only)
//bt_soft_body->m_cfg.kSS_SPLT_CL = 1; // Soft vs Soft impulse split [0,1] (cluster only)
//bt_soft_body->m_cfg.collisions = btSoftBody::fCollision::CL_SS + btSoftBody::fCollision::CL_RS + btSoftBody::fCollision::VF_SS;
//bt_soft_body->generateClusters(64);
bt_soft_body->m_cfg.piterations = simulation_precision;
bt_soft_body->m_cfg.viterations = simulation_precision;
bt_soft_body->m_cfg.diterations = simulation_precision;
bt_soft_body->m_cfg.citerations = 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->m_cfg.kMT = pose_matching_coefficient;
bt_soft_body->setTotalMass(total_mass);
btSoftBodyHelpers::ReoptimizeLinkOrder(bt_soft_body);
bt_soft_body->updateBounds();
// Set pinned nodes
for (int i = pinned_nodes.size() - 1; 0 <= i; --i) {
bt_soft_body->setMass(pinned_nodes[i], 0);
}
}
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);
void SoftBodyBullet::pin_node(int p_node_index) {
if (-1 == search_node_pinned(p_node_index)) {
pinned_nodes.push_back(p_node_index);
}
destroyBulletCollisionObject();
bt_soft_body = NULL;
}
void SoftBodyBullet::unpin_node(int p_node_index) {
const int id = search_node_pinned(p_node_index);
if (-1 != id) {
pinned_nodes.remove(id);
}
}
int SoftBodyBullet::search_node_pinned(int p_node_index) const {
for (int i = pinned_nodes.size() - 1; 0 <= i; --i) {
if (p_node_index == pinned_nodes[i]) {
return i;
}
}
return -1;
}

View file

@ -40,7 +40,10 @@
#define x11_None 0L
#endif
#include <BulletSoftBody/btSoftBodyHelpers.h>
#include "BulletSoftBody/btSoftBodyHelpers.h"
#include "collision_object_bullet.h"
#include "scene/resources/mesh.h"
#include "servers/physics_server.h"
#ifdef x11_None
/// This is required to re add the macro None defined by x11 compiler
@ -52,39 +55,34 @@
@author AndreaCatania
*/
struct SoftShapeData {};
struct TrimeshSoftShapeData : public SoftShapeData {
PoolVector<int> m_triangles_indices;
PoolVector<Vector3> m_vertices;
int m_triangles_num;
};
class SoftBodyBullet : public CollisionObjectBullet {
public:
enum SoftShapeType {
SOFT_SHAPETYPE_NONE = 0,
SOFT_SHAPE_TYPE_TRIMESH
};
private:
btSoftBody *bt_soft_body;
Vector<Vector<int> > indices_table;
btSoftBody::Material *mat0; // This is just a copy of pointer managed by btSoftBody
SoftShapeType soft_shape_type;
bool isScratched;
SoftShapeData *soft_body_shape_data;
Ref<Mesh> soft_mesh;
Transform transform;
int simulation_precision;
real_t mass;
real_t stiffness; // [0,1]
real_t total_mass;
real_t linear_stiffness; // [0,1]
real_t areaAngular_stiffness; // [0,1]
real_t volume_stiffness; // [0,1]
real_t pressure_coefficient; // [-inf,+inf]
real_t pose_matching_coefficient; // [0,1]
real_t damping_coefficient; // [0,1]
real_t drag_coefficient; // [0,1]
Vector<int> pinned_nodes;
class ImmediateGeometry *test_geometry; // TODO remove this please
Ref<SpatialMaterial> red_mat; // TODO remove this please
bool test_is_in_scene; // TODO remove this please
// Other property to add
//btScalar kVC; // Volume conversation coefficient [0,+inf]
//btScalar kDF; // Dynamic friction coefficient [0,1]
//btScalar kMT; // Pose matching coefficient [0,1]
//btScalar kCHR; // Rigid contacts hardness [0,1]
//btScalar kKHR; // Kinetic contacts hardness [0,1]
//btScalar kSHR; // Soft contacts hardness [0,1]
public:
SoftBodyBullet();
@ -101,39 +99,64 @@ public:
_FORCE_INLINE_ btSoftBody *get_bt_soft_body() const { return bt_soft_body; }
void set_trimesh_body_shape(PoolVector<int> p_indices, PoolVector<Vector3> p_vertices, int p_triangles_num);
void set_body_shape_data(SoftShapeData *p_soft_shape_data, SoftShapeType p_type);
void update_visual_server(class SoftBodyVisualServerHandler *p_visual_server_handler);
void set_transform(const Transform &p_transform);
/// This function doesn't return the exact COM transform.
/// It returns the origin only of first node (vertice) of current soft body
/// ---
/// The soft body doesn't have a fixed center of mass, but is a group of nodes (vertices)
/// that each has its own position in the world.
/// For this reason return the correct COM is not so simple and must be calculate
/// Check this to improve this function http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=8803
const Transform &get_transform() const;
void get_first_node_origin(btVector3 &p_out_origin) const;
void set_soft_mesh(const Ref<Mesh> &p_mesh);
void destroy_soft_body();
// Special function. This function has bad performance
void set_soft_transform(const Transform &p_transform);
void move_all_nodes(const Transform &p_transform);
void set_node_position(int node_index, const Vector3 &p_global_position);
void set_node_position(int node_index, const btVector3 &p_global_position);
void get_node_position(int node_index, Vector3 &r_position) const;
// Heavy function, Please cache this info
void get_node_offset(int node_index, Vector3 &r_offset) const;
// Heavy function, Please cache this info
void get_node_offset(int node_index, btVector3 &r_offset) const;
void set_node_mass(int node_index, btScalar p_mass);
btScalar get_node_mass(int node_index) const;
void reset_all_node_mass();
void reset_all_node_positions();
void set_activation_state(bool p_active);
void set_mass(real_t p_val);
_FORCE_INLINE_ real_t get_mass() const { return mass; }
void set_stiffness(real_t p_val);
_FORCE_INLINE_ real_t get_stiffness() const { return stiffness; }
void set_total_mass(real_t p_val);
_FORCE_INLINE_ real_t get_total_mass() const { return total_mass; }
void set_linear_stiffness(real_t p_val);
_FORCE_INLINE_ real_t get_linear_stiffness() const { return linear_stiffness; }
void set_areaAngular_stiffness(real_t p_val);
_FORCE_INLINE_ real_t get_areaAngular_stiffness() const { return areaAngular_stiffness; }
void set_volume_stiffness(real_t p_val);
_FORCE_INLINE_ real_t get_volume_stiffness() const { return volume_stiffness; }
void set_simulation_precision(int p_val);
_FORCE_INLINE_ int get_simulation_precision() const { return simulation_precision; }
void set_pressure_coefficient(real_t p_val);
_FORCE_INLINE_ real_t get_pressure_coefficient() const { return pressure_coefficient; }
void set_pose_matching_coefficient(real_t p_val);
_FORCE_INLINE_ real_t get_pose_matching_coefficient() const { return pose_matching_coefficient; }
void set_damping_coefficient(real_t p_val);
_FORCE_INLINE_ real_t get_damping_coefficient() const { return damping_coefficient; }
void set_drag_coefficient(real_t p_val);
_FORCE_INLINE_ real_t get_drag_coefficient() const { return drag_coefficient; }
private:
void reload_soft_body();
void create_soft_body();
void destroy_soft_body();
void set_trimesh_body_shape(PoolVector<int> p_indices, PoolVector<Vector3> p_vertices);
void setup_soft_body();
void pin_node(int p_node_index);
void unpin_node(int p_node_index);
int search_node_pinned(int p_node_index) const;
};
#endif // SOFT_BODY_BULLET_H

View file

@ -36,6 +36,7 @@
#include "constraint_bullet.h"
#include "godot_collision_configuration.h"
#include "godot_collision_dispatcher.h"
#include "project_settings.h"
#include "rigid_body_bullet.h"
#include "servers/physics_server.h"
#include "soft_body_bullet.h"
@ -325,7 +326,7 @@ Vector3 BulletPhysicsDirectSpaceState::get_closest_point_to_object_volume(RID p_
}
}
SpaceBullet::SpaceBullet(bool p_create_soft_world) :
SpaceBullet::SpaceBullet() :
broadphase(NULL),
dispatcher(NULL),
solver(NULL),
@ -338,7 +339,7 @@ SpaceBullet::SpaceBullet(bool p_create_soft_world) :
gravityMagnitude(10),
contactDebugCount(0) {
create_empty_world(p_create_soft_world);
create_empty_world(GLOBAL_DEF("physics/3d/active_soft_world", true));
direct_access = memnew(BulletPhysicsDirectSpaceState(this));
}
@ -355,6 +356,7 @@ void SpaceBullet::flush_queries() {
}
void SpaceBullet::step(real_t p_delta_time) {
delta_time = p_delta_time;
dynamicsWorld->stepSimulation(p_delta_time, 0, 0);
}
@ -483,6 +485,7 @@ void SpaceBullet::reload_collision_filters(RigidBodyBullet *p_body) {
void SpaceBullet::add_soft_body(SoftBodyBullet *p_body) {
if (is_using_soft_world()) {
if (p_body->get_bt_soft_body()) {
p_body->get_bt_soft_body()->m_worldInfo = get_soft_body_world_info();
static_cast<btSoftRigidDynamicsWorld *>(dynamicsWorld)->addSoftBody(p_body->get_bt_soft_body(), p_body->get_collision_layer(), p_body->get_collision_mask());
}
} else {
@ -494,6 +497,7 @@ void SpaceBullet::remove_soft_body(SoftBodyBullet *p_body) {
if (is_using_soft_world()) {
if (p_body->get_bt_soft_body()) {
static_cast<btSoftRigidDynamicsWorld *>(dynamicsWorld)->removeSoftBody(p_body->get_bt_soft_body());
p_body->get_bt_soft_body()->m_worldInfo = NULL;
}
}
}

View file

@ -84,7 +84,7 @@ public:
};
class SpaceBullet : public RIDBullet {
private:
friend class AreaBullet;
friend void onBulletTickCallback(btDynamicsWorld *world, btScalar timeStep);
friend class BulletPhysicsDirectSpaceState;
@ -109,12 +109,14 @@ private:
Vector<Vector3> contactDebug;
int contactDebugCount;
real_t delta_time;
public:
SpaceBullet(bool p_create_soft_world);
SpaceBullet();
virtual ~SpaceBullet();
void flush_queries();
real_t get_delta_time() { return delta_time; }
void step(real_t p_delta_time);
_FORCE_INLINE_ btBroadphaseInterface *get_broadphase() { return broadphase; }