diff --git a/scene/3d/soft_body.cpp b/scene/3d/soft_body.cpp index 8498dc34c0f..4ab70137079 100644 --- a/scene/3d/soft_body.cpp +++ b/scene/3d/soft_body.cpp @@ -98,7 +98,7 @@ SoftBody::PinnedPoint::PinnedPoint(const PinnedPoint &obj_tocopy) { point_index = obj_tocopy.point_index; spatial_attachment_path = obj_tocopy.spatial_attachment_path; spatial_attachment = obj_tocopy.spatial_attachment; - vertex_offset_transform = obj_tocopy.vertex_offset_transform; + offset = obj_tocopy.offset; } void SoftBody::_update_pickable() { @@ -164,6 +164,7 @@ void SoftBody::_get_property_list(List *p_list) const { for (int i = 0; i < pinned_points_indices_size; ++i) { p_list->push_back(PropertyInfo(Variant::INT, "attachments/" + itos(i) + "/point_index")); p_list->push_back(PropertyInfo(Variant::NODE_PATH, "attachments/" + itos(i) + "/spatial_attachment_path")); + p_list->push_back(PropertyInfo(Variant::VECTOR3, "attachments/" + itos(i) + "/offset")); } } @@ -204,6 +205,10 @@ bool SoftBody::_set_property_pinned_points_attachment(int p_item, const String & if ("spatial_attachment_path" == p_what) { PoolVector::Write w = pinned_points_indices.write(); pin_point(w[p_item].point_index, true, p_value); + _make_cache_dirty(); + } else if ("offset" == p_what) { + PoolVector::Write w = pinned_points_indices.write(); + w[p_item].offset = p_value; } else { return false; } @@ -221,6 +226,8 @@ bool SoftBody::_get_property_pinned_points(int p_item, const String &p_what, Var r_ret = r[p_item].point_index; } else if ("spatial_attachment_path" == p_what) { r_ret = r[p_item].spatial_attachment_path; + } else if ("offset" == p_what) { + r_ret = r[p_item].offset; } else { return false; } @@ -245,7 +252,6 @@ void SoftBody::_notification(int p_what) { RID space = get_world()->get_space(); PhysicsServer::get_singleton()->soft_body_set_space(physics_rid, space); - PhysicsServer::get_singleton()->soft_body_set_transform(physics_rid, get_global_transform()); update_physics_server(); } break; case NOTIFICATION_READY: { @@ -255,20 +261,30 @@ void SoftBody::_notification(int p_what) { } break; case NOTIFICATION_TRANSFORM_CHANGED: { - if (!simulation_started) { - PhysicsServer::get_singleton()->soft_body_set_transform(physics_rid, get_global_transform()); + if (Engine::get_singleton()->is_editor_hint()) + return; - _update_cache_pin_points_datas(); - // Submit bone attachment - const int pinned_points_indices_size = pinned_points_indices.size(); - PoolVector::Read r = pinned_points_indices.read(); - for (int i = 0; i < pinned_points_indices_size; ++i) { - if (!r[i].spatial_attachment) { - // Use soft body position to update the point position - PhysicsServer::get_singleton()->soft_body_move_point(physics_rid, r[i].point_index, (get_global_transform() * r[i].vertex_offset_transform).origin); - } else { - PhysicsServer::get_singleton()->soft_body_move_point(physics_rid, r[i].point_index, (r[i].spatial_attachment->get_global_transform() * r[i].vertex_offset_transform).origin); - } + PhysicsServer::get_singleton()->soft_body_set_transform(physics_rid, get_global_transform()); + + set_notify_transform(false); + // Required to be top level with Transform at center of world in order to modify VisualServer only to support custom Transform + set_as_toplevel(true); + set_transform(Transform()); + set_notify_transform(true); + + } break; + case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { + + if (!simulation_started) + return; + + _update_cache_pin_points_datas(); + // Submit bone attachment + const int pinned_points_indices_size = pinned_points_indices.size(); + PoolVector::Read r = pinned_points_indices.read(); + for (int i = 0; i < pinned_points_indices_size; ++i) { + if (r[i].spatial_attachment) { + PhysicsServer::get_singleton()->soft_body_move_point(physics_rid, r[i].point_index, r[i].spatial_attachment->get_global_transform().xform(r[i].offset)); } } } break; @@ -408,8 +424,15 @@ void SoftBody::_draw_soft_mesh() { void SoftBody::update_physics_server() { - if (Engine::get_singleton()->is_editor_hint()) + if (Engine::get_singleton()->is_editor_hint()) { + + if (get_mesh().is_valid()) + PhysicsServer::get_singleton()->soft_body_set_mesh(physics_rid, get_mesh()); + else + PhysicsServer::get_singleton()->soft_body_set_mesh(physics_rid, NULL); + return; + } if (get_mesh().is_valid()) { @@ -430,6 +453,9 @@ void SoftBody::become_mesh_owner() { if (!mesh_owner) { mesh_owner = true; + Vector > copy_materials; + copy_materials.append_array(materials); + ERR_FAIL_COND(!mesh->get_surface_count()); // Get current mesh array and create new mesh array with necessary flag for softbody @@ -443,11 +469,10 @@ void SoftBody::become_mesh_owner() { Ref soft_mesh; soft_mesh.instance(); soft_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, surface_arrays, surface_blend_arrays, surface_format); + soft_mesh->surface_set_material(0, mesh->surface_get_material(0)); set_mesh(soft_mesh); - Vector > copy_materials; - copy_materials.append_array(materials); for (int i = copy_materials.size() - 1; 0 <= i; --i) { set_surface_material(i, copy_materials[i]); } @@ -651,6 +676,8 @@ SoftBody::SoftBody() : pinned_points_cache_dirty(true) { PhysicsServer::get_singleton()->body_attach_object_instance_id(physics_rid, get_instance_id()); + //set_notify_transform(true); + set_physics_process_internal(true); } SoftBody::~SoftBody() { @@ -664,30 +691,24 @@ void SoftBody::reset_softbody_pin() { } } +void SoftBody::_make_cache_dirty() { + pinned_points_cache_dirty = true; +} + void SoftBody::_update_cache_pin_points_datas() { - if (pinned_points_cache_dirty) { - pinned_points_cache_dirty = false; + if (!pinned_points_cache_dirty) + return; - PoolVector::Write w = pinned_points_indices.write(); - for (int i = pinned_points_indices.size() - 1; 0 <= i; --i) { + pinned_points_cache_dirty = false; - if (!w[i].spatial_attachment_path.is_empty()) { - w[i].spatial_attachment = Object::cast_to(get_node(w[i].spatial_attachment_path)); - if (w[i].spatial_attachment) { + PoolVector::Write w = pinned_points_indices.write(); + for (int i = pinned_points_indices.size() - 1; 0 <= i; --i) { - Transform point_global_transform(get_global_transform()); - point_global_transform.translate(PhysicsServer::get_singleton()->soft_body_get_point_offset(physics_rid, w[i].point_index)); - - // Local transform relative to spatial attachment node - w[i].vertex_offset_transform = w[i].spatial_attachment->get_global_transform().affine_inverse() * point_global_transform; - continue; - } else { - ERR_PRINTS("The node with path: " + String(w[i].spatial_attachment_path) + " was not found or is not a spatial node."); - } - } - // Local transform relative to Soft body - w[i].vertex_offset_transform.origin = PhysicsServer::get_singleton()->soft_body_get_point_offset(physics_rid, w[i].point_index); - w[i].vertex_offset_transform.basis = Basis(); + if (!w[i].spatial_attachment_path.is_empty()) { + w[i].spatial_attachment = Object::cast_to(get_node(w[i].spatial_attachment_path)); + } + if (!w[i].spatial_attachment) { + ERR_PRINT("Spatial node not defined in the pinned point, Softbody undefined behaviour!"); } } } @@ -699,15 +720,28 @@ void SoftBody::_pin_point_on_physics_server(int p_point_index, bool pin) { void SoftBody::_add_pinned_point(int p_point_index, const NodePath &p_spatial_attachment_path) { SoftBody::PinnedPoint *pinned_point; if (-1 == _get_pinned_point(p_point_index, pinned_point)) { + // Create new PinnedPoint pp; pp.point_index = p_point_index; pp.spatial_attachment_path = p_spatial_attachment_path; + + if (!p_spatial_attachment_path.is_empty() && has_node(p_spatial_attachment_path)) { + pp.spatial_attachment = Object::cast_to(get_node(p_spatial_attachment_path)); + pp.offset = (pp.spatial_attachment->get_global_transform().affine_inverse() * get_global_transform()).xform(PhysicsServer::get_singleton()->soft_body_get_point_global_position(physics_rid, pp.point_index)); + } + pinned_points_indices.push_back(pp); + } else { - // Update + pinned_point->point_index = p_point_index; pinned_point->spatial_attachment_path = p_spatial_attachment_path; + + if (!p_spatial_attachment_path.is_empty() && has_node(p_spatial_attachment_path)) { + pinned_point->spatial_attachment = Object::cast_to(get_node(p_spatial_attachment_path)); + pinned_point->offset = (pinned_point->spatial_attachment->get_global_transform().affine_inverse() * get_global_transform()).xform(PhysicsServer::get_singleton()->soft_body_get_point_global_position(physics_rid, pinned_point->point_index)); + } } } diff --git a/scene/3d/soft_body.h b/scene/3d/soft_body.h index f44f3376988..6cf19ef8c46 100644 --- a/scene/3d/soft_body.h +++ b/scene/3d/soft_body.h @@ -72,9 +72,7 @@ public: int point_index; NodePath spatial_attachment_path; Spatial *spatial_attachment; // Cache - /// This is the offset from the soft body to point or attachment to point - /// Depend if the spatial_attachment_node is NULL or not - Transform vertex_offset_transform; // Cache + Vector3 offset; PinnedPoint(); PinnedPoint(const PinnedPoint &obj_tocopy); @@ -186,6 +184,7 @@ public: private: void reset_softbody_pin(); + void _make_cache_dirty(); void _update_cache_pin_points_datas(); void _pin_point_on_physics_server(int p_point_index, bool pin); void _add_pinned_point(int p_point_index, const NodePath &p_spatial_attachment_path);