Browse Source

Improved sorting of LRA constraints (#1052)

Also added ability to draw soft body constraint order
Jorrit Rouwe 1 năm trước cách đây
mục cha
commit
c416db3c76

+ 3 - 0
Jolt/Core/Color.h

@@ -37,6 +37,9 @@ public:
 	/// Multiply two colors
 	inline Color			operator * (const Color &inRHS) const									{ return Color(uint8((uint32(r) * inRHS.r) >> 8), uint8((uint32(g) * inRHS.g) >> 8), uint8((uint32(b) * inRHS.b) >> 8), uint8((uint32(a) * inRHS.a) >> 8)); }
 
+	/// Multiply color with intensity in the range [0, 1]
+	inline Color			operator * (float inIntensity) const									{ return Color(uint8(r * inIntensity), uint8(g * inIntensity), uint8(b * inIntensity), a); }
+
 	/// Convert to Vec4 with range [0, 1]
 	inline Vec4				ToVec4() const															{ return Vec4(r, g, b, a) / 255.0f; }
 

+ 4 - 4
Jolt/Physics/Body/BodyManager.cpp

@@ -1083,19 +1083,19 @@ void BodyManager::Draw(const DrawSettings &inDrawSettings, const PhysicsSettings
 					mp->DrawVertexVelocities(inRenderer, com);
 
 				if (inDrawSettings.mDrawSoftBodyEdgeConstraints)
-					mp->DrawEdgeConstraints(inRenderer, com, inDrawSettings.mDrawSoftBodyConstraintColor == BodyManager::ESoftBodyConstraintColor::ConstraintGroup);
+					mp->DrawEdgeConstraints(inRenderer, com, inDrawSettings.mDrawSoftBodyConstraintColor);
 
 				if (inDrawSettings.mDrawSoftBodyBendConstraints)
-					mp->DrawBendConstraints(inRenderer, com, inDrawSettings.mDrawSoftBodyConstraintColor == BodyManager::ESoftBodyConstraintColor::ConstraintGroup);
+					mp->DrawBendConstraints(inRenderer, com, inDrawSettings.mDrawSoftBodyConstraintColor);
 
 				if (inDrawSettings.mDrawSoftBodyVolumeConstraints)
-					mp->DrawVolumeConstraints(inRenderer, com, inDrawSettings.mDrawSoftBodyConstraintColor == BodyManager::ESoftBodyConstraintColor::ConstraintGroup);
+					mp->DrawVolumeConstraints(inRenderer, com, inDrawSettings.mDrawSoftBodyConstraintColor);
 
 				if (inDrawSettings.mDrawSoftBodySkinConstraints)
 					mp->DrawSkinConstraints(inRenderer, com);
 
 				if (inDrawSettings.mDrawSoftBodyLRAConstraints)
-					mp->DrawLRAConstraints(inRenderer, com, inDrawSettings.mDrawSoftBodyConstraintColor == BodyManager::ESoftBodyConstraintColor::ConstraintGroup);
+					mp->DrawLRAConstraints(inRenderer, com, inDrawSettings.mDrawSoftBodyConstraintColor);
 
 				if (inDrawSettings.mDrawSoftBodyPredictedBounds)
 					mp->DrawPredictedBounds(inRenderer, com);

+ 12 - 6
Jolt/Physics/Body/BodyManager.h

@@ -21,6 +21,18 @@ class DebugRenderer;
 class BodyDrawFilter;
 #endif // JPH_DEBUG_RENDERER
 
+#ifdef JPH_DEBUG_RENDERER
+
+/// Defines how to color soft body constraints
+enum class ESoftBodyConstraintColor
+{
+	ConstraintType,				/// Draw different types of constraints in different colors
+	ConstraintGroup,			/// Draw constraints in the same group in the same color, non-parallel group will be red
+	ConstraintOrder,			/// Draw constraints in the same group in the same color, non-parallel group will be red, and order within each group will be indicated with gradient
+};
+
+#endif // JPH_DEBUG_RENDERER
+
 /// Array of bodies
 using BodyVector = Array<Body *>;
 
@@ -214,12 +226,6 @@ public:
 		MaterialColor,				///< Color as defined by the PhysicsMaterial of the shape
 	};
 
-	enum class ESoftBodyConstraintColor
-	{
-		ConstraintType,				/// Draw different types of constraints in different colors
-		ConstraintGroup,			/// Draw constraints in the same group in the same color, non-parallel group will be red
-	};
-
 	/// Draw settings
 	struct DrawSettings
 	{

+ 61 - 68
Jolt/Physics/SoftBody/SoftBodyMotionProperties.cpp

@@ -9,6 +9,7 @@
 #include <Jolt/Physics/SoftBody/SoftBodyContactListener.h>
 #include <Jolt/Physics/SoftBody/SoftBodyManifold.h>
 #include <Jolt/Physics/PhysicsSystem.h>
+#include <Jolt/Physics/Body/BodyManager.h>
 #ifdef JPH_DEBUG_RENDERER
 	#include <Jolt/Renderer/DebugRenderer.h>
 #endif // JPH_DEBUG_RENDERER
@@ -990,43 +991,51 @@ void SoftBodyMotionProperties::DrawVertexVelocities(DebugRenderer *inRenderer, R
 		inRenderer->DrawArrow(inCenterOfMassTransform * v.mPosition, inCenterOfMassTransform * (v.mPosition + v.mVelocity), Color::sYellow, 0.01f);
 }
 
-void SoftBodyMotionProperties::DrawEdgeConstraints(DebugRenderer *inRenderer, RMat44Arg inCenterOfMassTransform, bool inDrawConstraintGroupColor) const
+template <typename GetEndIndex, typename DrawConstraint>
+inline void SoftBodyMotionProperties::DrawConstraints(ESoftBodyConstraintColor inConstraintColor, const GetEndIndex &inGetEndIndex, const DrawConstraint &inDrawConstraint, ColorArg inBaseColor) const
 {
-	uint idx = 0;
+	uint start = 0;
 	for (uint i = 0; i < (uint)mSettings->mUpdateGroups.size(); ++i)
 	{
-		uint end = mSettings->mUpdateGroups[i].mEdgeEndIndex;
+		uint end = inGetEndIndex(mSettings->mUpdateGroups[i]);
 
-		Color color;
-		if (inDrawConstraintGroupColor)
-			color = Color::sGetDistinctColor((uint)mSettings->mUpdateGroups.size() - i - 1); // Ensure that color 0 is always the last group
+		Color base_color;
+		if (inConstraintColor != ESoftBodyConstraintColor::ConstraintType)
+			base_color = Color::sGetDistinctColor((uint)mSettings->mUpdateGroups.size() - i - 1); // Ensure that color 0 is always the last group
 		else
-			color = Color::sWhite;
+			base_color = inBaseColor;
 
-		for (; idx < end; ++idx)
+		for (uint idx = start; idx < end; ++idx)
 		{
-			const Edge &e = mSettings->mEdgeConstraints[idx];
-			inRenderer->DrawLine(inCenterOfMassTransform * mVertices[e.mVertex[0]].mPosition, inCenterOfMassTransform * mVertices[e.mVertex[1]].mPosition, color);
+			Color color = inConstraintColor == ESoftBodyConstraintColor::ConstraintOrder? base_color * (float(idx - start) / (end - start)) : base_color;
+			inDrawConstraint(idx, color);
 		}
+
+		start = end;
 	}
 }
 
-void SoftBodyMotionProperties::DrawBendConstraints(DebugRenderer *inRenderer, RMat44Arg inCenterOfMassTransform, bool inDrawConstraintGroupColor) const
+void SoftBodyMotionProperties::DrawEdgeConstraints(DebugRenderer *inRenderer, RMat44Arg inCenterOfMassTransform, ESoftBodyConstraintColor inConstraintColor) const
 {
-	uint idx = 0;
-	for (uint i = 0; i < (uint)mSettings->mUpdateGroups.size(); ++i)
-	{
-		uint end = mSettings->mUpdateGroups[i].mDihedralBendEndIndex;
-
-		Color color;
-		if (inDrawConstraintGroupColor)
-			color = Color::sGetDistinctColor((uint)mSettings->mUpdateGroups.size() - i - 1); // Ensure that color 0 is always the last group
-		else
-			color = Color::sGreen;
+	DrawConstraints(inConstraintColor, 
+		[](const SoftBodySharedSettings::UpdateGroup &inGroup) {
+			return inGroup.mEdgeEndIndex;
+		},
+		[this, inRenderer, &inCenterOfMassTransform](uint inIndex, ColorArg inColor) {
+			const Edge &e = mSettings->mEdgeConstraints[inIndex];
+			inRenderer->DrawLine(inCenterOfMassTransform * mVertices[e.mVertex[0]].mPosition, inCenterOfMassTransform * mVertices[e.mVertex[1]].mPosition, inColor);
+		},
+		Color::sWhite);
+}
 
-		for (; idx < end; ++idx)
-		{
-			const DihedralBend &b = mSettings->mDihedralBendConstraints[idx];
+void SoftBodyMotionProperties::DrawBendConstraints(DebugRenderer *inRenderer, RMat44Arg inCenterOfMassTransform, ESoftBodyConstraintColor inConstraintColor) const
+{
+	DrawConstraints(inConstraintColor, 
+		[](const SoftBodySharedSettings::UpdateGroup &inGroup) {
+			return inGroup.mDihedralBendEndIndex;
+		},
+		[this, inRenderer, &inCenterOfMassTransform](uint inIndex, ColorArg inColor) {
+			const DihedralBend &b = mSettings->mDihedralBendConstraints[inIndex];
 
 			RVec3 x0 = inCenterOfMassTransform * mVertices[b.mVertex[0]].mPosition;
 			RVec3 x1 = inCenterOfMassTransform * mVertices[b.mVertex[1]].mPosition;
@@ -1036,41 +1045,33 @@ void SoftBodyMotionProperties::DrawBendConstraints(DebugRenderer *inRenderer, RM
 			RVec3 c0 = (x0 + x1 + x2) / 3.0_r;
 			RVec3 c1 = (x0 + x1 + x3) / 3.0_r;
 
-			inRenderer->DrawArrow(0.9_r * x0 + 0.1_r * x1, 0.1_r * x0 + 0.9_r * x1, color, 0.01f);
-			inRenderer->DrawLine(c_edge, 0.1_r * c_edge + 0.9_r * c0, color);
-			inRenderer->DrawLine(c_edge, 0.1_r * c_edge + 0.9_r * c1, color);
-		}
-	}
+			inRenderer->DrawArrow(0.9_r * x0 + 0.1_r * x1, 0.1_r * x0 + 0.9_r * x1, inColor, 0.01f);
+			inRenderer->DrawLine(c_edge, 0.1_r * c_edge + 0.9_r * c0, inColor);
+			inRenderer->DrawLine(c_edge, 0.1_r * c_edge + 0.9_r * c1, inColor);
+		},
+		Color::sGreen);
 }
 
-void SoftBodyMotionProperties::DrawVolumeConstraints(DebugRenderer *inRenderer, RMat44Arg inCenterOfMassTransform, bool inDrawConstraintGroupColor) const
+void SoftBodyMotionProperties::DrawVolumeConstraints(DebugRenderer *inRenderer, RMat44Arg inCenterOfMassTransform, ESoftBodyConstraintColor inConstraintColor) const
 {
-	uint idx = 0;
-	for (uint i = 0; i < (uint)mSettings->mUpdateGroups.size(); ++i)
-	{
-		uint end = mSettings->mUpdateGroups[i].mVolumeEndIndex;
-
-		Color color;
-		if (inDrawConstraintGroupColor)
-			color = Color::sGetDistinctColor((uint)mSettings->mUpdateGroups.size() - i - 1); // Ensure that color 0 is always the last group
-		else
-			color = Color::sYellow;
-
-		for (; idx < end; ++idx)
-		{
-			const Volume &v = mSettings->mVolumeConstraints[idx];
+	DrawConstraints(inConstraintColor, 
+		[](const SoftBodySharedSettings::UpdateGroup &inGroup) {
+			return inGroup.mVolumeEndIndex;
+		},
+		[this, inRenderer, &inCenterOfMassTransform](uint inIndex, ColorArg inColor) {
+			const Volume &v = mSettings->mVolumeConstraints[inIndex];
 
 			RVec3 x1 = inCenterOfMassTransform * mVertices[v.mVertex[0]].mPosition;
 			RVec3 x2 = inCenterOfMassTransform * mVertices[v.mVertex[1]].mPosition;
 			RVec3 x3 = inCenterOfMassTransform * mVertices[v.mVertex[2]].mPosition;
 			RVec3 x4 = inCenterOfMassTransform * mVertices[v.mVertex[3]].mPosition;
 
-			inRenderer->DrawTriangle(x1, x3, x2, color, DebugRenderer::ECastShadow::On);
-			inRenderer->DrawTriangle(x2, x3, x4, color, DebugRenderer::ECastShadow::On);
-			inRenderer->DrawTriangle(x1, x4, x3, color, DebugRenderer::ECastShadow::On);
-			inRenderer->DrawTriangle(x1, x2, x4, color, DebugRenderer::ECastShadow::On);
-		}
-	}
+			inRenderer->DrawTriangle(x1, x3, x2, inColor, DebugRenderer::ECastShadow::On);
+			inRenderer->DrawTriangle(x2, x3, x4, inColor, DebugRenderer::ECastShadow::On);
+			inRenderer->DrawTriangle(x1, x4, x3, inColor, DebugRenderer::ECastShadow::On);
+			inRenderer->DrawTriangle(x1, x2, x4, inColor, DebugRenderer::ECastShadow::On);
+		},
+		Color::sYellow);
 }
 
 void SoftBodyMotionProperties::DrawSkinConstraints(DebugRenderer *inRenderer, RMat44Arg inCenterOfMassTransform) const
@@ -1083,25 +1084,17 @@ void SoftBodyMotionProperties::DrawSkinConstraints(DebugRenderer *inRenderer, RM
 	}
 }
 
-void SoftBodyMotionProperties::DrawLRAConstraints(DebugRenderer *inRenderer, RMat44Arg inCenterOfMassTransform, bool inDrawConstraintGroupColor) const
+void SoftBodyMotionProperties::DrawLRAConstraints(DebugRenderer *inRenderer, RMat44Arg inCenterOfMassTransform, ESoftBodyConstraintColor inConstraintColor) const
 {
-	uint idx = 0;
-	for (uint i = 0; i < (uint)mSettings->mUpdateGroups.size(); ++i)
-	{
-		uint end = mSettings->mUpdateGroups[i].mLRAEndIndex;
-
-		Color color;
-		if (inDrawConstraintGroupColor)
-			color = Color::sGetDistinctColor((uint)mSettings->mUpdateGroups.size() - i - 1); // Ensure that color 0 is always the last group
-		else
-			color = Color::sGrey;
-
-		for (; idx < end; ++idx)
-		{
-			const LRA &l = mSettings->mLRAConstraints[idx];
-			inRenderer->DrawLine(inCenterOfMassTransform * mVertices[l.mVertex[0]].mPosition, inCenterOfMassTransform * mVertices[l.mVertex[1]].mPosition, color);
-		}
-	}
+	DrawConstraints(inConstraintColor, 
+		[](const SoftBodySharedSettings::UpdateGroup &inGroup) {
+			return inGroup.mLRAEndIndex;
+		},
+		[this, inRenderer, &inCenterOfMassTransform](uint inIndex, ColorArg inColor) {
+			const LRA &l = mSettings->mLRAConstraints[inIndex];
+			inRenderer->DrawLine(inCenterOfMassTransform * mVertices[l.mVertex[0]].mPosition, inCenterOfMassTransform * mVertices[l.mVertex[1]].mPosition, inColor);
+		},
+		Color::sGrey);
 }
 
 void SoftBodyMotionProperties::DrawPredictedBounds(DebugRenderer *inRenderer, RMat44Arg inCenterOfMassTransform) const

+ 11 - 4
Jolt/Physics/SoftBody/SoftBodyMotionProperties.h

@@ -23,6 +23,7 @@ class SoftBodyCreationSettings;
 class TempAllocator;
 #ifdef JPH_DEBUG_RENDERER
 class DebugRenderer;
+enum class ESoftBodyConstraintColor;
 #endif // JPH_DEBUG_RENDERER
 
 /// This class contains the runtime information of a soft body.
@@ -98,11 +99,11 @@ public:
 	/// Draw the state of a soft body
 	void								DrawVertices(DebugRenderer *inRenderer, RMat44Arg inCenterOfMassTransform) const;
 	void								DrawVertexVelocities(DebugRenderer *inRenderer, RMat44Arg inCenterOfMassTransform) const;
-	void								DrawEdgeConstraints(DebugRenderer *inRenderer, RMat44Arg inCenterOfMassTransform, bool inDrawConstraintGroupColor) const;
-	void								DrawBendConstraints(DebugRenderer *inRenderer, RMat44Arg inCenterOfMassTransform, bool inDrawConstraintGroupColor) const;
-	void								DrawVolumeConstraints(DebugRenderer *inRenderer, RMat44Arg inCenterOfMassTransform, bool inDrawConstraintGroupColor) const;
+	void								DrawEdgeConstraints(DebugRenderer *inRenderer, RMat44Arg inCenterOfMassTransform, ESoftBodyConstraintColor inConstraintColor) const;
+	void								DrawBendConstraints(DebugRenderer *inRenderer, RMat44Arg inCenterOfMassTransform, ESoftBodyConstraintColor inConstraintColor) const;
+	void								DrawVolumeConstraints(DebugRenderer *inRenderer, RMat44Arg inCenterOfMassTransform, ESoftBodyConstraintColor inConstraintColor) const;
 	void								DrawSkinConstraints(DebugRenderer *inRenderer, RMat44Arg inCenterOfMassTransform) const;
-	void								DrawLRAConstraints(DebugRenderer *inRenderer, RMat44Arg inCenterOfMassTransform, bool inDrawConstraintGroupColor) const;
+	void								DrawLRAConstraints(DebugRenderer *inRenderer, RMat44Arg inCenterOfMassTransform, ESoftBodyConstraintColor inConstraintColor) const;
 	void								DrawPredictedBounds(DebugRenderer *inRenderer, RMat44Arg inCenterOfMassTransform) const;
 #endif // JPH_DEBUG_RENDERER
 
@@ -239,6 +240,12 @@ private:
 	/// Returns 6 times the volume of the soft body
 	float								GetVolumeTimesSix() const;
 
+#ifdef JPH_DEBUG_RENDERER
+	/// Helper function to draw constraints
+	template <typename GetEndIndex, typename DrawConstraint>
+		inline void						DrawConstraints(ESoftBodyConstraintColor inConstraintColor, const GetEndIndex &inGetEndIndex, const DrawConstraint &inDrawConstraint, ColorArg inBaseColor) const;
+#endif // JPH_DEBUG_RENDERER
+
 	RMat44								mSkinStateTransform = RMat44::sIdentity();	///< The matrix that transforms mSkinState to world space
 	RefConst<SoftBodySharedSettings>	mSettings;									///< Configuration of the particles and constraints
 	Array<Vertex>						mVertices;									///< Current state of all vertices in the simulation

+ 5 - 5
Jolt/Physics/SoftBody/SoftBodySharedSettings.cpp

@@ -728,11 +728,11 @@ void SoftBodySharedSettings::Optimize(OptimizationResults &outResults)
 				const LRA &l1 = mLRAConstraints[inLHS];
 				const LRA &l2 = mLRAConstraints[inRHS];
 
-				// First sort so that the edge with the smallest distance to a kinematic vertex comes first
-				float d1 = min(mClosestKinematic[l1.mVertex[0]].mDistance, mClosestKinematic[l1.mVertex[1]].mDistance);
-				float d2 = min(mClosestKinematic[l2.mVertex[0]].mDistance, mClosestKinematic[l2.mVertex[1]].mDistance);
-				if (d1 != d2)
-					return d1 < d2;
+				// First sort so that the longest constraint comes first (meaning the shortest constraint has the most influence on the end result)
+				// Most of the time there will be a single LRA constraint per vertex and since the LRA constraint only modifies a single vertex,
+				// updating one constraint will not violate another constraint.
+				if (l1.mMaxDistance != l2.mMaxDistance)
+					return l1.mMaxDistance > l2.mMaxDistance;
 
 				// Order constraints so that the ones with the smallest index go first
 				uint32 m1 = l1.GetMinVertexIndex();

+ 1 - 1
Samples/SamplesApp.cpp

@@ -531,7 +531,7 @@ SamplesApp::SamplesApp()
 			mDebugUI->CreateCheckBox(drawing_options, "Draw Soft Body Skin Constraints", mBodyDrawSettings.mDrawSoftBodySkinConstraints, [this](UICheckBox::EState inState) { mBodyDrawSettings.mDrawSoftBodySkinConstraints = inState == UICheckBox::STATE_CHECKED; });
 			mDebugUI->CreateCheckBox(drawing_options, "Draw Soft Body LRA Constraints", mBodyDrawSettings.mDrawSoftBodyLRAConstraints, [this](UICheckBox::EState inState) { mBodyDrawSettings.mDrawSoftBodyLRAConstraints = inState == UICheckBox::STATE_CHECKED; });
 			mDebugUI->CreateCheckBox(drawing_options, "Draw Soft Body Predicted Bounds", mBodyDrawSettings.mDrawSoftBodyPredictedBounds, [this](UICheckBox::EState inState) { mBodyDrawSettings.mDrawSoftBodyPredictedBounds = inState == UICheckBox::STATE_CHECKED; });
-			mDebugUI->CreateComboBox(drawing_options, "Draw Soft Body Constraint Color", { "Constraint Type", "Constraint Group" }, (int)mBodyDrawSettings.mDrawSoftBodyConstraintColor, [this](int inItem) { mBodyDrawSettings.mDrawSoftBodyConstraintColor = (BodyManager::ESoftBodyConstraintColor)inItem; });
+			mDebugUI->CreateComboBox(drawing_options, "Draw Soft Body Constraint Color", { "Constraint Type", "Constraint Group", "Constraint Order" }, (int)mBodyDrawSettings.mDrawSoftBodyConstraintColor, [this](int inItem) { mBodyDrawSettings.mDrawSoftBodyConstraintColor = (ESoftBodyConstraintColor)inItem; });
 			mDebugUI->ShowMenu(drawing_options);
 		});
 	#endif // JPH_DEBUG_RENDERER