CARLA
 
载入中...
搜索中...
未找到
WheeledVehicleMovementComponentNW.cpp
浏览该文件的文档.
1// Copyright (c) 2022 Computer Vision Center (CVC) at the Universitat Autonoma
2// de Barcelona (UAB).
3//
4// This work is licensed under the terms of the MIT license.
5// For a copy, see <https://opensource.org/licenses/MIT>.
6
8#include "PhysicsPublic.h"
9#include "PhysXPublic.h"
10#include "PhysXVehicleManager.h"
11#include "Components/PrimitiveComponent.h"
12#include "Logging/MessageLog.h"
13
14UWheeledVehicleMovementComponentNW::UWheeledVehicleMovementComponentNW(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer)
15{
16 // grab default values from physx
17 PxVehicleEngineData DefEngineData;
18 EngineSetup.MOI = DefEngineData.mMOI;
19 EngineSetup.MaxRPM = OmegaToRPM(DefEngineData.mMaxOmega);
20 EngineSetup.DampingRateFullThrottle = DefEngineData.mDampingRateFullThrottle;
21 EngineSetup.DampingRateZeroThrottleClutchEngaged = DefEngineData.mDampingRateZeroThrottleClutchEngaged;
22 EngineSetup.DampingRateZeroThrottleClutchDisengaged = DefEngineData.mDampingRateZeroThrottleClutchDisengaged;
23
24 // Convert from PhysX curve to ours
25 FRichCurve* TorqueCurveData = EngineSetup.TorqueCurve.GetRichCurve();
26 for (PxU32 KeyIdx = 0; KeyIdx < DefEngineData.mTorqueCurve.getNbDataPairs(); ++KeyIdx)
27 {
28 float Input = DefEngineData.mTorqueCurve.getX(KeyIdx) * EngineSetup.MaxRPM;
29 float Output = DefEngineData.mTorqueCurve.getY(KeyIdx) * DefEngineData.mPeakTorque;
30 TorqueCurveData->AddKey(Input, Output);
31 }
32
33 PxVehicleClutchData DefClutchData;
34 TransmissionSetup.ClutchStrength = DefClutchData.mStrength;
35
36 PxVehicleGearsData DefGearSetup;
37 TransmissionSetup.GearSwitchTime = DefGearSetup.mSwitchTime;
38 TransmissionSetup.ReverseGearRatio = DefGearSetup.mRatios[PxVehicleGearsData::eREVERSE];
39 TransmissionSetup.FinalRatio = DefGearSetup.mFinalRatio;
40
41 PxVehicleAutoBoxData DefAutoBoxSetup;
42 TransmissionSetup.NeutralGearUpRatio = DefAutoBoxSetup.mUpRatios[PxVehicleGearsData::eNEUTRAL];
43 TransmissionSetup.GearAutoBoxLatency = DefAutoBoxSetup.getLatency();
44 TransmissionSetup.bUseGearAutoBox = true;
45
46 for (uint32 i = PxVehicleGearsData::eFIRST; i < DefGearSetup.mNbRatios; ++i)
47 {
48 FVehicleNWGearData GearData;
49 GearData.DownRatio = DefAutoBoxSetup.mDownRatios[i];
50 GearData.UpRatio = DefAutoBoxSetup.mUpRatios[i];
51 GearData.Ratio = DefGearSetup.mRatios[i];
52 TransmissionSetup.ForwardGears.Add(GearData);
53 }
54
55 // Init steering speed curve
56 FRichCurve* SteeringCurveData = SteeringCurve.GetRichCurve();
57 SteeringCurveData->AddKey(0.0f, 1.0f);
58 SteeringCurveData->AddKey(20.0f, 0.9f);
59 SteeringCurveData->AddKey(60.0f, 0.8f);
60 SteeringCurveData->AddKey(120.0f, 0.7f);
61
62 // Initialize WheelSetups array with 4 wheels, this can be modified via editor later
63 const int32 NbrWheels = 4;
64 WheelSetups.SetNum(NbrWheels);
65 DifferentialSetup.SetNum(NbrWheels);
66
67 IdleBrakeInput = 10;
68}
69
70#if WITH_EDITOR
71void UWheeledVehicleMovementComponentNW::PostEditChangeProperty(struct FPropertyChangedEvent& PropertyChangedEvent)
72{
73 Super::PostEditChangeProperty(PropertyChangedEvent);
74 const FName PropertyName = PropertyChangedEvent.Property ? PropertyChangedEvent.Property->GetFName() : NAME_None;
75
76 if (PropertyName == TEXT("DownRatio"))
77 {
78 for (int32 GearIdx = 0; GearIdx < TransmissionSetup.ForwardGears.Num(); ++GearIdx)
79 {
80 FVehicleNWGearData& GearData = TransmissionSetup.ForwardGears[GearIdx];
81 GearData.DownRatio = FMath::Min(GearData.DownRatio, GearData.UpRatio);
82 }
83 }
84 else if (PropertyName == TEXT("UpRatio"))
85 {
86 for (int32 GearIdx = 0; GearIdx < TransmissionSetup.ForwardGears.Num(); ++GearIdx)
87 {
88 FVehicleNWGearData& GearData = TransmissionSetup.ForwardGears[GearIdx];
89 GearData.UpRatio = FMath::Max(GearData.DownRatio, GearData.UpRatio);
90 }
91 }
92 else if (PropertyName == TEXT("SteeringCurve"))
93 {
94 //make sure values are capped between 0 and 1
95 TArray<FRichCurveKey> SteerKeys = SteeringCurve.GetRichCurve()->GetCopyOfKeys();
96 for (int32 KeyIdx = 0; KeyIdx < SteerKeys.Num(); ++KeyIdx)
97 {
98 float NewValue = FMath::Clamp(SteerKeys[KeyIdx].Value, 0.0f, 1.0f);
99 SteeringCurve.GetRichCurve()->UpdateOrAddKey(SteerKeys[KeyIdx].Time, NewValue);
100 }
101 }
102}
103#endif
104
105static void GetVehicleDifferentialNWSetup(const TArray<FVehicleNWWheelDifferentialData>& Setup, PxVehicleDifferentialNWData& PxSetup)
106{
107 for (int32 i = 0; i < Setup.Num(); ++i)
108 {
109 PxSetup.setDrivenWheel(i, Setup[i].bDriven);
110 }
111}
112
114{
115 // Find max torque
116 float PeakTorque = 0.0f;
117 TArray<FRichCurveKey> TorqueKeys = TorqueCurve.GetRichCurveConst()->GetCopyOfKeys();
118 for (int32 KeyIdx = 0; KeyIdx < TorqueKeys.Num(); ++KeyIdx)
119 {
120 FRichCurveKey& Key = TorqueKeys[KeyIdx];
121 PeakTorque = FMath::Max(PeakTorque, Key.Value);
122 }
123 return PeakTorque;
124}
125
126static void GetVehicleEngineSetup(const FVehicleNWEngineData& Setup, PxVehicleEngineData& PxSetup)
127{
128 PxSetup.mMOI = M2ToCm2(Setup.MOI);
129 PxSetup.mMaxOmega = RPMToOmega(Setup.MaxRPM);
130 PxSetup.mDampingRateFullThrottle = M2ToCm2(Setup.DampingRateFullThrottle);
131 PxSetup.mDampingRateZeroThrottleClutchEngaged = M2ToCm2(Setup.DampingRateZeroThrottleClutchEngaged);
132 PxSetup.mDampingRateZeroThrottleClutchDisengaged = M2ToCm2(Setup.DampingRateZeroThrottleClutchDisengaged);
133
134 float PeakTorque = Setup.FindPeakTorque(); // In Nm
135 PxSetup.mPeakTorque = M2ToCm2(PeakTorque); // convert Nm to (kg cm^2/s^2)
136
137 // Convert from our curve to PhysX
138 PxSetup.mTorqueCurve.clear();
139 TArray<FRichCurveKey> TorqueKeys = Setup.TorqueCurve.GetRichCurveConst()->GetCopyOfKeys();
140 int32 NumTorqueCurveKeys = FMath::Min<int32>(TorqueKeys.Num(), PxVehicleEngineData::eMAX_NB_ENGINE_TORQUE_CURVE_ENTRIES);
141 for (int32 KeyIdx = 0; KeyIdx < NumTorqueCurveKeys; ++KeyIdx)
142 {
143 FRichCurveKey& Key = TorqueKeys[KeyIdx];
144 PxSetup.mTorqueCurve.addPair(FMath::Clamp(Key.Time / Setup.MaxRPM, 0.0f, 1.0f), Key.Value / PeakTorque); // Normalize torque to 0-1 range
145 }
146}
147
148static void GetVehicleGearSetup(const FVehicleNWTransmissionData& Setup, PxVehicleGearsData& PxSetup)
149{
150 PxSetup.mSwitchTime = Setup.GearSwitchTime;
151 PxSetup.mRatios[PxVehicleGearsData::eREVERSE] = Setup.ReverseGearRatio;
152 for (int32 i = 0; i < Setup.ForwardGears.Num(); i++)
153 {
154 PxSetup.mRatios[i + PxVehicleGearsData::eFIRST] = Setup.ForwardGears[i].Ratio;
155 }
156 PxSetup.mFinalRatio = Setup.FinalRatio;
157 PxSetup.mNbRatios = Setup.ForwardGears.Num() + PxVehicleGearsData::eFIRST;
158}
159
160static void GetVehicleAutoBoxSetup(const FVehicleNWTransmissionData& Setup, PxVehicleAutoBoxData& PxSetup)
161{
162 for (int32 i = 0; i < Setup.ForwardGears.Num(); ++i)
163 {
164 const FVehicleNWGearData& GearData = Setup.ForwardGears[i];
165 PxSetup.mUpRatios[i + PxVehicleGearsData::eFIRST] = GearData.UpRatio;
166 PxSetup.mDownRatios[i + PxVehicleGearsData::eFIRST] = GearData.DownRatio;
167 }
168 PxSetup.mUpRatios[PxVehicleGearsData::eNEUTRAL] = Setup.NeutralGearUpRatio;
169 PxSetup.setLatency(Setup.GearAutoBoxLatency);
170
171}
172
173int32 UWheeledVehicleMovementComponentNW::GetCustomGearBoxNumForwardGears() const
174{
175 return TransmissionSetup.ForwardGears.Num();
176}
177
178void SetupDriveHelper(const UWheeledVehicleMovementComponentNW* VehicleData, const PxVehicleWheelsSimData* PWheelsSimData, PxVehicleDriveSimDataNW& DriveData)
179{
180 PxVehicleDifferentialNWData DifferentialSetup;
181 GetVehicleDifferentialNWSetup(VehicleData->DifferentialSetup, DifferentialSetup);
182
183 DriveData.setDiffData(DifferentialSetup);
184
185 PxVehicleEngineData EngineSetup;
186 GetVehicleEngineSetup(VehicleData->EngineSetup, EngineSetup);
187 DriveData.setEngineData(EngineSetup);
188
189 PxVehicleClutchData ClutchSetup;
190 ClutchSetup.mStrength = M2ToCm2(VehicleData->TransmissionSetup.ClutchStrength);
191 DriveData.setClutchData(ClutchSetup);
192
193 PxVehicleGearsData GearSetup;
194 GetVehicleGearSetup(VehicleData->TransmissionSetup, GearSetup);
195 DriveData.setGearsData(GearSetup);
196
197 PxVehicleAutoBoxData AutoBoxSetup;
198 GetVehicleAutoBoxSetup(VehicleData->TransmissionSetup, AutoBoxSetup);
199 DriveData.setAutoBoxData(AutoBoxSetup);
200}
201
202void UWheeledVehicleMovementComponentNW::SetupVehicle()
203{
204 if (!UpdatedPrimitive)
205 {
206 return;
207 }
208
209 if (WheelSetups.Num() < 2)
210 {
211 PVehicle = nullptr;
212 PVehicleDrive = nullptr;
213 return;
214 }
215
216 for (int32 WheelIdx = 0; WheelIdx < WheelSetups.Num(); ++WheelIdx)
217 {
218 const FWheelSetup& WheelSetup = WheelSetups[WheelIdx];
219 if (WheelSetup.BoneName == NAME_None)
220 {
221 return;
222 }
223 }
224
225 // Setup the chassis and wheel shapes
226 SetupVehicleShapes();
227
228 // Setup mass properties
229 SetupVehicleMass();
230
231 // Setup the wheels
232 PxVehicleWheelsSimData* PWheelsSimData = PxVehicleWheelsSimData::allocate(WheelSetups.Num());
233 SetupWheels(PWheelsSimData);
234
235 // Setup drive data
236 PxVehicleDriveSimDataNW DriveData;
237 SetupDriveHelper(this, PWheelsSimData, DriveData);
238
239 // Create the vehicle
240 PxVehicleDriveNW* PVehicleDriveNW = PxVehicleDriveNW::allocate(WheelSetups.Num());
241 check(PVehicleDriveNW);
242
243 FBodyInstance* TargetInstance = UpdatedPrimitive->GetBodyInstance();
244
245 FPhysicsCommand::ExecuteWrite(TargetInstance->ActorHandle, [&](const FPhysicsActorHandle& Actor)
246 {
247 PxRigidActor* PActor = FPhysicsInterface::GetPxRigidActor_AssumesLocked(Actor);
248 if (!PActor)
249 {
250 return;
251 }
252
253 if (PxRigidDynamic* PVehicleActor = PActor->is<PxRigidDynamic>())
254 {
255 PVehicleDriveNW->setup(GPhysXSDK, PVehicleActor, *PWheelsSimData, DriveData, 0);
256 PVehicleDriveNW->setToRestState();
257
258 // cleanup
259 PWheelsSimData->free();
260 }
261 });
262
263 PWheelsSimData = nullptr;
264
265 // cache values
266 PVehicle = PVehicleDriveNW;
267 PVehicleDrive = PVehicleDriveNW;
268
269 SetUseAutoGears(TransmissionSetup.bUseGearAutoBox);
270
271}
272
273void UWheeledVehicleMovementComponentNW::UpdateSimulation(float DeltaTime)
274{
275 if (PVehicleDrive == nullptr)
276 return;
277
278 FBodyInstance* TargetInstance = UpdatedPrimitive->GetBodyInstance();
279
280 FPhysicsCommand::ExecuteWrite(TargetInstance->ActorHandle, [&](const FPhysicsActorHandle& Actor)
281 {
282 PxVehicleDriveNWRawInputData RawInputData;
283 RawInputData.setAnalogAccel(ThrottleInput);
284 RawInputData.setAnalogSteer(SteeringInput);
285 RawInputData.setAnalogBrake(BrakeInput);
286 RawInputData.setAnalogHandbrake(HandbrakeInput);
287
288 if (!PVehicleDrive->mDriveDynData.getUseAutoGears())
289 {
290 RawInputData.setGearUp(bRawGearUpInput);
291 RawInputData.setGearDown(bRawGearDownInput);
292 }
293
294 // Convert from our curve to PxFixedSizeLookupTable
295 PxFixedSizeLookupTable<8> SpeedSteerLookup;
296 TArray<FRichCurveKey> SteerKeys = SteeringCurve.GetRichCurve()->GetCopyOfKeys();
297 const int32 MaxSteeringSamples = FMath::Min(8, SteerKeys.Num());
298 for (int32 KeyIdx = 0; KeyIdx < MaxSteeringSamples; KeyIdx++)
299 {
300 FRichCurveKey& Key = SteerKeys[KeyIdx];
301 SpeedSteerLookup.addPair(KmHToCmS(Key.Time), FMath::Clamp(Key.Value, 0.0f, 1.0f));
302 }
303
304 PxVehiclePadSmoothingData SmoothData = {
305 { ThrottleInputRate.RiseRate, BrakeInputRate.RiseRate, HandbrakeInputRate.RiseRate, SteeringInputRate.RiseRate, SteeringInputRate.RiseRate },
306 { ThrottleInputRate.FallRate, BrakeInputRate.FallRate, HandbrakeInputRate.FallRate, SteeringInputRate.FallRate, SteeringInputRate.FallRate }
307 };
308
309 PxVehicleDriveNW* PVehicleDriveNW = (PxVehicleDriveNW*)PVehicleDrive;
310 PxVehicleDriveNWSmoothAnalogRawInputsAndSetAnalogInputs(SmoothData, SpeedSteerLookup, RawInputData, DeltaTime, false, *PVehicleDriveNW);
311 });
312}
313
314void UWheeledVehicleMovementComponentNW::UpdateEngineSetup(const FVehicleNWEngineData& NewEngineSetup)
315{
316 if (PVehicleDrive)
317 {
318 PxVehicleEngineData EngineData;
319 GetVehicleEngineSetup(NewEngineSetup, EngineData);
320
321 PxVehicleDriveNW* PVehicleDriveNW = (PxVehicleDriveNW*)PVehicleDrive;
322 PVehicleDriveNW->mDriveSimData.setEngineData(EngineData);
323 }
324}
325
326void UWheeledVehicleMovementComponentNW::UpdateDifferentialSetup(const TArray<FVehicleNWWheelDifferentialData>& NewDifferentialSetup)
327{
328 if (PVehicleDrive)
329 {
330 PxVehicleDifferentialNWData DifferentialData;
331 GetVehicleDifferentialNWSetup(NewDifferentialSetup, DifferentialData);
332
333 PxVehicleDriveNW* PVehicleDriveNW = (PxVehicleDriveNW*)PVehicleDrive;
334 PVehicleDriveNW->mDriveSimData.setDiffData(DifferentialData);
335 }
336}
337
338void UWheeledVehicleMovementComponentNW::UpdateTransmissionSetup(const FVehicleNWTransmissionData& NewTransmissionSetup)
339{
340 if (PVehicleDrive)
341 {
342 PxVehicleGearsData GearData;
343 GetVehicleGearSetup(NewTransmissionSetup, GearData);
344
345 PxVehicleAutoBoxData AutoBoxData;
346 GetVehicleAutoBoxSetup(NewTransmissionSetup, AutoBoxData);
347
348 PxVehicleDriveNW* PVehicleDriveNW = (PxVehicleDriveNW*)PVehicleDrive;
349 PVehicleDriveNW->mDriveSimData.setGearsData(GearData);
350 PVehicleDriveNW->mDriveSimData.setAutoBoxData(AutoBoxData);
351 }
352}
353
354void BackwardsConvertCm2ToM2NW(float& val, float defaultValue)
355{
356 if (val != defaultValue)
357 {
358 val = Cm2ToM2(val);
359 }
360}
361
362void UWheeledVehicleMovementComponentNW::Serialize(FArchive& Ar)
363{
364 Super::Serialize(Ar);
365 if (Ar.IsLoading() && Ar.UE4Ver() < VER_UE4_VEHICLES_UNIT_CHANGE)
366 {
367 PxVehicleEngineData DefEngineData;
368 const float DefaultRPM = OmegaToRPM(DefEngineData.mMaxOmega);
369
370 // We need to convert from old units to new. This backwards compatible code fails in the rare case that they were using very strange values that are the new defaults in the correct units.
371 EngineSetup.MaxRPM = EngineSetup.MaxRPM != DefaultRPM ? OmegaToRPM(EngineSetup.MaxRPM) : DefaultRPM; //need to convert from rad/s to RPM
372 }
373
374 if (Ar.IsLoading() && Ar.UE4Ver() < VER_UE4_VEHICLES_UNIT_CHANGE2)
375 {
376 PxVehicleEngineData DefEngineData;
377 PxVehicleClutchData DefClutchData;
378
379 // We need to convert from old units to new. This backwards compatable code fails in the rare case that they were using very strange values that are the new defaults in the correct units.
380 BackwardsConvertCm2ToM2NW(EngineSetup.DampingRateFullThrottle, DefEngineData.mDampingRateFullThrottle);
381 BackwardsConvertCm2ToM2NW(EngineSetup.DampingRateZeroThrottleClutchDisengaged, DefEngineData.mDampingRateZeroThrottleClutchDisengaged);
382 BackwardsConvertCm2ToM2NW(EngineSetup.DampingRateZeroThrottleClutchEngaged, DefEngineData.mDampingRateZeroThrottleClutchEngaged);
383 BackwardsConvertCm2ToM2NW(EngineSetup.MOI, DefEngineData.mMOI);
384 BackwardsConvertCm2ToM2NW(TransmissionSetup.ClutchStrength, DefClutchData.mStrength);
385 }
386}
387
388void UWheeledVehicleMovementComponentNW::ComputeConstants()
389{
390 Super::ComputeConstants();
391 MaxEngineRPM = EngineSetup.MaxRPM;
392}
393
394const void* UWheeledVehicleMovementComponentNW::GetTireData(physx::PxVehicleWheels* InWheels, UVehicleWheel* InWheel)
395{
396 const void* realShaderData = &InWheels->mWheelsSimData.getTireData((PxU32)InWheel->WheelIndex);
397 return realShaderData;
398}
399
400const int32 UWheeledVehicleMovementComponentNW::GetWheelShapeMapping(physx::PxVehicleWheels* InWheels, uint32 InWheel)
401{
402 const physx::PxI32 ShapeIndex = InWheels->mWheelsSimData.getWheelShapeMapping((PxU32)InWheel);
403 return ShapeIndex;
404}
405
406const physx::PxVehicleWheelData UWheeledVehicleMovementComponentNW::GetWheelData(physx::PxVehicleWheels* InWheels, uint32 InWheel)
407{
408 const physx::PxVehicleWheelData WheelData = InWheels->mWheelsSimData.getWheelData((physx::PxU32)InWheel);
409 return WheelData;
410}
static void GetVehicleEngineSetup(const FVehicleNWEngineData &Setup, PxVehicleEngineData &PxSetup)
static void GetVehicleGearSetup(const FVehicleNWTransmissionData &Setup, PxVehicleGearsData &PxSetup)
void BackwardsConvertCm2ToM2NW(float &val, float defaultValue)
void SetupDriveHelper(const UWheeledVehicleMovementComponentNW *VehicleData, const PxVehicleWheelsSimData *PWheelsSimData, PxVehicleDriveSimDataNW &DriveData)
static void GetVehicleDifferentialNWSetup(const TArray< FVehicleNWWheelDifferentialData > &Setup, PxVehicleDifferentialNWData &PxSetup)
static void GetVehicleAutoBoxSetup(const FVehicleNWTransmissionData &Setup, PxVehicleAutoBoxData &PxSetup)
float MOI
Moment of inertia of the engine around the axis of rotation (Kgm^2).
float MaxRPM
Maximum revolutions per minute of the engine
float DampingRateFullThrottle
Damping rate of engine when full throttle is applied (Kgm^2/s)
float FindPeakTorque() const
Find the peak torque produced by the TorqueCurve
float DampingRateZeroThrottleClutchEngaged
Damping rate of engine in at zero throttle when the clutch is engaged (Kgm^2/s)
FRuntimeFloatCurve TorqueCurve
Torque (Nm) at a given RPM
float DampingRateZeroThrottleClutchDisengaged
Damping rate of engine in at zero throttle when the clutch is disengaged (in neutral gear) (Kgm^2/s)
float Ratio
Determines the amount of torque multiplication
float DownRatio
Value of engineRevs/maxEngineRevs that is low enough to gear down
float UpRatio
Value of engineRevs/maxEngineRevs that is high enough to gear up
float NeutralGearUpRatio
Value of engineRevs/maxEngineRevs that is high enough to increment gear
float GearSwitchTime
Time it takes to switch gears (seconds)
float FinalRatio
The final gear ratio multiplies the transmission gear ratios.
TArray< FVehicleNWGearData > ForwardGears
Forward gear ratios (up to 30)
float GearAutoBoxLatency
Minimum time it takes the automatic transmission to initiate a gear change (seconds)