Prechádzať zdrojové kódy

Ability to override the position where the suspension and tire forces are applied (#562)

This allows the vehicle to be more stable at the cost of less realistic interaction between the wheels and dynamic objects.
Jorrit Rouwe 2 rokov pred
rodič
commit
9cfdcf024c

+ 13 - 5
Jolt/Physics/Vehicle/VehicleConstraint.cpp

@@ -315,10 +315,18 @@ uint VehicleConstraint::BuildIslandSplits(LargeIslandSplitter &ioSplitter) const
 	return ioSplitter.AssignToNonParallelSplit(mBody);
 }
 
-void VehicleConstraint::CalculateWheelContactPoint(const Wheel &inWheel, Vec3 &outR1PlusU, Vec3 &outR2) const
+void VehicleConstraint::CalculateSuspensionForcePoint(const Wheel &inWheel, Vec3 &outR1PlusU, Vec3 &outR2) const
 {
-	outR1PlusU = Vec3(inWheel.mContactPosition - mBody->GetCenterOfMassPosition());
-	outR2 = Vec3(inWheel.mContactPosition - inWheel.mContactBody->GetCenterOfMassPosition());
+	// Determine point to apply force to
+	RVec3 force_point;
+	if (inWheel.mSettings->mEnableSuspensionForcePoint)
+		force_point = mBody->GetWorldTransform() * inWheel.mSettings->mSuspensionForcePoint;
+	else
+		force_point = inWheel.mContactPosition;
+
+	// Calculate r1 + u and r2
+	outR1PlusU = Vec3(force_point - mBody->GetCenterOfMassPosition());
+	outR2 = Vec3(force_point - inWheel.mContactBody->GetCenterOfMassPosition());
 }
 
 void VehicleConstraint::CalculatePitchRollConstraintProperties(RMat44Arg inBodyTransform)
@@ -358,7 +366,7 @@ void VehicleConstraint::SetupVelocityConstraint(float inDeltaTime)
 			Vec3 neg_contact_normal = -w->mContactNormal;
 
 			Vec3 r1_plus_u, r2;
-			CalculateWheelContactPoint(*w, r1_plus_u, r2);
+			CalculateSuspensionForcePoint(*w, r1_plus_u, r2);
 
 			// Suspension spring
 			if (settings->mSuspensionMaxLength > settings->mSuspensionMinLength)
