Add Vehicle anti roll bar and suspension sprung force multiplier

This commit is contained in:
Mr. Capybara
2024-01-06 14:49:38 -04:00
parent a102bad87e
commit 14a4c92aa8
4 changed files with 130 additions and 28 deletions

View File

@@ -56,9 +56,6 @@ WheeledVehicle::DriveControlSettings WheeledVehicle::GetDriveControl() const
void WheeledVehicle::SetDriveControl(DriveControlSettings &value)
{
// Don't let have an invalid steer vs speed list.
if (&value.SteerVsSpeed == nullptr)
value.SteerVsSpeed = Array<WheeledVehicle::SteerControl>();
if (value.SteerVsSpeed.Count() < 1)
value.SteerVsSpeed.Add(WheeledVehicle::SteerControl());
else // physx backend requires the max of 4 values only
@@ -171,6 +168,20 @@ void WheeledVehicle::SetGearbox(const GearboxSettings &value)
_gearbox = value;
}
void WheeledVehicle::SetAntiRollBars(const Array<AntiRollBar> &value)
{
_antiRollBars = value;
#if WITH_VEHICLE
if (_vehicle)
PhysicsBackend::UpdateVehicleAntiRollBars(this);
#endif
}
const Array<WheeledVehicle::AntiRollBar> &WheeledVehicle::GetAntiRollBars() const
{
return _antiRollBars;
}
void WheeledVehicle::SetThrottle(float value)
{
_throttle = Math::Clamp(value, -1.0f, 1.0f);
@@ -398,20 +409,24 @@ void WheeledVehicle::OnDebugDrawSelected()
DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(data.State.TireContactPoint, 5.0f), Color::Green, 0, false);
}
}
// Draw wheels axes
if (wheelIndex % 2 == 0 && wheelIndex + 1 < _wheels.Count())
{
if (!_wheels[wheelIndex].Collider || !_wheels[wheelIndex + 1].Collider)
continue;
const Vector3 wheelPos = _wheels[wheelIndex].Collider->GetPosition();
const Vector3 nextWheelPos = _wheels[wheelIndex + 1].Collider->GetPosition();
DEBUG_DRAW_LINE(wheelPos, nextWheelPos, Color::Yellow, 0, false);
}
}
// Center of mass
// Draw anti roll bars axes
int wheelsCount = _wheels.Count();
for (int i = 0; i < GetAntiRollBars().Count(); i++)
{
int axleIndex = GetAntiRollBars()[i].Axle;
int leftWheelIndex = axleIndex * 2;
int rightWheelIndex = leftWheelIndex + 1;
if (leftWheelIndex >= wheelsCount || rightWheelIndex >= wheelsCount)
continue;
if (!_wheels[leftWheelIndex].Collider || !_wheels[rightWheelIndex].Collider)
continue;
DEBUG_DRAW_LINE(_wheels[leftWheelIndex].Collider->GetPosition(), _wheels[rightWheelIndex].Collider->GetPosition(), Color::Yellow, 0, false);
}
// Center of mass
DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(_transform.LocalToWorld(_centerOfMassOffset), 10.0f), Color::Blue, 0, false);
RigidBody::OnDebugDrawSelected();
@@ -434,6 +449,7 @@ void WheeledVehicle::Serialize(SerializeStream &stream, const void *otherObj)
SERIALIZE_MEMBER(Engine, _engine);
SERIALIZE_MEMBER(Differential, _differential);
SERIALIZE_MEMBER(Gearbox, _gearbox);
SERIALIZE_MEMBER(AntiRollBars, _antiRollBars);
}
void WheeledVehicle::Deserialize(DeserializeStream &stream, ISerializeModifier *modifier)
@@ -449,6 +465,7 @@ void WheeledVehicle::Deserialize(DeserializeStream &stream, ISerializeModifier *
DESERIALIZE_MEMBER(Engine, _engine);
DESERIALIZE_MEMBER(Differential, _differential);
DESERIALIZE_MEMBER(Gearbox, _gearbox);
DESERIALIZE_MEMBER(AntiRollBars, _antiRollBars);
// [Deprecated on 13.06.2023, expires on 13.06.2025]
_fixInvalidForwardDir |= modifier->EngineBuild < 6341;

View File

@@ -306,6 +306,11 @@ API_CLASS(Attributes="ActorContextMenu(\"New/Physics/Wheeled Vehicle\"), ActorTo
/// </summary>
API_FIELD(Attributes="EditorOrder(4)") ScriptingObjectReference<Collider> Collider;
/// <summary>
/// Spring sprung mass force multiplier.
/// </summary>
API_FIELD(Attributes="Limit(0.01f), EditorDisplay(\"Suspension\"), EditorOrder(19)") float SprungMassMultiplier = 1.0f;
/// <summary>
/// Spring damper rate of suspension unit.
/// </summary>
@@ -407,6 +412,25 @@ API_CLASS(Attributes="ActorContextMenu(\"New/Physics/Wheeled Vehicle\"), ActorTo
#endif
};
/// <summary>
/// Vehicle axle anti roll bar.
/// </summary>
API_STRUCT() struct AntiRollBar : ISerializable
{
DECLARE_SCRIPTING_TYPE_MINIMAL(AntiRollBar);
API_AUTO_SERIALIZATION();
/// <summary>
/// The specific axle with wheels to apply anti roll.
/// </summary>
API_FIELD() int Axle;
/// <summary>
/// The anti roll stiffness.
/// </summary>
API_FIELD() float Stiffness;
};
private:
struct WheelData
{
@@ -420,7 +444,8 @@ private:
DriveModes _driveMode = DriveModes::Standard;
Array<WheelData, FixedAllocation<20>> _wheelsData;
float _throttle = 0.0f, _steering = 0.0f, _brake = 0.0f, _handBrake = 0.0f, _tankLeftThrottle, _tankRightThrottle, _tankLeftBrake, _tankRightBrake;
Array<Wheel> _wheels;
Array<WheeledVehicle::Wheel> _wheels;
Array<WheeledVehicle::AntiRollBar> _antiRollBars;
DriveControlSettings _driveControl;
EngineSettings _engine;
DifferentialSettings _differential;
@@ -511,6 +536,16 @@ public:
/// </summary>
API_PROPERTY() void SetGearbox(const GearboxSettings& value);
// <summary>
/// Sets axles anti roll bars to increase vehicle estability.
/// </summary>
API_PROPERTY() void SetAntiRollBars(const Array<AntiRollBar>& value);
// <summary>
/// Gets axles anti roll bars.
/// </summary>
API_PROPERTY() const Array<AntiRollBar>& GetAntiRollBars() const;
public:
/// <summary>
/// Sets the input for vehicle throttle. It is the analog accelerator pedal value in range (0,1) where 1 represents the pedal fully pressed and 0 represents the pedal in its rest state.

View File

@@ -39,6 +39,7 @@
#include <ThirdParty/PhysX/vehicle/PxVehicleDriveNW.h>
#include <ThirdParty/PhysX/vehicle/PxVehicleDriveTank.h>
#include <ThirdParty/PhysX/vehicle/PxVehicleUtilSetup.h>
#include <ThirdParty/PhysX/vehicle/PxVehicleComponents.h>
#include <ThirdParty/PhysX/PxFiltering.h>
#endif
#if WITH_CLOTH
@@ -3333,7 +3334,7 @@ PxVehicleSuspensionData CreatePxVehicleSuspensionData(const WheeledVehicle::Whee
const float suspensionFrequency = 7.0f;
suspensionData.mMaxCompression = settings.SuspensionMaxRaise;
suspensionData.mMaxDroop = settings.SuspensionMaxDrop;
suspensionData.mSprungMass = wheelSprungMass;
suspensionData.mSprungMass = wheelSprungMass * settings.SprungMassMultiplier;
suspensionData.mSpringStrength = Math::Square(suspensionFrequency) * suspensionData.mSprungMass;
suspensionData.mSpringDamperRate = settings.SuspensionDampingRate * 2.0f * Math::Sqrt(suspensionData.mSpringStrength * suspensionData.mSprungMass);
return suspensionData;
@@ -3380,23 +3381,29 @@ PxVehicleAckermannGeometryData CreatePxVehicleAckermannGeometryData(PxVehicleWhe
return ackermann;
}
bool SortWheelsFrontToBack(WheeledVehicle::Wheel const& a, WheeledVehicle::Wheel const& b)
PxVehicleAntiRollBarData CreatePxPxVehicleAntiRollBarData(const WheeledVehicle::AntiRollBar& settings, int leftWheelIndex, int rightWheelIndex)
{
PxVehicleAntiRollBarData antiRollBar;
antiRollBar.mWheel0 = leftWheelIndex;
antiRollBar.mWheel1 = rightWheelIndex;
antiRollBar.mStiffness = settings.Stiffness;
return antiRollBar;
}
bool SortWheelsFrontToBack(WheeledVehicle::Wheel const &a, WheeledVehicle::Wheel const &b)
{
return a.Collider && b.Collider && a.Collider->GetLocalPosition().Z > b.Collider->GetLocalPosition().Z;
}
void* PhysicsBackend::CreateVehicle(WheeledVehicle* actor)
{
#if USE_EDITOR
if (Editor::IsPlayMode)
#endif
// Physx vehicles needs to have all wheels sorted to apply controls correctly.
// Its needs to know what wheels are on front to turn wheel to correctly side
// and needs to know wheel side to apply throttle to correctly direction for each track when using tanks.
// Anti roll bars needs to have all wheels sorted to get correctly wheel index too.
if (actor->_driveType != WheeledVehicle::DriveTypes::NoDrive)
{
// Physx vehicles needs to have all wheels sorted to apply controls correctly.
// Its needs to know what wheels are on front to turn wheel to correctly side
// and needs to know wheel side to apply throttle to correctly direction for each track when using tanks.
if (actor->_driveType == WheeledVehicle::DriveTypes::Drive4W)
Sorting::QuickSort(actor->_wheels.Get(), actor->_wheels.Count(), SortWheelsFrontToBack);
Sorting::QuickSort(actor->_wheels.Get(), actor->_wheels.Count(), SortWheelsFrontToBack);
// sort wheels by side
if (actor->_driveType == WheeledVehicle::DriveTypes::Tank)
@@ -3468,7 +3475,8 @@ void* PhysicsBackend::CreateVehicle(WheeledVehicle* actor)
// TODO: get gravityDirection from scenePhysX->Scene->getGravity()
PxVehicleComputeSprungMasses(wheels.Count(), offsets, centerOfMassOffset.p, mass, 1, sprungMasses);
PxVehicleWheelsSimData* wheelsSimData = PxVehicleWheelsSimData::allocate(wheels.Count());
for (int32 i = 0; i < wheels.Count(); i++)
int wheelsCount = wheels.Count();
for (int32 i = 0; i < wheelsCount; i++)
{
auto& wheel = *wheels[i];
@@ -3514,6 +3522,19 @@ void* PhysicsBackend::CreateVehicle(WheeledVehicle* actor)
wheelsSimData->disableWheel(i);
}
}
// Add Anti roll bars for wheels axles
for (int i = 0; i < actor->GetAntiRollBars().Count(); i++)
{
int axleIndex = actor->GetAntiRollBars()[i].Axle;
int leftWheelIndex = axleIndex * 2;
int rightWheelIndex = leftWheelIndex + 1;
if (leftWheelIndex >= wheelsCount || rightWheelIndex >= wheelsCount)
continue;
const PxVehicleAntiRollBarData &antiRollBar = CreatePxPxVehicleAntiRollBarData(actor->GetAntiRollBars()[i], leftWheelIndex, rightWheelIndex);
wheelsSimData->addAntiRollBarData(antiRollBar);
}
for (auto child : actor->Children)
{
auto collider = ScriptingObject::Cast<Collider>(child);
@@ -3676,6 +3697,34 @@ void PhysicsBackend::UpdateVehicleWheels(WheeledVehicle* actor)
}
}
void PhysicsBackend::UpdateVehicleAntiRollBars(WheeledVehicle *actor)
{
int wheelsCount = actor->_wheels.Count();
auto drive = (PxVehicleWheels *)actor->_vehicle;
PxVehicleWheelsSimData *wheelsSimData = &drive->mWheelsSimData;
// Update Anti roll bars for wheels axles
for (int i = 0; i < actor->GetAntiRollBars().Count(); i++)
{
int axleIndex = actor->GetAntiRollBars()[i].Axle;
int leftWheelIndex = axleIndex * 2;
int rightWheelIndex = leftWheelIndex + 1;
if (leftWheelIndex >= wheelsCount || rightWheelIndex >= wheelsCount)
continue;
const PxVehicleAntiRollBarData &antiRollBar = CreatePxPxVehicleAntiRollBarData(actor->GetAntiRollBars()[i], leftWheelIndex, rightWheelIndex);
if (wheelsSimData->getNbAntiRollBarData() - 1 < i)
{
wheelsSimData->addAntiRollBarData(antiRollBar);
}
else
{
wheelsSimData->setAntiRollBarData(axleIndex, antiRollBar);
}
}
}
void PhysicsBackend::SetVehicleEngine(void* vehicle, const void* value)
{
auto drive = (PxVehicleDrive*)vehicle;

View File

@@ -262,6 +262,7 @@ public:
static void* CreateVehicle(class WheeledVehicle* actor);
static void DestroyVehicle(void* vehicle, int32 driveType);
static void UpdateVehicleWheels(WheeledVehicle* actor);
static void UpdateVehicleAntiRollBars(WheeledVehicle* actor);
static void SetVehicleEngine(void* vehicle, const void* value);
static void SetVehicleDifferential(void* vehicle, const void* value);
static void SetVehicleGearbox(void* vehicle, const void* value);