From ba422d7fe9a92bab1e31cc2a8c20869961461122 Mon Sep 17 00:00:00 2001
From: PiCode <122909224+PiCode9560@users.noreply.github.com>
Date: Tue, 31 Dec 2024 15:58:15 +0300
Subject: [PATCH] Add functions to apply impulse and force to SoftBody on
GodotPhysics and JoltPhysics
---
doc/classes/PhysicsServer3D.xml | 36 ++++++++
doc/classes/PhysicsServer3DExtension.xml | 30 +++++++
doc/classes/SoftBody3D.xml | 32 +++++++
.../godot_physics_server_3d.cpp | 27 ++++++
.../godot_physics_server_3d.h | 5 ++
.../godot_physics_3d/godot_soft_body_3d.cpp | 24 +++++
modules/godot_physics_3d/godot_soft_body_3d.h | 3 +
.../jolt_physics/jolt_physics_server_3d.cpp | 27 ++++++
modules/jolt_physics/jolt_physics_server_3d.h | 5 ++
.../objects/jolt_soft_body_3d.cpp | 89 +++++++++++++++++++
.../jolt_physics/objects/jolt_soft_body_3d.h | 5 ++
scene/3d/soft_body_3d.cpp | 21 +++++
scene/3d/soft_body_3d.h | 5 ++
.../physics_server_3d_extension.cpp | 5 ++
.../extensions/physics_server_3d_extension.h | 5 ++
servers/physics_server_3d.cpp | 5 ++
servers/physics_server_3d.h | 5 ++
servers/physics_server_3d_dummy.h | 5 ++
servers/physics_server_3d_wrap_mt.h | 5 ++
.../SoftBody/SoftBodyMotionProperties.cpp | 4 +-
20 files changed, 341 insertions(+), 2 deletions(-)
diff --git a/doc/classes/PhysicsServer3D.xml b/doc/classes/PhysicsServer3D.xml
index f87d6342c79d..31f41887c9e1 100644
--- a/doc/classes/PhysicsServer3D.xml
+++ b/doc/classes/PhysicsServer3D.xml
@@ -1058,6 +1058,42 @@
Adds the given body to the list of bodies exempt from collisions.
+
+
+
+
+
+ Distributes and applies a force to all vertices. A force is time dependent and meant to be applied every physics update.
+
+
+
+
+
+
+
+ Distributes and applies an impulse to all vertices.
+ An impulse is time-independent! Applying an impulse every frame would result in a framerate-dependent force. For this reason, it should only be used when simulating one-time impacts (use the "_force" functions otherwise).
+
+
+
+
+
+
+
+
+ Applies a force to a vertex. A force is time dependent and meant to be applied every physics update.
+
+
+
+
+
+
+
+
+ Applies an impulse to a vertex.
+ An impulse is time-independent! Applying an impulse every frame would result in a framerate-dependent force. For this reason, it should only be used when simulating one-time impacts (use the "_force" functions otherwise).
+
+
diff --git a/doc/classes/PhysicsServer3DExtension.xml b/doc/classes/PhysicsServer3DExtension.xml
index e58a7ff9a8aa..2683450947a0 100644
--- a/doc/classes/PhysicsServer3DExtension.xml
+++ b/doc/classes/PhysicsServer3DExtension.xml
@@ -989,6 +989,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/doc/classes/SoftBody3D.xml b/doc/classes/SoftBody3D.xml
index 4d8791d8c1f7..82ab71bbdaf0 100644
--- a/doc/classes/SoftBody3D.xml
+++ b/doc/classes/SoftBody3D.xml
@@ -19,6 +19,38 @@
Adds a body to the list of bodies that this body can't collide with.
+
+
+
+
+ Distributes and applies a force to all vertices. A force is time dependent and meant to be applied every physics update.
+
+
+
+
+
+
+ Distributes and applies an impulse to all vertices.
+ An impulse is time-independent! Applying an impulse every frame would result in a framerate-dependent force. For this reason, it should only be used when simulating one-time impacts (use the "_force" functions otherwise).
+
+
+
+
+
+
+
+ Applies a force to a vertex. A force is time dependent and meant to be applied every physics update.
+
+
+
+
+
+
+
+ Applies an impulse to a vertex.
+ An impulse is time-independent! Applying an impulse every frame would result in a framerate-dependent force. For this reason, it should only be used when simulating one-time impacts (use the "_force" functions otherwise).
+
+
diff --git a/modules/godot_physics_3d/godot_physics_server_3d.cpp b/modules/godot_physics_3d/godot_physics_server_3d.cpp
index 35aa538ef51d..2598474f11e5 100644
--- a/modules/godot_physics_3d/godot_physics_server_3d.cpp
+++ b/modules/godot_physics_3d/godot_physics_server_3d.cpp
@@ -736,6 +736,33 @@ void GodotPhysicsServer3D::body_apply_force(RID p_body, const Vector3 &p_force,
body->apply_force(p_force, p_position);
body->wakeup();
}
+void GodotPhysicsServer3D::soft_body_apply_point_impulse(RID p_body, const Vector3 p_impulse, int point_index) {
+ GodotSoftBody3D *soft_body = soft_body_owner.get_or_null(p_body);
+ ERR_FAIL_NULL(soft_body);
+
+ soft_body->apply_node_impulse(point_index, p_impulse);
+}
+
+void GodotPhysicsServer3D::soft_body_apply_point_force(RID p_body, const Vector3 p_force, int point_index) {
+ GodotSoftBody3D *soft_body = soft_body_owner.get_or_null(p_body);
+ ERR_FAIL_NULL(soft_body);
+
+ soft_body->apply_node_force(point_index, p_force);
+}
+
+void GodotPhysicsServer3D::soft_body_apply_central_impulse(RID p_body, const Vector3 p_impulse) {
+ GodotSoftBody3D *soft_body = soft_body_owner.get_or_null(p_body);
+ ERR_FAIL_NULL(soft_body);
+
+ soft_body->apply_central_impulse(p_impulse);
+}
+
+void GodotPhysicsServer3D::soft_body_apply_central_force(RID p_body, const Vector3 p_force) {
+ GodotSoftBody3D *soft_body = soft_body_owner.get_or_null(p_body);
+ ERR_FAIL_NULL(soft_body);
+
+ soft_body->apply_central_force(p_force);
+}
void GodotPhysicsServer3D::body_apply_torque(RID p_body, const Vector3 &p_torque) {
GodotBody3D *body = body_owner.get_or_null(p_body);
diff --git a/modules/godot_physics_3d/godot_physics_server_3d.h b/modules/godot_physics_3d/godot_physics_server_3d.h
index 94003a7087fb..757d733e602f 100644
--- a/modules/godot_physics_3d/godot_physics_server_3d.h
+++ b/modules/godot_physics_3d/godot_physics_server_3d.h
@@ -213,6 +213,11 @@ class GodotPhysicsServer3D : public PhysicsServer3D {
virtual void body_apply_impulse(RID p_body, const Vector3 &p_impulse, const Vector3 &p_position = Vector3()) override;
virtual void body_apply_torque_impulse(RID p_body, const Vector3 &p_impulse) override;
+ virtual void soft_body_apply_point_impulse(RID p_body, const Vector3 p_impulse, int p_point_index) override;
+ virtual void soft_body_apply_point_force(RID p_body, const Vector3 p_force, int p_point_index) override;
+ virtual void soft_body_apply_central_impulse(RID p_body, const Vector3 p_impulse) override;
+ virtual void soft_body_apply_central_force(RID p_body, const Vector3 p_force) override;
+
virtual void body_apply_central_force(RID p_body, const Vector3 &p_force) override;
virtual void body_apply_force(RID p_body, const Vector3 &p_force, const Vector3 &p_position = Vector3()) override;
virtual void body_apply_torque(RID p_body, const Vector3 &p_torque) override;
diff --git a/modules/godot_physics_3d/godot_soft_body_3d.cpp b/modules/godot_physics_3d/godot_soft_body_3d.cpp
index bbee0ecf71f7..d765a1ec594b 100644
--- a/modules/godot_physics_3d/godot_soft_body_3d.cpp
+++ b/modules/godot_physics_3d/godot_soft_body_3d.cpp
@@ -446,6 +446,30 @@ void GodotSoftBody3D::apply_node_impulse(uint32_t p_node_index, const Vector3 &p
node.v += p_impulse * node.im;
}
+void GodotSoftBody3D::apply_node_force(uint32_t p_node_index, const Vector3 &p_force) {
+ ERR_FAIL_UNSIGNED_INDEX(p_node_index, nodes.size());
+ Node &node = nodes[p_node_index];
+ node.f += p_force;
+}
+
+void GodotSoftBody3D::apply_central_impulse(const Vector3 &p_impulse) {
+ const Vector3 impulse = p_impulse / nodes.size();
+ for (Node &node : nodes) {
+ if (node.im > 0) {
+ node.v += impulse * node.im;
+ }
+ }
+}
+
+void GodotSoftBody3D::apply_central_force(const Vector3 &p_force) {
+ const Vector3 force = p_force / nodes.size();
+ for (Node &node : nodes) {
+ if (node.im > 0) {
+ node.f += force;
+ }
+ }
+}
+
void GodotSoftBody3D::apply_node_bias_impulse(uint32_t p_node_index, const Vector3 &p_impulse) {
ERR_FAIL_UNSIGNED_INDEX(p_node_index, nodes.size());
Node &node = nodes[p_node_index];
diff --git a/modules/godot_physics_3d/godot_soft_body_3d.h b/modules/godot_physics_3d/godot_soft_body_3d.h
index e23f4bb9f555..9e8a2bdd7f6d 100644
--- a/modules/godot_physics_3d/godot_soft_body_3d.h
+++ b/modules/godot_physics_3d/godot_soft_body_3d.h
@@ -173,6 +173,9 @@ class GodotSoftBody3D : public GodotCollisionObject3D {
Vector3 get_node_velocity(uint32_t p_node_index) const;
Vector3 get_node_biased_velocity(uint32_t p_node_index) const;
void apply_node_impulse(uint32_t p_node_index, const Vector3 &p_impulse);
+ void apply_node_force(uint32_t p_node_index, const Vector3 &p_force);
+ void apply_central_impulse(const Vector3 &p_impulse);
+ void apply_central_force(const Vector3 &p_force);
void apply_node_bias_impulse(uint32_t p_node_index, const Vector3 &p_impulse);
uint32_t get_face_count() const;
diff --git a/modules/jolt_physics/jolt_physics_server_3d.cpp b/modules/jolt_physics/jolt_physics_server_3d.cpp
index d126f8bde7b1..7fa6ee1bcf9e 100644
--- a/modules/jolt_physics/jolt_physics_server_3d.cpp
+++ b/modules/jolt_physics/jolt_physics_server_3d.cpp
@@ -288,6 +288,33 @@ void JoltPhysicsServer3D::area_set_space(RID p_area, RID p_space) {
area->set_space(space);
}
+void JoltPhysicsServer3D::soft_body_apply_point_impulse(RID p_body, const Vector3 p_impulse, int p_node_index) {
+ JoltSoftBody3D *body = soft_body_owner.get_or_null(p_body);
+ ERR_FAIL_NULL(body);
+
+ body->apply_node_impulse(p_node_index, p_impulse);
+}
+
+void JoltPhysicsServer3D::soft_body_apply_point_force(RID p_body, const Vector3 p_force, int p_node_index) {
+ JoltSoftBody3D *body = soft_body_owner.get_or_null(p_body);
+ ERR_FAIL_NULL(body);
+
+ body->apply_node_force(p_node_index, p_force);
+}
+
+void JoltPhysicsServer3D::soft_body_apply_central_impulse(RID p_body, const Vector3 p_impulse) {
+ JoltSoftBody3D *body = soft_body_owner.get_or_null(p_body);
+ ERR_FAIL_NULL(body);
+
+ body->apply_central_impulse(p_impulse);
+}
+void JoltPhysicsServer3D::soft_body_apply_central_force(RID p_body, const Vector3 p_force) {
+ JoltSoftBody3D *body = soft_body_owner.get_or_null(p_body);
+ ERR_FAIL_NULL(body);
+
+ body->apply_central_force(p_force);
+}
+
RID JoltPhysicsServer3D::area_get_space(RID p_area) const {
const JoltArea3D *area = area_owner.get_or_null(p_area);
ERR_FAIL_NULL_V(area, RID());
diff --git a/modules/jolt_physics/jolt_physics_server_3d.h b/modules/jolt_physics/jolt_physics_server_3d.h
index 7dac7610f71a..980386f5e803 100644
--- a/modules/jolt_physics/jolt_physics_server_3d.h
+++ b/modules/jolt_physics/jolt_physics_server_3d.h
@@ -323,6 +323,11 @@ class JoltPhysicsServer3D final : public PhysicsServer3D {
virtual void soft_body_set_transform(RID p_body, const Transform3D &p_transform) override;
+ virtual void soft_body_apply_point_impulse(RID p_body, const Vector3 p_impulse, int p_point_index) override;
+ virtual void soft_body_apply_point_force(RID p_body, const Vector3 p_force, int p_point_index) override;
+ virtual void soft_body_apply_central_impulse(RID p_body, const Vector3 p_impulse) override;
+ virtual void soft_body_apply_central_force(RID p_body, const Vector3 p_force) override;
+
virtual void soft_body_set_simulation_precision(RID p_body, int p_precision) override;
virtual int soft_body_get_simulation_precision(RID p_body) const override;
diff --git a/modules/jolt_physics/objects/jolt_soft_body_3d.cpp b/modules/jolt_physics/objects/jolt_soft_body_3d.cpp
index c9e834fd42e2..5ac7a09a19b0 100644
--- a/modules/jolt_physics/objects/jolt_soft_body_3d.cpp
+++ b/modules/jolt_physics/objects/jolt_soft_body_3d.cpp
@@ -424,6 +424,95 @@ bool JoltSoftBody3D::is_sleeping() const {
return !body->IsActive();
}
+void JoltSoftBody3D::apply_node_impulse(int p_index, const Vector3 &p_impulse) {
+ ERR_FAIL_COND_MSG(!in_space(), vformat("Failed to apply impulse for '%s'. Doing so without a physics space is not supported when using Jolt Physics. If this relates to a node, try adding the node to a scene tree first.", to_string()));
+
+ ERR_FAIL_NULL(shared);
+ ERR_FAIL_INDEX(p_index, (int)shared->mesh_to_physics.size());
+ const size_t physics_index = (size_t)shared->mesh_to_physics[p_index];
+
+ if (pinned_vertices.has(physics_index)) {
+ return;
+ }
+
+ const float last_step = space->get_last_step();
+ if (unlikely(last_step == 0.0f)) {
+ return;
+ }
+ wake_up();
+
+ JoltWritableBody3D body = space->write_body(jolt_id);
+ ERR_FAIL_COND(body.is_invalid());
+
+ JPH::SoftBodyMotionProperties &motion_properties = static_cast(*body->GetMotionPropertiesUnchecked());
+
+ JPH::Array &physics_vertices = motion_properties.GetVertices();
+ JPH::SoftBodyVertex &physics_vertex = physics_vertices[physics_index];
+
+ const JPH::Vec3 impulse = to_jolt(p_impulse);
+ physics_vertex.mVelocity += impulse * physics_vertex.mInvMass;
+}
+
+void JoltSoftBody3D::apply_node_force(int p_index, const Vector3 &p_force) {
+ ERR_FAIL_COND_MSG(!in_space(), vformat("Failed to apply force for '%s'. Doing so without a physics space is not supported when using Jolt Physics. If this relates to a node, try adding the node to a scene tree first.", to_string()));
+
+ const float last_step = space->get_last_step();
+ const Vector3 impulse = p_force * last_step;
+ apply_node_impulse(p_index, impulse);
+}
+
+void JoltSoftBody3D::apply_central_impulse(const Vector3 &p_impulse) {
+ ERR_FAIL_COND_MSG(!in_space(), vformat("Failed to apply central impulse for '%s'. Doing so without a physics space is not supported when using Jolt Physics. If this relates to a node, try adding the node to a scene tree first.", to_string()));
+
+ ERR_FAIL_NULL(shared);
+
+ const float last_step = space->get_last_step();
+ if (unlikely(last_step == 0.0f)) {
+ return;
+ }
+ wake_up();
+
+ JoltWritableBody3D body = space->write_body(jolt_id);
+ ERR_FAIL_COND(body.is_invalid());
+
+ JPH::SoftBodyMotionProperties &motion_properties = static_cast(*body->GetMotionPropertiesUnchecked());
+
+ JPH::Array &physics_vertices = motion_properties.GetVertices();
+
+ const int mesh_vertex_count = shared->mesh_to_physics.size();
+
+ const JPH::Vec3 impulse = to_jolt(p_impulse) / mesh_vertex_count;
+
+ for (int i = 0; i < mesh_vertex_count; ++i) {
+ const size_t physics_index = (size_t)shared->mesh_to_physics[i];
+
+ if (pinned_vertices.has(physics_index)) {
+ continue;
+ }
+
+ JPH::SoftBodyVertex &physics_vertex = physics_vertices[physics_index];
+
+ physics_vertex.mVelocity += impulse * physics_vertex.mInvMass;
+ }
+}
+
+void JoltSoftBody3D::apply_central_force(const Vector3 &p_force) {
+ ERR_FAIL_COND_MSG(!in_space(), vformat("Failed to apply central force for '%s'. Doing so without a physics space is not supported when using Jolt Physics. If this relates to a node, try adding the node to a scene tree first.", to_string()));
+
+ ERR_FAIL_NULL(shared);
+
+ const float last_step = space->get_last_step();
+ if (unlikely(last_step == 0.0f)) {
+ return;
+ }
+
+ JPH::BodyInterface &body_iface = space->get_body_iface();
+
+ const JPH::Vec3 force = to_jolt(p_force);
+
+ body_iface.AddForce(jolt_id, force, JPH::EActivation::Activate);
+}
+
void JoltSoftBody3D::set_is_sleeping(bool p_enabled) {
if (!in_space()) {
return;
diff --git a/modules/jolt_physics/objects/jolt_soft_body_3d.h b/modules/jolt_physics/objects/jolt_soft_body_3d.h
index 45e8be2e7bf4..a55b9092fd97 100644
--- a/modules/jolt_physics/objects/jolt_soft_body_3d.h
+++ b/modules/jolt_physics/objects/jolt_soft_body_3d.h
@@ -168,6 +168,11 @@ class JoltSoftBody3D final : public JoltObject3D {
bool is_vertex_pinned(int p_index) const;
+ void apply_node_impulse(int p_index, const Vector3 &p_impulse);
+ void apply_node_force(int p_index, const Vector3 &p_force);
+ void apply_central_impulse(const Vector3 &p_impulse);
+ void apply_central_force(const Vector3 &p_force);
+
String to_string() const;
};
diff --git a/scene/3d/soft_body_3d.cpp b/scene/3d/soft_body_3d.cpp
index b0fc94d75f8a..c6418a2d1bc8 100644
--- a/scene/3d/soft_body_3d.cpp
+++ b/scene/3d/soft_body_3d.cpp
@@ -363,6 +363,11 @@ void SoftBody3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_point_transform", "point_index"), &SoftBody3D::get_point_transform);
+ ClassDB::bind_method(D_METHOD("apply_impulse", "impulse", "point_index"), &SoftBody3D::apply_impulse);
+ ClassDB::bind_method(D_METHOD("apply_force", "force", "point_index"), &SoftBody3D::apply_force);
+ ClassDB::bind_method(D_METHOD("apply_central_impulse", "impulse"), &SoftBody3D::apply_central_impulse);
+ ClassDB::bind_method(D_METHOD("apply_central_force", "force"), &SoftBody3D::apply_central_force);
+
ClassDB::bind_method(D_METHOD("set_point_pinned", "point_index", "pinned", "attachment_path", "insert_at"), &SoftBody3D::pin_point, DEFVAL(NodePath()), DEFVAL(-1));
ClassDB::bind_method(D_METHOD("is_point_pinned", "point_index"), &SoftBody3D::is_point_pinned);
@@ -671,6 +676,22 @@ Vector3 SoftBody3D::get_point_transform(int p_point_index) {
return PhysicsServer3D::get_singleton()->soft_body_get_point_global_position(physics_rid, p_point_index);
}
+void SoftBody3D::apply_impulse(Vector3 p_impulse, int p_point_index) {
+ PhysicsServer3D::get_singleton()->soft_body_apply_point_impulse(physics_rid, p_impulse, p_point_index);
+}
+
+void SoftBody3D::apply_force(Vector3 p_force, int p_point_index) {
+ PhysicsServer3D::get_singleton()->soft_body_apply_point_force(physics_rid, p_force, p_point_index);
+}
+
+void SoftBody3D::apply_central_impulse(Vector3 p_impulse) {
+ PhysicsServer3D::get_singleton()->soft_body_apply_central_impulse(physics_rid, p_impulse);
+}
+
+void SoftBody3D::apply_central_force(Vector3 p_force) {
+ PhysicsServer3D::get_singleton()->soft_body_apply_central_force(physics_rid, p_force);
+}
+
void SoftBody3D::pin_point_toggle(int p_point_index) {
pin_point(p_point_index, !(-1 != _has_pinned_point(p_point_index)));
}
diff --git a/scene/3d/soft_body_3d.h b/scene/3d/soft_body_3d.h
index 72544b233cb3..0029e76e0831 100644
--- a/scene/3d/soft_body_3d.h
+++ b/scene/3d/soft_body_3d.h
@@ -189,6 +189,11 @@ class SoftBody3D : public MeshInstance3D {
void set_ray_pickable(bool p_ray_pickable);
bool is_ray_pickable() const;
+ void apply_impulse(Vector3 p_impulse, int p_point_index);
+ void apply_force(Vector3 p_force, int p_point_index);
+ void apply_central_impulse(Vector3 p_impulse);
+ void apply_central_force(Vector3 p_force);
+
SoftBody3D();
~SoftBody3D();
diff --git a/servers/extensions/physics_server_3d_extension.cpp b/servers/extensions/physics_server_3d_extension.cpp
index 0937021c641f..f03cd70e617b 100644
--- a/servers/extensions/physics_server_3d_extension.cpp
+++ b/servers/extensions/physics_server_3d_extension.cpp
@@ -358,6 +358,11 @@ void PhysicsServer3DExtension::_bind_methods() {
GDVIRTUAL_BIND(_soft_body_pin_point, "body", "point_index", "pin");
GDVIRTUAL_BIND(_soft_body_is_point_pinned, "body", "point_index");
+ GDVIRTUAL_BIND(_soft_body_apply_point_impulse, "body", "impulse", "point_index");
+ GDVIRTUAL_BIND(_soft_body_apply_point_force, "body", "force", "point_index");
+ GDVIRTUAL_BIND(_soft_body_apply_central_impulse, "body", "impulse");
+ GDVIRTUAL_BIND(_soft_body_apply_central_force, "body", "force");
+
/* JOINT API */
GDVIRTUAL_BIND(_joint_create);
diff --git a/servers/extensions/physics_server_3d_extension.h b/servers/extensions/physics_server_3d_extension.h
index aba124ab9cd4..4f4f5bd95d8c 100644
--- a/servers/extensions/physics_server_3d_extension.h
+++ b/servers/extensions/physics_server_3d_extension.h
@@ -466,6 +466,11 @@ class PhysicsServer3DExtension : public PhysicsServer3D {
EXBIND3(soft_body_pin_point, RID, int, bool)
EXBIND2RC(bool, soft_body_is_point_pinned, RID, int)
+ EXBIND3(soft_body_apply_point_impulse, RID, Vector3, int)
+ EXBIND3(soft_body_apply_point_force, RID, Vector3, int)
+ EXBIND2(soft_body_apply_central_impulse, RID, Vector3)
+ EXBIND2(soft_body_apply_central_force, RID, Vector3)
+
/* JOINT API */
EXBIND0R(RID, joint_create)
diff --git a/servers/physics_server_3d.cpp b/servers/physics_server_3d.cpp
index 6e1665f1a3a0..d53a30defb64 100644
--- a/servers/physics_server_3d.cpp
+++ b/servers/physics_server_3d.cpp
@@ -894,6 +894,11 @@ void PhysicsServer3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("soft_body_is_point_pinned", "body", "point_index"), &PhysicsServer3D::soft_body_is_point_pinned);
+ ClassDB::bind_method(D_METHOD("soft_body_apply_point_impulse", "body", "impulse", "point_index"), &PhysicsServer3D::soft_body_apply_point_impulse);
+ ClassDB::bind_method(D_METHOD("soft_body_apply_point_force", "body", "force", "point_index"), &PhysicsServer3D::soft_body_apply_point_force);
+ ClassDB::bind_method(D_METHOD("soft_body_apply_central_impulse", "body", "impulse"), &PhysicsServer3D::soft_body_apply_central_impulse);
+ ClassDB::bind_method(D_METHOD("soft_body_apply_central_force", "body", "force"), &PhysicsServer3D::soft_body_apply_central_force);
+
/* JOINT API */
ClassDB::bind_method(D_METHOD("joint_create"), &PhysicsServer3D::joint_create);
diff --git a/servers/physics_server_3d.h b/servers/physics_server_3d.h
index 61e62aed1480..2268d57e9948 100644
--- a/servers/physics_server_3d.h
+++ b/servers/physics_server_3d.h
@@ -618,6 +618,11 @@ class PhysicsServer3D : public Object {
virtual void soft_body_move_point(RID p_body, int p_point_index, const Vector3 &p_global_position) = 0;
virtual Vector3 soft_body_get_point_global_position(RID p_body, int p_point_index) const = 0;
+ virtual void soft_body_apply_point_impulse(RID p_body, Vector3 p_impulse, int p_point_index) = 0;
+ virtual void soft_body_apply_point_force(RID p_body, Vector3 p_force, int p_point_index) = 0;
+ virtual void soft_body_apply_central_impulse(RID p_body, Vector3 p_impulse) = 0;
+ virtual void soft_body_apply_central_force(RID p_body, Vector3 p_force) = 0;
+
virtual void soft_body_remove_all_pinned_points(RID p_body) = 0;
virtual void soft_body_pin_point(RID p_body, int p_point_index, bool p_pin) = 0;
virtual bool soft_body_is_point_pinned(RID p_body, int p_point_index) const = 0;
diff --git a/servers/physics_server_3d_dummy.h b/servers/physics_server_3d_dummy.h
index 209a541fea01..c00b8e413709 100644
--- a/servers/physics_server_3d_dummy.h
+++ b/servers/physics_server_3d_dummy.h
@@ -358,6 +358,11 @@ class PhysicsServer3DDummy : public PhysicsServer3D {
virtual void soft_body_pin_point(RID p_body, int p_point_index, bool p_pin) override {}
virtual bool soft_body_is_point_pinned(RID p_body, int p_point_index) const override { return false; }
+ virtual void soft_body_apply_point_impulse(RID p_body, const Vector3 p_impulse, int p_point_index) override {}
+ virtual void soft_body_apply_point_force(RID p_body, const Vector3 p_force, int p_point_index) override {}
+ virtual void soft_body_apply_central_impulse(RID p_body, const Vector3 p_impulse) override {}
+ virtual void soft_body_apply_central_force(RID p_body, const Vector3 p_force) override {}
+
/* JOINT API */
virtual RID joint_create() override { return RID(); }
diff --git a/servers/physics_server_3d_wrap_mt.h b/servers/physics_server_3d_wrap_mt.h
index 2fd39546a59e..5a190bfde2c7 100644
--- a/servers/physics_server_3d_wrap_mt.h
+++ b/servers/physics_server_3d_wrap_mt.h
@@ -226,6 +226,11 @@ class PhysicsServer3DWrapMT : public PhysicsServer3D {
FUNC3(body_apply_force, RID, const Vector3 &, const Vector3 &);
FUNC2(body_apply_torque, RID, const Vector3 &);
+ FUNC3(soft_body_apply_point_impulse, RID, const Vector3, int);
+ FUNC3(soft_body_apply_point_force, RID, const Vector3, int);
+ FUNC2(soft_body_apply_central_impulse, RID, const Vector3);
+ FUNC2(soft_body_apply_central_force, RID, const Vector3);
+
FUNC2(body_add_constant_central_force, RID, const Vector3 &);
FUNC3(body_add_constant_force, RID, const Vector3 &, const Vector3 &);
FUNC2(body_add_constant_torque, RID, const Vector3 &);
diff --git a/thirdparty/jolt_physics/Jolt/Physics/SoftBody/SoftBodyMotionProperties.cpp b/thirdparty/jolt_physics/Jolt/Physics/SoftBody/SoftBodyMotionProperties.cpp
index 78eacd485a96..80871375e1c6 100644
--- a/thirdparty/jolt_physics/Jolt/Physics/SoftBody/SoftBodyMotionProperties.cpp
+++ b/thirdparty/jolt_physics/Jolt/Physics/SoftBody/SoftBodyMotionProperties.cpp
@@ -315,7 +315,7 @@ void SoftBodyMotionProperties::IntegratePositions(const SoftBodyUpdateContext &i
// Integrate
Vec3 sub_step_gravity = inContext.mGravity * dt;
- Vec3 sub_step_impulse = GetAccumulatedForce() * dt;
+ Vec3 sub_step_impulse = GetAccumulatedForce() * dt / max(float(mVertices.size()), 1.0f);
for (Vertex &v : mVertices)
if (v.mInvMass > 0.0f)
{
@@ -765,7 +765,7 @@ void SoftBodyMotionProperties::UpdateSoftBodyState(SoftBodyUpdateContext &ioCont
// Calculate linear/angular velocity of the body by averaging all vertices and bringing the value to world space
float num_vertices_divider = float(max(int(mVertices.size()), 1));
- SetLinearVelocity(ioContext.mCenterOfMassTransform.Multiply3x3(linear_velocity / num_vertices_divider));
+ SetLinearVelocityClamped(ioContext.mCenterOfMassTransform.Multiply3x3(linear_velocity / num_vertices_divider));
SetAngularVelocity(ioContext.mCenterOfMassTransform.Multiply3x3(angular_velocity / num_vertices_divider));
if (mUpdatePosition)