@@ -509,7 +517,7 @@ bool VehicleConstraint::SolvePositionConstraint(float inDeltaTime, float inBaumg
 
 				// Recalculate constraint properties since the body may have moved
 				Vec3 r1_plus_u, r2;
-				CalculateWheelContactPoint(*w, r1_plus_u, r2);
+				CalculateSuspensionForcePoint(*w, r1_plus_u, r2);
 				w->mSuspensionMaxUpPart.CalculateConstraintProperties(*mBody, r1_plus_u, *w->mContactBody, r2, neg_contact_normal);
 
 				impulse |= w->mSuspensionMaxUpPart.SolvePositionConstraint(*mBody, *w->mContactBody, neg_contact_normal, max_up_error, inBaumgarte);

+ 2 - 2
Jolt/Physics/Vehicle/VehicleConstraint.h

@@ -154,8 +154,8 @@ private:
 	// See: PhysicsStepListener
 	virtual void				OnStep(float inDeltaTime, PhysicsSystem &inPhysicsSystem) override;
 
-	// Calculate the contact positions of the wheel in world space, relative to the center of mass of both bodies
-	void						CalculateWheelContactPoint(const Wheel &inWheel, Vec3 &outR1PlusU, Vec3 &outR2) const;
+	// Calculate the position where the suspension and traction forces should be applied in world space, relative to the center of mass of both bodies
+	void						CalculateSuspensionForcePoint(const Wheel &inWheel, Vec3 &outR1PlusU, Vec3 &outR2) const;
 
 	// Calculate the constraint properties for mPitchRollPart
 	void						CalculatePitchRollConstraintProperties(RMat44Arg inBodyTransform);

+ 6 - 0
Jolt/Physics/Vehicle/Wheel.cpp

@@ -12,6 +12,7 @@ JPH_NAMESPACE_BEGIN
 
 JPH_IMPLEMENT_SERIALIZABLE_VIRTUAL(WheelSettings)
 {
+	JPH_ADD_ATTRIBUTE(WheelSettings, mSuspensionForcePoint)
 	JPH_ADD_ATTRIBUTE(WheelSettings, mPosition)
 	JPH_ADD_ATTRIBUTE(WheelSettings, mSuspensionDirection)
 	JPH_ADD_ATTRIBUTE(WheelSettings, mSteeringAxis)
@@ -24,10 +25,12 @@ JPH_IMPLEMENT_SERIALIZABLE_VIRTUAL(WheelSettings)
 	JPH_ADD_ATTRIBUTE(WheelSettings, mSuspensionDamping)
 	JPH_ADD_ATTRIBUTE(WheelSettings, mRadius)
 	JPH_ADD_ATTRIBUTE(WheelSettings, mWidth)
+	JPH_ADD_ATTRIBUTE(WheelSettings, mEnableSuspensionForcePoint)
 }
 
 void WheelSettings::SaveBinaryState(StreamOut &inStream) const
 {
+	inStream.Write(mSuspensionForcePoint);
 	inStream.Write(mPosition);
 	inStream.Write(mSuspensionDirection);
 	inStream.Write(mSteeringAxis);
@@ -40,10 +43,12 @@ void WheelSettings::SaveBinaryState(StreamOut &inStream) const
 	inStream.Write(mSuspensionDamping);
 	inStream.Write(mRadius);
 	inStream.Write(mWidth);
+	inStream.Write(mEnableSuspensionForcePoint);
 }
 
 void WheelSettings::RestoreBinaryState(StreamIn &inStream)
 {
+	inStream.Read(mSuspensionForcePoint);
 	inStream.Read(mPosition);
 	inStream.Read(mSuspensionDirection);
 	inStream.Read(mSteeringAxis);
@@ -56,6 +61,7 @@ void WheelSettings::RestoreBinaryState(StreamIn &inStream)
 	inStream.Read(mSuspensionDamping);
 	inStream.Read(mRadius);
 	inStream.Read(mWidth);
+	inStream.Read(mEnableSuspensionForcePoint);
 }
 
 Wheel::Wheel(const WheelSettings &inSettings) :

+ 2 - 0
Jolt/Physics/Vehicle/Wheel.h

@@ -27,6 +27,7 @@ public:
 	virtual void			RestoreBinaryState(StreamIn &inStream);
 
 	Vec3					mPosition { 0, 0, 0 };						///< Attachment point of wheel suspension in local space of the body
+	Vec3					mSuspensionForcePoint { 0, 0, 0 };			///< Where tire forces (suspension and traction) are applied, in local space of the body. A good default is the center of the wheel in its neutral pose. See mEnableSuspensionForcePoint.
 	Vec3					mSuspensionDirection { 0, -1, 0 };			///< Direction of the suspension in local space of the body, should point down
 	Vec3					mSteeringAxis { 0, 1, 0 };					///< Direction of the steering axis in local space of the body, should point up (e.g. for a bike would be -mSuspensionDirection)
 	Vec3					mWheelUp { 0, 1, 0 };						///< Up direction when the wheel is in the neutral steering position (usually VehicleConstraintSettings::mUp but can be used to give the wheel camber or for a bike would be -mSuspensionDirection)
@@ -38,6 +39,7 @@ public:
 	float					mSuspensionDamping = 0.5f;					///< Damping factor of the suspension spring (0 = no damping, 1 = critical damping)
 	float					mRadius = 0.3f;								///< Radius of the wheel (m)
 	float					mWidth = 0.1f;								///< Width of the wheel (m)
+	bool					mEnableSuspensionForcePoint = false;		///< Enables mSuspensionForcePoint, if disabled, the forces are applied at the collision contect point. This leads to a more accurate simulation when interacting with dynamic objects but makes the vehicle less stable. When settings this to true, all forces will be applied to a fixed point on the vehicle body.
 };
 
 /// Base class for runtime data for a wheel, each VehicleController can implement a derived class of this

