Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add SoftBody3D::apply_impulse() and SoftBody3D::apply_force() #100463

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions doc/classes/PhysicsServer3D.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1058,6 +1058,42 @@
Adds the given body to the list of bodies exempt from collisions.
</description>
</method>
<method name="soft_body_apply_central_force">
<return type="void" />
<param index="0" name="body" type="RID" />
<param index="1" name="force" type="Vector3" />
<description>
Distributes and applies a force to all vertices. A force is time dependent and meant to be applied every physics update.
</description>
</method>
<method name="soft_body_apply_central_impulse">
<return type="void" />
<param index="0" name="body" type="RID" />
<param index="1" name="impulse" type="Vector3" />
<description>
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).
</description>
</method>
<method name="soft_body_apply_point_force">
<return type="void" />
<param index="0" name="body" type="RID" />
<param index="1" name="force" type="Vector3" />
<param index="2" name="point_index" type="int" />
<description>
Applies a force to a vertex. A force is time dependent and meant to be applied every physics update.
</description>
</method>
<method name="soft_body_apply_point_impulse">
<return type="void" />
<param index="0" name="body" type="RID" />
<param index="1" name="impulse" type="Vector3" />
<param index="2" name="point_index" type="int" />
<description>
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).
</description>
</method>
<method name="soft_body_create">
<return type="RID" />
<description>
Expand Down
30 changes: 30 additions & 0 deletions doc/classes/PhysicsServer3DExtension.xml
Original file line number Diff line number Diff line change
Expand Up @@ -989,6 +989,36 @@
<description>
</description>
</method>
<method name="_soft_body_apply_central_force" qualifiers="virtual">
<return type="void" />
<param index="0" name="body" type="RID" />
<param index="1" name="force" type="Vector3" />
<description>
</description>
</method>
<method name="_soft_body_apply_central_impulse" qualifiers="virtual">
<return type="void" />
<param index="0" name="body" type="RID" />
<param index="1" name="impulse" type="Vector3" />
<description>
</description>
</method>
<method name="_soft_body_apply_point_force" qualifiers="virtual">
<return type="void" />
<param index="0" name="body" type="RID" />
<param index="1" name="force" type="Vector3" />
<param index="2" name="point_index" type="int" />
<description>
</description>
</method>
<method name="_soft_body_apply_point_impulse" qualifiers="virtual">
<return type="void" />
<param index="0" name="body" type="RID" />
<param index="1" name="impulse" type="Vector3" />
<param index="2" name="point_index" type="int" />
<description>
</description>
</method>
<method name="_soft_body_create" qualifiers="virtual">
<return type="RID" />
<description>
Expand Down
32 changes: 32 additions & 0 deletions doc/classes/SoftBody3D.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,38 @@
Adds a body to the list of bodies that this body can't collide with.
</description>
</method>
<method name="apply_central_force">
<return type="void" />
<param index="0" name="force" type="Vector3" />
<description>
Distributes and applies a force to all vertices. A force is time dependent and meant to be applied every physics update.
</description>
</method>
<method name="apply_central_impulse">
<return type="void" />
<param index="0" name="impulse" type="Vector3" />
<description>
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).
</description>
</method>
<method name="apply_force">
<return type="void" />
<param index="0" name="force" type="Vector3" />
<param index="1" name="point_index" type="int" />
<description>
Applies a force to a vertex. A force is time dependent and meant to be applied every physics update.
</description>
</method>
<method name="apply_impulse">
<return type="void" />
<param index="0" name="impulse" type="Vector3" />
<param index="1" name="point_index" type="int" />
<description>
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).
</description>
</method>
<method name="get_collision_exceptions">
<return type="PhysicsBody3D[]" />
<description>
Expand Down
27 changes: 27 additions & 0 deletions modules/godot_physics_3d/godot_physics_server_3d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
5 changes: 5 additions & 0 deletions modules/godot_physics_3d/godot_physics_server_3d.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
24 changes: 24 additions & 0 deletions modules/godot_physics_3d/godot_soft_body_3d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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];
Expand Down
3 changes: 3 additions & 0 deletions modules/godot_physics_3d/godot_soft_body_3d.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
27 changes: 27 additions & 0 deletions modules/jolt_physics/jolt_physics_server_3d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand Down
5 changes: 5 additions & 0 deletions modules/jolt_physics/jolt_physics_server_3d.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
89 changes: 89 additions & 0 deletions modules/jolt_physics/objects/jolt_soft_body_3d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<JPH::SoftBodyMotionProperties &>(*body->GetMotionPropertiesUnchecked());

JPH::Array<JPH::SoftBodyVertex> &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) {
PiCode9560 marked this conversation as resolved.
Show resolved Hide resolved
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<JPH::SoftBodyMotionProperties &>(*body->GetMotionPropertiesUnchecked());

JPH::Array<JPH::SoftBodyVertex> &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;
PiCode9560 marked this conversation as resolved.
Show resolved Hide resolved

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;
Expand Down
5 changes: 5 additions & 0 deletions modules/jolt_physics/objects/jolt_soft_body_3d.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};

Expand Down
21 changes: 21 additions & 0 deletions scene/3d/soft_body_3d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -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)));
}
Expand Down
Loading