Browse Source

Added a global multiplier to the skin constraints mMaxDistance (#1023)

This allows blending from hard skinning to simulation.
Jorrit Rouwe 1 year ago
parent
commit
2c9bb90893

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

@@ -393,7 +393,7 @@ void SoftBodyMotionProperties::ApplyVolumeConstraints(const SoftBodyUpdateContex
 void SoftBodyMotionProperties::ApplySkinConstraints([[maybe_unused]] const SoftBodyUpdateContext &inContext)
 {
 	// Early out if nothing to do
-	if (mSettings->mSkinnedConstraints.empty())
+	if (mSettings->mSkinnedConstraints.empty() || !mEnableSkinConstraints)
 		return;
 
 	JPH_ASSERT(mSkinStateTransform == inContext.mCenterOfMassTransform, "Skinning state is stale, artifacts will show!");
@@ -405,10 +405,11 @@ void SoftBodyMotionProperties::ApplySkinConstraints([[maybe_unused]] const SoftB
 	{
 		Vertex &vertex = vertices[s.mVertex];
 		const SkinState &skin_state = skin_states[s.mVertex];
-		if (s.mMaxDistance > 0.0f)
+		float max_distance = s.mMaxDistance * mSkinnedMaxDistanceMultiplier;
+		if (max_distance > 0.0f)
 		{
 			// Move vertex if it violated the back stop
-			if (s.mBackStopDistance < s.mMaxDistance)
+			if (s.mBackStopDistance < max_distance)
 			{
 				// Center of the back stop sphere
 				Vec3 center = skin_state.mPosition - skin_state.mNormal * (s.mBackStopDistance + s.mBackStopRadius);
@@ -427,11 +428,11 @@ void SoftBodyMotionProperties::ApplySkinConstraints([[maybe_unused]] const SoftB
 			}
 
 			// Clamp vertex distance to max distance from skinned position
-			if (s.mMaxDistance < FLT_MAX)
+			if (max_distance < FLT_MAX)
 			{
 				Vec3 delta = vertex.mPosition - skin_state.mPosition;
 				float delta_len_sq = delta.LengthSq();
-				float max_distance_sq = Square(s.mMaxDistance);
+				float max_distance_sq = Square(max_distance);
 				if (delta_len_sq > max_distance_sq)
 					vertex.mPosition = skin_state.mPosition + delta * sqrt(max_distance_sq / delta_len_sq);
 			}
@@ -936,6 +937,16 @@ void SoftBodyMotionProperties::SkinVertices(RMat44Arg inCenterOfMassTransform, c
 			vertex.mVelocity = Vec3::sZero();
 		}
 	}
+	else if (!mEnableSkinConstraints)
+	{
+		// Hard skin only the kinematic vertices as we will not solve the skin constraints later
+		for (const Skinned &s : mSettings->mSkinnedConstraints)
+			if (s.mMaxDistance == 0.0f)
+			{
+				Vertex &vertex = mVertices[s.mVertex];
+				vertex.mPosition = mSkinState[s.mVertex].mPosition;
+			}
+	}
 }
 
 void SoftBodyMotionProperties::CustomUpdate(float inDeltaTime, Body &ioSoftBody, PhysicsSystem &inSystem)

+ 10 - 0
Jolt/Physics/SoftBody/SoftBodyMotionProperties.h

@@ -77,6 +77,14 @@ public:
 	bool								GetUpdatePosition() const					{ return mUpdatePosition; }
 	void								SetUpdatePosition(bool inUpdatePosition)	{ mUpdatePosition = inUpdatePosition; }
 
+	/// Global setting to turn on/off skin constraints
+	bool								GetEnableSkinConstraints() const			{ return mEnableSkinConstraints; }
+	void								SetEnableSkinConstraints(bool inEnableSkinConstraints) { mEnableSkinConstraints = inEnableSkinConstraints; }
+
+	/// Multiplier applied to Skinned::mMaxDistance to allow tightening or loosening of the skin constraints. 0 to hard skin all vertices.
+	float								GetSkinnedMaxDistanceMultiplier() const		{ return mSkinnedMaxDistanceMultiplier; }
+	void								SetSkinnedMaxDistanceMultiplier(float inSkinnedMaxDistanceMultiplier) { mSkinnedMaxDistanceMultiplier = inSkinnedMaxDistanceMultiplier; }
+
 	/// Get local bounding box
 	const AABox &						GetLocalBounds() const						{ return mLocalBounds; }
 
@@ -237,8 +245,10 @@ private:
 	AABox								mLocalPredictedBounds;						///< Predicted bounding box for all vertices using extrapolation of velocity by last step delta time
 	uint32								mNumIterations;								///< Number of solver iterations
 	float								mPressure;									///< n * R * T, amount of substance * ideal gas constant * absolute temperature, see https://en.wikipedia.org/wiki/Pressure
+	float								mSkinnedMaxDistanceMultiplier = 1.0f;		///< Multiplier applied to Skinned::mMaxDistance to allow tightening or loosening of the skin constraints
 	bool								mUpdatePosition;							///< Update the position of the body while simulating (set to false for something that is attached to the static world)
 	bool								mHasContact = false;						///< True if the soft body has collided with anything in the last update
+	bool								mEnableSkinConstraints = true;				///< If skin constraints are enabled
 };
 
 JPH_NAMESPACE_END

+ 9 - 0
Samples/Tests/SoftBody/SoftBodySkinnedConstraintTest.cpp

@@ -10,6 +10,7 @@
 #include <Utils/SoftBodyCreator.h>
 #include <Layers.h>
 #include <Renderer/DebugRendererImp.h>
+#include <Application/DebugUI.h>
 
 JPH_IMPLEMENT_RTTI_VIRTUAL(SoftBodySkinnedConstraintTest)
 {
@@ -49,6 +50,8 @@ void SoftBodySkinnedConstraintTest::SkinVertices(bool inHardSkinAll)
 		m = offset * m;
 
 	SoftBodyMotionProperties *mp = static_cast<SoftBodyMotionProperties *>(mBody->GetMotionProperties());
+	mp->SetEnableSkinConstraints(sEnableSkinConstraints);
+	mp->SetSkinnedMaxDistanceMultiplier(sMaxDistanceMultiplier);
 	mp->SkinVertices(com, pose.data(), cNumJoints, inHardSkinAll, *mTempAllocator);
 }
 
@@ -156,3 +159,9 @@ void SoftBodySkinnedConstraintTest::RestoreState(StateRecorder &inStream)
 {
 	inStream.Read(mTime);
 }
+
+void SoftBodySkinnedConstraintTest::CreateSettingsMenu(DebugUI *inUI, UIElement *inSubMenu)
+{
+	inUI->CreateCheckBox(inSubMenu, "Enable Skin Constraints", sEnableSkinConstraints, [](UICheckBox::EState inState) { sEnableSkinConstraints = inState == UICheckBox::STATE_CHECKED; });
+	inUI->CreateSlider(inSubMenu, "Max Distance Multiplier", sMaxDistanceMultiplier, 0.0f, 10.0f, 0.1f, [](float inValue) { sMaxDistanceMultiplier = inValue; });
+}

+ 6 - 0
Samples/Tests/SoftBody/SoftBodySkinnedConstraintTest.h

@@ -19,6 +19,8 @@ public:
 	virtual void			GetInitialCamera(CameraState &ioState) const override		{ ioState.mPos = RVec3(15, 30, 15); }
 	virtual void			SaveState(StateRecorder &inStream) const override;
 	virtual void			RestoreState(StateRecorder &inStream) override;
+	virtual bool			HasSettingsMenu() const override							{ return true; }
+	virtual void			CreateSettingsMenu(DebugUI *inUI, UIElement *inSubMenu) override;
 
 private:
 	// Size and spacing of the cloth
@@ -43,4 +45,8 @@ private:
 
 	// Current time
 	float					mTime = 0.0f;
+
+	// Settings
+	static inline bool		sEnableSkinConstraints = true;
+	static inline float		sMaxDistanceMultiplier = 1.0f;
 };