+ 18 - 3
Samples/Tests/Vehicle/MotorcycleTest.cpp

@@ -90,6 +90,18 @@ void MotorcycleTest::Initialize()
 	back->mSuspensionFrequency = back_suspension_freq;
 	back->mMaxBrakeTorque = back_brake_torque;
 
+	if (sOverrideFrontSuspensionForcePoint)
+	{
+		front->mEnableSuspensionForcePoint = true;
+		front->mSuspensionForcePoint = front->mPosition + front->mSuspensionDirection * front->mSuspensionMinLength;
+	}
+
+	if (sOverrideRearSuspensionForcePoint)
+	{
+		back->mEnableSuspensionForcePoint = true;
+		back->mSuspensionForcePoint = back->mPosition + back->mSuspensionDirection * back->mSuspensionMinLength;
+	}
+
 	vehicle.mWheels = { front, back };
 
 	MotorcycleControllerSettings *controller = new MotorcycleControllerSettings;
@@ -172,8 +184,9 @@ void MotorcycleTest::PrePhysicsUpdate(const PreUpdateParams &inParams)
 		mBodyInterface->ActivateBody(mMotorcycleBody->GetID());
 
 	// Pass the input on to the constraint
-	WheeledVehicleController *controller = static_cast<WheeledVehicleController *>(mVehicleConstraint->GetController());
+	MotorcycleController *controller = static_cast<MotorcycleController *>(mVehicleConstraint->GetController());
 	controller->SetDriverInput(forward, mCurrentRight, brake, false);
+	controller->EnableLeanController(sEnableLeanController);
 
 	// Draw our wheels (this needs to be done in the pre update since we draw the bodies too in the state before the step)
 	for (uint w = 0; w < 2; ++w)
@@ -227,6 +240,8 @@ void MotorcycleTest::CreateSettingsMenu(DebugUI *inUI, UIElement *inSubMenu)
 {
 	VehicleTest::CreateSettingsMenu(inUI, inSubMenu);
 
-	MotorcycleController *controller = static_cast<MotorcycleController *>(mVehicleConstraint->GetController());
-	inUI->CreateCheckBox(inSubMenu, "Enable Lean Controller", controller->IsLeanControllerEnabled(), [controller](UICheckBox::EState inState) { controller->EnableLeanController(inState == UICheckBox::STATE_CHECKED); });
+	inUI->CreateCheckBox(inSubMenu, "Override Front Suspension Force Point", sOverrideFrontSuspensionForcePoint, [](UICheckBox::EState inState) { sOverrideFrontSuspensionForcePoint = inState == UICheckBox::STATE_CHECKED; });
+	inUI->CreateCheckBox(inSubMenu, "Override Rear Suspension Force Point", sOverrideRearSuspensionForcePoint, [](UICheckBox::EState inState) { sOverrideRearSuspensionForcePoint = inState == UICheckBox::STATE_CHECKED; });
+	inUI->CreateCheckBox(inSubMenu, "Enable Lean Controller", sEnableLeanController, [](UICheckBox::EState inState) { sEnableLeanController = inState == UICheckBox::STATE_CHECKED; });
+	inUI->CreateTextButton(inSubMenu, "Accept", [this]() { RestartTest(); });
 }

+ 4 - 0
Samples/Tests/Vehicle/MotorcycleTest.h

@@ -29,6 +29,10 @@ public:
 	virtual void				CreateSettingsMenu(DebugUI *inUI, UIElement *inSubMenu) override;
 
 private:
+	static inline bool			sOverrideFrontSuspensionForcePoint = false;	///< If true, the front suspension force point is overridden
+	static inline bool			sOverrideRearSuspensionForcePoint = false;	///< If true, the rear suspension force point is overridden
+	static inline bool			sEnableLeanController = true;				///< If true, the lean controller is enabled
+
 	Body *						mMotorcycleBody;							///< The vehicle
 	Ref<VehicleConstraint>		mVehicleConstraint;							///< The vehicle constraint
 	float						mPreviousForward = 1.0f;					///< Keeps track of last motorcycle direction so we know when to brake and when to accelerate