From 3162d4e7709bba6ca79e2f91ef1478783a8563e8 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Mon, 29 Mar 2021 13:41:25 +0200 Subject: [PATCH] Add option for WheeledVehicle drive type --- .../Engine/Physics/Actors/WheeledVehicle.cpp | 169 ++++++++++++++---- Source/Engine/Physics/Actors/WheeledVehicle.h | 30 +++- Source/Engine/Physics/Physics.cpp | 33 +++- 3 files changed, 188 insertions(+), 44 deletions(-) diff --git a/Source/Engine/Physics/Actors/WheeledVehicle.cpp b/Source/Engine/Physics/Actors/WheeledVehicle.cpp index dd518a1f9..7898331b3 100644 --- a/Source/Engine/Physics/Actors/WheeledVehicle.cpp +++ b/Source/Engine/Physics/Actors/WheeledVehicle.cpp @@ -11,7 +11,9 @@ #endif #if WITH_VEHICLE #include +#include #include +#include #include #include #endif @@ -21,12 +23,47 @@ extern void InitVehicleSDK(); extern Array WheelVehicles; #endif +namespace +{ + void FreeDrive(WheeledVehicle::DriveTypes driveType, PxVehicleWheels* drive) + { + switch (driveType) + { + case WheeledVehicle::DriveTypes::Drive4W: + ((PxVehicleDrive4W*)drive)->free(); + break; + case WheeledVehicle::DriveTypes::DriveNW: + ((PxVehicleDriveNW*)drive)->free(); + break; + case WheeledVehicle::DriveTypes::NoDrive: + ((PxVehicleNoDrive*)drive)->free(); + break; + } + } +} + WheeledVehicle::WheeledVehicle(const SpawnParams& params) : RigidBody(params) { _useCCD = 1; } +WheeledVehicle::DriveTypes WheeledVehicle::GetDriveType() const +{ + return _driveType; +} + +void WheeledVehicle::SetDriveType(DriveTypes value) +{ + if (_driveType == value) + return; + _driveType = value; + if (IsDuringPlay()) + { + Setup(); + } +} + const Array& WheeledVehicle::GetWheels() const { return _wheels; @@ -49,7 +86,7 @@ WheeledVehicle::GearboxSettings WheeledVehicle::GetGearbox() const void WheeledVehicle::SetGearbox(const GearboxSettings& value) { #if WITH_VEHICLE - auto& drive = (PxVehicleDrive4W*&)_drive; + auto& drive = (PxVehicleDrive*&)_drive; if (drive) { drive->mDriveDynData.setUseAutoGears(value.AutoGear); @@ -90,7 +127,7 @@ void WheeledVehicle::ClearInput() float WheeledVehicle::GetForwardSpeed() const { #if WITH_VEHICLE - auto& drive = (const PxVehicleDrive4W*&)_drive; + auto& drive = (const PxVehicleWheels*&)_drive; return drive ? drive->computeForwardSpeed() : 0.0f; #else return 0.0f; @@ -100,7 +137,7 @@ float WheeledVehicle::GetForwardSpeed() const float WheeledVehicle::GetSidewaysSpeed() const { #if WITH_VEHICLE - auto& drive = (const PxVehicleDrive4W*&)_drive; + auto& drive = (const PxVehicleWheels*&)_drive; return drive ? drive->computeSidewaysSpeed() : 0.0f; #else return 0.0f; @@ -110,8 +147,8 @@ float WheeledVehicle::GetSidewaysSpeed() const float WheeledVehicle::GetEngineRotationSpeed() const { #if WITH_VEHICLE - auto& drive = (const PxVehicleDrive4W*&)_drive; - return drive ? RadPerSToRpm(drive->mDriveDynData.getEngineRotationSpeed()) : 0.0f; + auto& drive = (const PxVehicleDrive*&)_drive; + return drive && _driveType != DriveTypes::NoDrive ? RadPerSToRpm(drive->mDriveDynData.getEngineRotationSpeed()) : 0.0f; #else return 0.0f; #endif @@ -120,8 +157,8 @@ float WheeledVehicle::GetEngineRotationSpeed() const int32 WheeledVehicle::GetCurrentGear() const { #if WITH_VEHICLE - auto& drive = (const PxVehicleDrive4W*&)_drive; - return drive ? (int32)drive->mDriveDynData.getCurrentGear() - 1 : 0; + auto& drive = (const PxVehicleDrive*&)_drive; + return drive && _driveType != DriveTypes::NoDrive ? (int32)drive->mDriveDynData.getCurrentGear() - 1 : 0; #else return 0; #endif @@ -130,8 +167,8 @@ int32 WheeledVehicle::GetCurrentGear() const void WheeledVehicle::SetCurrentGear(int32 value) { #if WITH_VEHICLE - auto& drive = (PxVehicleDrive4W*&)_drive; - if (drive) + auto& drive = (PxVehicleDrive*&)_drive; + if (drive && _driveType != DriveTypes::NoDrive) { drive->mDriveDynData.forceGearChange((PxU32)(value + 1)); } @@ -141,8 +178,8 @@ void WheeledVehicle::SetCurrentGear(int32 value) int32 WheeledVehicle::GetTargetGear() const { #if WITH_VEHICLE - auto& drive = (const PxVehicleDrive4W*&)_drive; - return drive ? (int32)drive->mDriveDynData.getTargetGear() - 1 : 0; + auto& drive = (const PxVehicleDrive*&)_drive; + return drive && _driveType != DriveTypes::NoDrive ? (int32)drive->mDriveDynData.getTargetGear() - 1 : 0; #else return 0; #endif @@ -151,8 +188,8 @@ int32 WheeledVehicle::GetTargetGear() const void WheeledVehicle::SetTargetGear(int32 value) { #if WITH_VEHICLE - auto& drive = (PxVehicleDrive4W*&)_drive; - if (drive) + auto& drive = (PxVehicleDrive*&)_drive; + if (drive && _driveType != DriveTypes::NoDrive) { drive->mDriveDynData.startGearChange((PxU32)(value + 1)); } @@ -180,13 +217,13 @@ void WheeledVehicle::Setup() #if WITH_VEHICLE if (!_actor) return; - auto& drive = (PxVehicleDrive4W*&)_drive; + auto& drive = (PxVehicleWheels*&)_drive; // Release previous if (drive) { WheelVehicles.Remove(this); - drive->free(); + FreeDrive(_driveTypeCurrent, drive); drive = nullptr; } @@ -270,15 +307,15 @@ void WheeledVehicle::Setup() wheelData.mDampingRate = M2ToCm2(0.25f); switch (wheel.Type) { - case WheelType::FrontLeft: - case WheelType::FrontRight: + case WheelTypes::FrontLeft: + case WheelTypes::FrontRight: // Enable steering for the front wheels only // TODO: expose as settings wheelData.mMaxSteer = PI * 0.3333f; wheelData.mMaxSteer = PI * 0.3333f; break; - case WheelType::RearLeft: - case WheelType::ReadRight: + case WheelTypes::RearLeft: + case WheelTypes::ReadRight: // Enable the handbrake for the rear wheels only // TODO: expose as settings wheelData.mMaxHandBrakeTorque = M2ToCm2(4000.0f); @@ -342,9 +379,14 @@ void WheeledVehicle::Setup() } } - // Initialize vehicle drive simulation data - PxVehicleDriveSimData4W driveSimData; + // Initialize vehicle drive + _driveTypeCurrent = _driveType; + switch (_driveType) { + case DriveTypes::Drive4W: + { + PxVehicleDriveSimData4W driveSimData; + // Differential PxVehicleDifferential4WData diff; // TODO: expose Differential options @@ -383,20 +425,79 @@ void WheeledVehicle::Setup() ackermann.mFrontWidth = Math::Abs(wheelsSimData->getWheelCentreOffset(PxVehicleDrive4WWheelOrder::eFRONT_RIGHT).z - wheelsSimData->getWheelCentreOffset(PxVehicleDrive4WWheelOrder::eFRONT_LEFT).z); ackermann.mRearWidth = Math::Abs(wheelsSimData->getWheelCentreOffset(PxVehicleDrive4WWheelOrder::eREAR_RIGHT).z - wheelsSimData->getWheelCentreOffset(PxVehicleDrive4WWheelOrder::eREAR_LEFT).z); driveSimData.setAckermannGeometryData(ackermann); + + // Create vehicle drive + auto drive4W = PxVehicleDrive4W::allocate(wheels.Count()); + drive4W->setup(CPhysX, _actor, *wheelsSimData, driveSimData, Math::Max(wheels.Count() - 4, 0)); + drive4W->setToRestState(); + drive4W->mDriveDynData.forceGearChange(PxVehicleGearsData::eFIRST); + drive4W->mDriveDynData.setUseAutoGears(_gearbox.AutoGear); + drive = drive4W; + break; + } + case DriveTypes::DriveNW: + { + PxVehicleDriveSimDataNW driveSimData; + + // Differential + PxVehicleDifferentialNWData diff; + // TODO: expose Differential options + for (int32 i = 0; i < wheels.Count(); i++) + diff.setDrivenWheel(i, true); + driveSimData.setDiffData(diff); + + // Engine + PxVehicleEngineData engine; + // TODO: expose Engine options + engine.mMOI = M2ToCm2(1.0f); + engine.mPeakTorque = M2ToCm2(500.0f); + engine.mMaxOmega = RpmToRadPerS(6000.0f); + engine.mDampingRateFullThrottle = M2ToCm2(0.15f); + engine.mDampingRateZeroThrottleClutchEngaged = M2ToCm2(2.0f); + engine.mDampingRateZeroThrottleClutchDisengaged = M2ToCm2(0.35f); + driveSimData.setEngineData(engine); + + // Gears + PxVehicleGearsData gears; + gears.mSwitchTime = Math::Max(_gearbox.SwitchTime, 0.0f); + driveSimData.setGearsData(gears); + + // Auto Box + PxVehicleAutoBoxData autoBox; + driveSimData.setAutoBoxData(autoBox); + + // Clutch + PxVehicleClutchData clutch; + // TODO: expose Clutch options + clutch.mStrength = M2ToCm2(10.0f); + driveSimData.setClutchData(clutch); + + // Create vehicle drive + auto driveNW = PxVehicleDriveNW::allocate(wheels.Count()); + driveNW->setup(CPhysX, _actor, *wheelsSimData, driveSimData, wheels.Count()); + driveNW->setToRestState(); + driveNW->mDriveDynData.forceGearChange(PxVehicleGearsData::eFIRST); + driveNW->mDriveDynData.setUseAutoGears(_gearbox.AutoGear); + drive = driveNW; + break; + } + case DriveTypes::NoDrive: + { + // Create vehicle drive + auto driveNo = PxVehicleNoDrive::allocate(wheels.Count()); + driveNo->setup(CPhysX, _actor, *wheelsSimData); + driveNo->setToRestState(); + drive = driveNo; + break; + } + default: + CRASH; } - // Create vehicle drive - drive = PxVehicleDrive4W::allocate(wheels.Count()); - _actor->setSolverIterationCounts(12, 4); - drive->setup(CPhysX, _actor, *wheelsSimData, driveSimData, Math::Max(wheels.Count() - 4, 0)); WheelVehicles.Add(this); - - // Initialize - drive->setToRestState(); - drive->mDriveDynData.forceGearChange(PxVehicleGearsData::eFIRST); - drive->mDriveDynData.setUseAutoGears(_gearbox.AutoGear); - wheelsSimData->free(); + _actor->setSolverIterationCounts(12, 4); + #else LOG(Fatal, "PhysX Vehicle SDK is not supported."); #endif @@ -441,6 +542,7 @@ void WheeledVehicle::Serialize(SerializeStream& stream, const void* otherObj) SERIALIZE_GET_OTHER_OBJ(WheeledVehicle); + SERIALIZE_MEMBER(DriveType, _driveType); SERIALIZE_MEMBER(Wheels, _wheels); SERIALIZE(UseReverseAsBrake); SERIALIZE_MEMBER(Gearbox, _gearbox); @@ -450,6 +552,7 @@ void WheeledVehicle::Deserialize(DeserializeStream& stream, ISerializeModifier* { RigidBody::Deserialize(stream, modifier); + DESERIALIZE_MEMBER(DriveType, _driveType); DESERIALIZE_MEMBER(Wheels, _wheels); DESERIALIZE(UseReverseAsBrake); DESERIALIZE_MEMBER(Gearbox, _gearbox); @@ -483,12 +586,12 @@ void WheeledVehicle::EndPlay() #endif #if WITH_VEHICLE - auto& drive = (PxVehicleDrive4W*&)_drive; + auto& drive = (PxVehicleWheels*&)_drive; if (drive) { // Parkway Drive WheelVehicles.Remove(this); - drive->free(); + FreeDrive(_driveTypeCurrent, drive); drive = nullptr; } #endif diff --git a/Source/Engine/Physics/Actors/WheeledVehicle.h b/Source/Engine/Physics/Actors/WheeledVehicle.h index b9752c691..88c6a5aa5 100644 --- a/Source/Engine/Physics/Actors/WheeledVehicle.h +++ b/Source/Engine/Physics/Actors/WheeledVehicle.h @@ -18,6 +18,19 @@ API_CLASS() class FLAXENGINE_API WheeledVehicle : public RigidBody DECLARE_SCENE_OBJECT(WheeledVehicle); public: + /// + /// Vehicle driving mode types. + /// + API_ENUM() enum class DriveTypes + { + // Four-wheel drive. Any additional wheels are non-drivable. Optimized for 4-wheel cars. + Drive4W, + // N-wheel drive. Up to 20 drivable wheels. Suits generic wheels configurations. + DriveNW, + // Non-drivable vehicle. + NoDrive, + }; + /// /// Vehicle gearbox settings. /// @@ -40,7 +53,7 @@ public: /// /// Vehicle wheel types. /// - API_ENUM() enum class WheelType + API_ENUM() enum class WheelTypes { // Left wheel of the front axle. FrontLeft, @@ -65,7 +78,7 @@ public: /// /// Wheel placement type. /// - API_FIELD() WheelType Type = WheelType::FrontLeft; + API_FIELD() WheelTypes Type = WheelTypes::FrontLeft; /// /// Combined mass of the wheel and the tire in kg. Typically, a wheel has mass between 20Kg and 80Kg but can be lower and higher depending on the vehicle. @@ -131,6 +144,7 @@ private: }; void* _drive = nullptr; + DriveTypes _driveType = DriveTypes::Drive4W, _driveTypeCurrent; Array> _wheelsData; float _throttle = 0.0f, _steering = 0.0f, _brake = 0.0f, _handBrake = 0.0f; GearboxSettings _gearbox; @@ -144,10 +158,20 @@ public: API_FIELD(Attributes="EditorOrder(0), EditorDisplay(\"Vehicle\")") bool UseReverseAsBrake = true; + /// + /// Gets the vehicle driving model type. + /// + API_PROPERTY(Attributes="EditorOrder(1), EditorDisplay(\"Vehicle\")") DriveTypes GetDriveType() const; + + /// + /// Sets the vehicle driving model type. + /// + API_PROPERTY() void SetDriveType(DriveTypes value); + /// /// Gets the vehicle wheels settings. /// - API_PROPERTY(Attributes="EditorOrder(1), EditorDisplay(\"Vehicle\")") const Array& GetWheels() const; + API_PROPERTY(Attributes="EditorOrder(2), EditorDisplay(\"Vehicle\")") const Array& GetWheels() const; /// /// Sets the vehicle wheels settings. diff --git a/Source/Engine/Physics/Physics.cpp b/Source/Engine/Physics/Physics.cpp index 3f5fd7948..333b21e99 100644 --- a/Source/Engine/Physics/Physics.cpp +++ b/Source/Engine/Physics/Physics.cpp @@ -661,12 +661,11 @@ void Physics::CollectResults() int32 wheelsCount = 0; for (auto wheelVehicle : WheelVehicles) { - auto drive = (PxVehicleDrive4W*)wheelVehicle->_drive; + auto drive = (PxVehicleWheels*)wheelVehicle->_drive; ASSERT(drive); WheelVehiclesCache.Add(drive); wheelsCount += drive->mWheelsSimData.getNbWheels(); - PxVehicleDrive4WRawInputData rawInputData; float throttle = wheelVehicle->_throttle; float brake = wheelVehicle->_brake; if (wheelVehicle->UseReverseAsBrake) @@ -723,10 +722,6 @@ void Physics::CollectResults() { throttle = Math::Max(throttle, 0.0f); } - rawInputData.setAnalogAccel(throttle); - rawInputData.setAnalogBrake(brake); - rawInputData.setAnalogSteer(wheelVehicle->_steering); - rawInputData.setAnalogHandbrake(wheelVehicle->_handBrake); // @formatter:off // Reference: PhysX SDK docs // TODO: expose input control smoothing data @@ -762,7 +757,29 @@ void Physics::CollectResults() }; const PxFixedSizeLookupTable<8> steerVsForwardSpeed(steerVsForwardSpeedData, 4); // @formatter:on - PxVehicleDrive4WSmoothAnalogRawInputsAndSetAnalogInputs(padSmoothing, steerVsForwardSpeed, rawInputData, LastDeltaTime, false, *drive); + switch (wheelVehicle->_driveTypeCurrent) + { + case WheeledVehicle::DriveTypes::Drive4W: + { + PxVehicleDrive4WRawInputData rawInputData; + rawInputData.setAnalogAccel(throttle); + rawInputData.setAnalogBrake(brake); + rawInputData.setAnalogSteer(wheelVehicle->_steering); + rawInputData.setAnalogHandbrake(wheelVehicle->_handBrake); + PxVehicleDrive4WSmoothAnalogRawInputsAndSetAnalogInputs(padSmoothing, steerVsForwardSpeed, rawInputData, LastDeltaTime, false, *(PxVehicleDrive4W*)drive); + break; + } + case WheeledVehicle::DriveTypes::DriveNW: + { + PxVehicleDriveNWRawInputData rawInputData; + rawInputData.setAnalogAccel(throttle); + rawInputData.setAnalogBrake(brake); + rawInputData.setAnalogSteer(wheelVehicle->_steering); + rawInputData.setAnalogHandbrake(wheelVehicle->_handBrake); + PxVehicleDriveNWSmoothAnalogRawInputsAndSetAnalogInputs(padSmoothing, steerVsForwardSpeed, rawInputData, LastDeltaTime, false, *(PxVehicleDriveNW*)drive); + break; + } + } } // Update batches queries cache @@ -798,7 +815,7 @@ void Physics::CollectResults() wheelsCount = 0; for (int32 i = 0; i < WheelVehicles.Count(); i++) { - auto drive = (PxVehicleDrive4W*)WheelVehicles[i]->_drive; + auto drive = (PxVehicleWheels*)WheelVehicles[i]->_drive; auto& perVehicle = WheelVehiclesResultsPerVehicle[i]; perVehicle.nbWheelQueryResults = drive->mWheelsSimData.getNbWheels(); perVehicle.wheelQueryResults = WheelVehiclesResultsPerWheel.Get() + wheelsCount;