Browse Source

Added support for applying a global force to a soft body (#1063)

Jorrit Rouwe 1 year ago
parent
commit
ca1ebf722f

+ 1 - 1
Docs/Architecture.md

@@ -286,7 +286,7 @@ The adjacent faces of the soft body will be used to calculate the normal of each
 Soft bodies are currently in development, please note the following:
 
 * Soft bodies can only collide with rigid bodies, collisions between soft bodies are not implemented yet.
-* AddForce/AddTorque/SetLinearVelocity/SetLinearVelocityClamped/SetAngularVelocity/SetAngularVelocityClamped/AddImpulse/AddAngularImpulse have no effect on soft bodies as the velocity is stored per particle rather than per body.
+* AddTorque/SetLinearVelocity/SetLinearVelocityClamped/SetAngularVelocity/SetAngularVelocityClamped/AddImpulse/AddAngularImpulse have no effect on soft bodies as the velocity is stored per particle rather than per body.
 * Buoyancy calculations have not been implemented yet.
 * Constraints cannot operate on soft bodies, set the inverse mass of a particle to zero and move it by setting a velocity to constrain a soft body to something else.
 * When calculating friction / restitution an empty SubShapeID will be passed to the ContactConstraintManager::CombineFunction because this is called once per body pair rather than once per sub shape as is common for rigid bodies.

+ 5 - 1
Jolt/Physics/SoftBody/SoftBodyMotionProperties.cpp

@@ -228,11 +228,12 @@ void SoftBodyMotionProperties::IntegratePositions(const SoftBodyUpdateContext &i
 
 	// Integrate
 	Vec3 sub_step_gravity = inContext.mGravity * dt;
+	Vec3 sub_step_impulse = GetAccumulatedForce() * dt;
 	for (Vertex &v : mVertices)
 		if (v.mInvMass > 0.0f)
 		{
 			// Gravity
-			v.mVelocity += sub_step_gravity;
+			v.mVelocity += sub_step_gravity + sub_step_impulse * v.mInvMass;
 
 			// Damping
 			v.mVelocity *= linear_damping;
@@ -709,6 +710,9 @@ void SoftBodyMotionProperties::UpdateSoftBodyState(SoftBodyUpdateContext &ioCont
 
 	// If SkinVertices is not called after this then don't use the previous position as the skin is static
 	mSkinStatePreviousPositionValid = false;
+
+	// Reset force accumulator
+	ResetForce();
 }
 
 void SoftBodyMotionProperties::UpdateRigidBodyVelocities(const SoftBodyUpdateContext &inContext, BodyInterface &inBodyInterface)

+ 2 - 0
Samples/Samples.cmake

@@ -173,6 +173,8 @@ set(SAMPLES_SRC_FILES
 	${SAMPLES_ROOT}/Tests/SoftBody/SoftBodyContactListenerTest.h
 	${SAMPLES_ROOT}/Tests/SoftBody/SoftBodyCustomUpdateTest.cpp
 	${SAMPLES_ROOT}/Tests/SoftBody/SoftBodyCustomUpdateTest.h
+	${SAMPLES_ROOT}/Tests/SoftBody/SoftBodyForceTest.cpp
+	${SAMPLES_ROOT}/Tests/SoftBody/SoftBodyForceTest.h
 	${SAMPLES_ROOT}/Tests/SoftBody/SoftBodyFrictionTest.cpp
 	${SAMPLES_ROOT}/Tests/SoftBody/SoftBodyFrictionTest.h
 	${SAMPLES_ROOT}/Tests/SoftBody/SoftBodyGravityFactorTest.cpp

+ 2 - 0
Samples/SamplesApp.cpp

@@ -317,6 +317,7 @@ JPH_DECLARE_RTTI_FOR_FACTORY(JPH_NO_EXPORT, SoftBodyFrictionTest)
 JPH_DECLARE_RTTI_FOR_FACTORY(JPH_NO_EXPORT, SoftBodyRestitutionTest)
 JPH_DECLARE_RTTI_FOR_FACTORY(JPH_NO_EXPORT, SoftBodyPressureTest)
 JPH_DECLARE_RTTI_FOR_FACTORY(JPH_NO_EXPORT, SoftBodyGravityFactorTest)
+JPH_DECLARE_RTTI_FOR_FACTORY(JPH_NO_EXPORT, SoftBodyForceTest)
 JPH_DECLARE_RTTI_FOR_FACTORY(JPH_NO_EXPORT, SoftBodyKinematicTest)
 JPH_DECLARE_RTTI_FOR_FACTORY(JPH_NO_EXPORT, SoftBodyUpdatePositionTest)
 JPH_DECLARE_RTTI_FOR_FACTORY(JPH_NO_EXPORT, SoftBodyStressTest)
@@ -336,6 +337,7 @@ static TestNameAndRTTI sSoftBodyTests[] =
 	{ "Soft Body Restitution",			JPH_RTTI(SoftBodyRestitutionTest) },
 	{ "Soft Body Pressure",				JPH_RTTI(SoftBodyPressureTest) },
 	{ "Soft Body Gravity Factor",		JPH_RTTI(SoftBodyGravityFactorTest) },
+	{ "Soft Body Force",				JPH_RTTI(SoftBodyForceTest) },
 	{ "Soft Body Kinematic",			JPH_RTTI(SoftBodyKinematicTest) },
 	{ "Soft Body Update Position",		JPH_RTTI(SoftBodyUpdatePositionTest) },
 	{ "Soft Body Stress Test",			JPH_RTTI(SoftBodyStressTest) },

+ 59 - 0
Samples/Tests/SoftBody/SoftBodyForceTest.cpp

@@ -0,0 +1,59 @@
+// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
+// SPDX-FileCopyrightText: 2024 Jorrit Rouwe
+// SPDX-License-Identifier: MIT
+
+#include <TestFramework.h>
+
+#include <Tests/SoftBody/SoftBodyForceTest.h>
+#include <Jolt/Physics/Body/BodyCreationSettings.h>
+#include <Jolt/Physics/SoftBody/SoftBodyCreationSettings.h>
+#include <Utils/SoftBodyCreator.h>
+#include <Renderer/DebugRendererImp.h>
+#include <Math/Perlin.h>
+#include <Layers.h>
+
+JPH_IMPLEMENT_RTTI_VIRTUAL(SoftBodyForceTest)
+{
+	JPH_ADD_BASE_CLASS(SoftBodyForceTest, Test)
+}
+
+void SoftBodyForceTest::Initialize()
+{
+	CreateFloor();
+
+	static constexpr uint cGridSize = 30;
+
+	// Create hanging cloth
+	auto inv_mass = [](uint inX, uint inZ) {
+		return (inX == 0 && inZ == 0)
+			|| (inX == cGridSize - 1 && inZ == 0)? 0.0f : 1.0f;
+	};
+	SoftBodyCreationSettings cloth(SoftBodyCreator::CreateCloth(cGridSize, cGridSize, 0.75f, inv_mass), RVec3(0, 15.0f, 0), Quat::sRotation(Vec3::sAxisX(), 0.5f * JPH_PI), Layers::MOVING);
+	mBodyID = mBodyInterface->CreateAndAddSoftBody(cloth, EActivation::Activate);
+}
+
+void SoftBodyForceTest::PrePhysicsUpdate(const PreUpdateParams &inParams)
+{
+	mTime += inParams.mDeltaTime;
+
+	// Apply a fluctuating force
+	constexpr float cMaxForce = 15.0f;
+	constexpr float cMaxAngle = DegreesToRadians(90.0f);
+	Vec3 force(0, 0, 0.5f * cMaxForce * (1.0f + PerlinNoise3(0, 0, mTime / 2.0f, 256, 256, 256)));
+	force = Mat44::sRotationY(cMaxAngle * PerlinNoise3(mTime / 10.0f, 0, 0, 256, 256, 256)) * force;
+	mBodyInterface->AddForce(mBodyID, force);
+
+	// Draw the force
+	RVec3 offset(0, 10, 0);
+	DebugRenderer::sInstance->DrawArrow(offset, offset + force, Color::sGreen, 0.1f);
+}
+
+void SoftBodyForceTest::SaveState(StateRecorder &inStream) const
+{
+	inStream.Write(mTime);
+}
+
+void SoftBodyForceTest::RestoreState(StateRecorder &inStream)
+{
+	inStream.Read(mTime);
+}

+ 24 - 0
Samples/Tests/SoftBody/SoftBodyForceTest.h

@@ -0,0 +1,24 @@
+// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
+// SPDX-FileCopyrightText: 2024 Jorrit Rouwe
+// SPDX-License-Identifier: MIT
+
+#pragma once
+
+#include <Tests/Test.h>
+
+// This test shows how to apply a global force to a soft body
+class SoftBodyForceTest : public Test
+{
+public:
+	JPH_DECLARE_RTTI_VIRTUAL(JPH_NO_EXPORT, SoftBodyForceTest)
+
+	// See: Test
+	virtual void		Initialize() override;
+	virtual void		PrePhysicsUpdate(const PreUpdateParams &inParams) override;
+	virtual void		SaveState(StateRecorder &inStream) const override;
+	virtual void		RestoreState(StateRecorder &inStream) override;
+
+private:
+	float				mTime = 0.0f;
+	BodyID				mBodyID;
+};