diff --git a/Source/Engine/Physics/Actors/WheeledVehicle.cpp b/Source/Engine/Physics/Actors/WheeledVehicle.cpp index 29d1a9e63..66a13fd7f 100644 --- a/Source/Engine/Physics/Actors/WheeledVehicle.cpp +++ b/Source/Engine/Physics/Actors/WheeledVehicle.cpp @@ -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(); - 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 &value) +{ + _antiRollBars = value; +#if WITH_VEHICLE + if (_vehicle) + PhysicsBackend::UpdateVehicleAntiRollBars(this); +#endif +} + +const Array &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; diff --git a/Source/Engine/Physics/Actors/WheeledVehicle.h b/Source/Engine/Physics/Actors/WheeledVehicle.h index f7288a240..2048a2f46 100644 --- a/Source/Engine/Physics/Actors/WheeledVehicle.h +++ b/Source/Engine/Physics/Actors/WheeledVehicle.h @@ -306,6 +306,11 @@ API_CLASS(Attributes="ActorContextMenu(\"New/Physics/Wheeled Vehicle\"), ActorTo /// API_FIELD(Attributes="EditorOrder(4)") ScriptingObjectReference Collider; + /// + /// Spring sprung mass force multiplier. + /// + API_FIELD(Attributes="Limit(0.01f), EditorDisplay(\"Suspension\"), EditorOrder(19)") float SprungMassMultiplier = 1.0f; + /// /// Spring damper rate of suspension unit. /// @@ -407,6 +412,25 @@ API_CLASS(Attributes="ActorContextMenu(\"New/Physics/Wheeled Vehicle\"), ActorTo #endif }; + /// + /// Vehicle axle anti roll bar. + /// + API_STRUCT() struct AntiRollBar : ISerializable + { + DECLARE_SCRIPTING_TYPE_MINIMAL(AntiRollBar); + API_AUTO_SERIALIZATION(); + + /// + /// The specific axle with wheels to apply anti roll. + /// + API_FIELD() int Axle; + + /// + /// The anti roll stiffness. + /// + API_FIELD() float Stiffness; + }; + private: struct WheelData { @@ -420,7 +444,8 @@ private: DriveModes _driveMode = DriveModes::Standard; Array> _wheelsData; float _throttle = 0.0f, _steering = 0.0f, _brake = 0.0f, _handBrake = 0.0f, _tankLeftThrottle, _tankRightThrottle, _tankLeftBrake, _tankRightBrake; - Array _wheels; + Array _wheels; + Array _antiRollBars; DriveControlSettings _driveControl; EngineSettings _engine; DifferentialSettings _differential; @@ -511,6 +536,16 @@ public: /// API_PROPERTY() void SetGearbox(const GearboxSettings& value); + // + /// Sets axles anti roll bars to increase vehicle estability. + /// + API_PROPERTY() void SetAntiRollBars(const Array& value); + + // + /// Gets axles anti roll bars. + /// + API_PROPERTY() const Array& GetAntiRollBars() const; + public: /// /// 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. diff --git a/Source/Engine/Physics/PhysX/PhysicsBackendPhysX.cpp b/Source/Engine/Physics/PhysX/PhysicsBackendPhysX.cpp index 98fbf7596..70ac6a2af 100644 --- a/Source/Engine/Physics/PhysX/PhysicsBackendPhysX.cpp +++ b/Source/Engine/Physics/PhysX/PhysicsBackendPhysX.cpp @@ -39,6 +39,7 @@ #include #include #include +#include #include #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(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; diff --git a/Source/Engine/Physics/PhysicsBackend.h b/Source/Engine/Physics/PhysicsBackend.h index f20683e31..63c14fdc3 100644 --- a/Source/Engine/Physics/PhysicsBackend.h +++ b/Source/Engine/Physics/PhysicsBackend.h @@ -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);