Ver código fonte

Vehicle improvements (#778)

* Added wheel index and friction direction to friction callback so you can have more differentiation between wheels
* Added ability to disable the lean steering limit for the motorcycle, turning this off makes the motorcycle more unstable, but gives you more control over the final steering angle.
Jorrit Rouwe 1 ano atrás
pai
commit
8d80155f93

+ 2 - 1
Jolt/Physics/Vehicle/MotorcycleController.cpp

@@ -171,7 +171,8 @@ void MotorcycleController::PreCollide(float inDeltaTime, PhysicsSystem &inPhysic
 			float steer_angle = steer_strength * w->GetSettings()->mMaxSteerAngle;
 
 			// Clamp to max steering angle
-			if (velocity_sq > 1.0e-6f && cos_caster_angle > 1.0e-6f)
+			if (mEnableLeanSteeringLimit
+				&& velocity_sq > 1.0e-6f && cos_caster_angle > 1.0e-6f)
 			{
 				float max_steer_angle = ASin(max_steer_angle_factor / (velocity_sq * cos_caster_angle));
 				steer_angle = min(steer_angle, max_steer_angle);

+ 26 - 0
Jolt/Physics/Vehicle/MotorcycleController.h

@@ -58,6 +58,31 @@ public:
 	/// Check if the lean spring is enabled.
 	bool						IsLeanControllerEnabled() const						{ return mEnableLeanController; }
 
+	/// Enable or disable the lean steering limit. When enabled (default) the steering angle is limited based on the vehicle speed to prevent steering that would cause an inertial force that causes the motorcycle to topple over.
+	void						EnableLeanSteeringLimit(bool inEnable)				{ mEnableLeanSteeringLimit = inEnable; }
+	bool						IsLeanSteeringLimitEnabled() const					{ return mEnableLeanSteeringLimit; }
+
+	/// Spring constant for the lean spring
+	void						SetLeanSpringConstant(float inConstant)				{ mLeanSpringConstant = inConstant; }
+	float						GetLeanSpringConstant() const						{ return mLeanSpringConstant; }
+
+	/// Spring damping constant for the lean spring
+	void						SetLeanSpringDamping(float inDamping)				{ mLeanSpringDamping = inDamping; }
+	float						GetLeanSpringDamping() const						{ return mLeanSpringDamping; }
+
+	/// The lean spring applies an additional force equal to this coefficient * Integral(delta angle, 0, t), this effectively makes the lean spring a PID controller
+	void						SetLeanSpringIntegrationCoefficient(float inCoefficient) { mLeanSpringIntegrationCoefficient = inCoefficient; }
+	float						GetLeanSpringIntegrationCoefficient() const			{ return mLeanSpringIntegrationCoefficient; }
+
+	/// How much to decay the angle integral when the wheels are not touching the floor: new_value = e^(-decay * t) * initial_value
+	void						SetLeanSpringIntegrationCoefficientDecay(float inDecay) { mLeanSpringIntegrationCoefficientDecay = inDecay; }
+	float						GetLeanSpringIntegrationCoefficientDecay() const	{ return mLeanSpringIntegrationCoefficientDecay; }
+
+	/// How much to smooth the lean angle (0 = no smoothing, 1 = lean angle never changes)
+	/// Note that this is frame rate dependent because the formula is: smoothing_factor * previous + (1 - smoothing_factor) * current
+	void						SetLeanSmoothingFactor(float inFactor)				{ mLeanSmoothingFactor = inFactor; }
+	float						GetLeanSmoothingFactor() const						{ return mLeanSmoothingFactor; }
+
 protected:
 	// See: VehicleController
 	virtual void				PreCollide(float inDeltaTime, PhysicsSystem &inPhysicsSystem) override;
@@ -70,6 +95,7 @@ protected:
 
 	// Configuration properties
 	bool						mEnableLeanController = true;
+	bool						mEnableLeanSteeringLimit = true;
 	float						mMaxLeanAngle;
 	float						mLeanSpringConstant;
 	float						mLeanSpringDamping;

+ 6 - 6
Jolt/Physics/Vehicle/TrackedVehicleController.cpp

@@ -57,7 +57,7 @@ void WheelTV::CalculateAngularVelocity(const VehicleConstraint &inConstraint)
 	mAngularVelocity = track.mAngularVelocity * wheels[track.mDrivenWheel]->GetSettings()->mRadius / settings->mRadius;
 }
 
-void WheelTV::Update(float inDeltaTime, const VehicleConstraint &inConstraint)
+void WheelTV::Update(uint inWheelIndex, float inDeltaTime, const VehicleConstraint &inConstraint)
 {
 	CalculateAngularVelocity(inConstraint);
 
@@ -72,8 +72,8 @@ void WheelTV::Update(float inDeltaTime, const VehicleConstraint &inConstraint)
 		// Friction at the point of this wheel between track and floor
 		const WheelSettingsTV *settings = GetSettings();
 		VehicleConstraint::CombineFunction combine_friction = inConstraint.GetCombineFriction();
-		mCombinedLongitudinalFriction = combine_friction(settings->mLongitudinalFriction, *mContactBody, mContactSubShapeID);
-		mCombinedLateralFriction = combine_friction(settings->mLateralFriction, *mContactBody, mContactSubShapeID);
+		mCombinedLongitudinalFriction = combine_friction(inWheelIndex, VehicleConstraint::ETireFrictionDirection::Longitudinal, settings->mLongitudinalFriction, *mContactBody, mContactSubShapeID);
+		mCombinedLateralFriction = combine_friction(inWheelIndex, VehicleConstraint::ETireFrictionDirection::Lateral, settings->mLateralFriction, *mContactBody, mContactSubShapeID);
 	}
 	else
 	{
@@ -206,10 +206,10 @@ void TrackedVehicleController::PostCollide(float inDeltaTime, PhysicsSystem &inP
 	Wheels &wheels = mConstraint.GetWheels();
 
 	// Update wheel angle, do this before applying torque to the wheels (as friction will slow them down again)
-	for (Wheel *w_base : wheels)
+	for (uint wheel_index = 0, num_wheels = (uint)wheels.size(); wheel_index < num_wheels; ++wheel_index)
 	{
-		WheelTV *w = static_cast<WheelTV *>(w_base);
-		w->Update(inDeltaTime, mConstraint);
+		WheelTV *w = static_cast<WheelTV *>(wheels[wheel_index]);
+		w->Update(wheel_index, inDeltaTime, mConstraint);
 	}
 
 	// First calculate engine speed based on speed of all wheels

+ 1 - 1
Jolt/Physics/Vehicle/TrackedVehicleController.h

@@ -44,7 +44,7 @@ public:
 	void						CalculateAngularVelocity(const VehicleConstraint &inConstraint);
 
 	/// Update the wheel rotation based on the current angular velocity
-	void						Update(float inDeltaTime, const VehicleConstraint &inConstraint);
+	void						Update(uint inWheelIndex, float inDeltaTime, const VehicleConstraint &inConstraint);
 
 	int							mTrackIndex = -1;							///< Index in mTracks to which this wheel is attached (calculated on initialization)
 	float						mCombinedLongitudinalFriction = 0.0f;		///< Combined friction coefficient in longitudinal direction (combines terrain and track)

+ 11 - 4
Jolt/Physics/Vehicle/VehicleConstraint.h

@@ -78,13 +78,20 @@ public:
 	/// Set the interface that tests collision between wheel and ground
 	void						SetVehicleCollisionTester(const VehicleCollisionTester *inTester) { mVehicleCollisionTester = inTester; }
 
+	/// Tire friction direction
+	enum class ETireFrictionDirection : uint8
+	{
+		Longitudinal,			///< Longitudinal friction direction
+		Lateral,				///< Lateral friction direction
+	};
+
 	/// Callback function to combine the friction of a tire with the friction of the body it is colliding with.
-	using CombineFunction = float (*)(float inTireFriction, const Body &inBody2, const SubShapeID &inSubShapeID2);
+	using CombineFunction = function<float(uint inWheelIndex, ETireFrictionDirection inTireFrictionDirection, float inTireFriction, const Body &inBody2, const SubShapeID &inSubShapeID2)>;
 
 	/// Set the function that combines the friction of two bodies and returns it
 	/// Default method is the geometric mean: sqrt(friction1 * friction2).
-	void						SetCombineFriction(CombineFunction inCombineFriction) { mCombineFriction = inCombineFriction; }
-	CombineFunction				GetCombineFriction() const					{ return mCombineFriction; }
+	void						SetCombineFriction(const CombineFunction &inCombineFriction) { mCombineFriction = inCombineFriction; }
+	const CombineFunction &		GetCombineFriction() const					{ return mCombineFriction; }
 
 	/// Callback function to notify of current stage in PhysicsStepListener::OnStep.
 	using StepCallback = function<void(VehicleConstraint &inVehicle, float inDeltaTime, PhysicsSystem &inPhysicsSystem)>;
@@ -199,7 +206,7 @@ private:
 
 	// Interfaces
 	RefConst<VehicleCollisionTester> mVehicleCollisionTester;				///< Class that performs testing of collision for the wheels
-	CombineFunction				mCombineFriction = [](float inTireFriction, const Body &inBody2, const SubShapeID &) { return sqrt(inTireFriction * inBody2.GetFriction()); };
+	CombineFunction				mCombineFriction = [](uint, ETireFrictionDirection, float inTireFriction, const Body &inBody2, const SubShapeID &) { return sqrt(inTireFriction * inBody2.GetFriction()); };
 
 	// Callbacks
 	StepCallback				mPreStepCallback;

+ 6 - 6
Jolt/Physics/Vehicle/WheeledVehicleController.cpp

@@ -85,7 +85,7 @@ WheelWV::WheelWV(const WheelSettingsWV &inSettings) :
 	JPH_ASSERT(inSettings.mMaxHandBrakeTorque >= 0.0f);
 }
 
-void WheelWV::Update(float inDeltaTime, const VehicleConstraint &inConstraint)
+void WheelWV::Update(uint inWheelIndex, float inDeltaTime, const VehicleConstraint &inConstraint)
 {
 	const WheelSettingsWV *settings = GetSettings();
 
@@ -122,8 +122,8 @@ void WheelWV::Update(float inDeltaTime, const VehicleConstraint &inConstraint)
 
 		// Tire friction
 		VehicleConstraint::CombineFunction combine_friction = inConstraint.GetCombineFriction();
-		mCombinedLongitudinalFriction = combine_friction(longitudinal_slip_friction, *mContactBody, mContactSubShapeID);
-		mCombinedLateralFriction = combine_friction(lateral_slip_friction, *mContactBody, mContactSubShapeID);
+		mCombinedLongitudinalFriction = combine_friction(inWheelIndex, VehicleConstraint::ETireFrictionDirection::Longitudinal, longitudinal_slip_friction, *mContactBody, mContactSubShapeID);
+		mCombinedLateralFriction = combine_friction(inWheelIndex, VehicleConstraint::ETireFrictionDirection::Lateral, lateral_slip_friction, *mContactBody, mContactSubShapeID);
 	}
 	else
 	{
@@ -265,10 +265,10 @@ void WheeledVehicleController::PostCollide(float inDeltaTime, PhysicsSystem &inP
 	Wheels &wheels = mConstraint.GetWheels();
 
 	// Update wheel angle, do this before applying torque to the wheels (as friction will slow them down again)
-	for (Wheel *w_base : wheels)
+	for (uint wheel_index = 0, num_wheels = (uint)wheels.size(); wheel_index < num_wheels; ++wheel_index)
 	{
-		WheelWV *w = static_cast<WheelWV *>(w_base);
-		w->Update(inDeltaTime, mConstraint);
+		WheelWV *w = static_cast<WheelWV *>(wheels[wheel_index]);
+		w->Update(wheel_index, inDeltaTime, mConstraint);
 	}
 
 	// In auto transmission mode, don't accelerate the engine when switching gears

+ 1 - 1
Jolt/Physics/Vehicle/WheeledVehicleController.h

@@ -56,7 +56,7 @@ public:
 	}
 
 	/// Update the wheel rotation based on the current angular velocity
-	void						Update(float inDeltaTime, const VehicleConstraint &inConstraint);
+	void						Update(uint inWheelIndex, float inDeltaTime, const VehicleConstraint &inConstraint);
 
 	float						mLongitudinalSlip = 0.0f;					///< Velocity difference between ground and wheel relative to ground velocity
 	float						mLateralSlip = 0.0f;						///< Angular difference (in radians) between ground and wheel relative to ground velocity