diff --git a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Carla.Build.cs b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Carla.Build.cs index d5e2afd93..641fae1a6 100644 --- a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Carla.Build.cs +++ b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Carla.Build.cs @@ -93,7 +93,8 @@ public class Carla : ModuleRules "PhysXVehicles", "PhysXVehicleLib", "Slate", - "SlateCore" + "SlateCore", + "PhysicsCore" // ... add private dependencies that you statically link with here ... } ); diff --git a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Vehicle/CarlaSimpleVehicle.h b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Vehicle/CarlaSimpleVehicle.h new file mode 100644 index 000000000..efa7b3f7e --- /dev/null +++ b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Vehicle/CarlaSimpleVehicle.h @@ -0,0 +1,76 @@ +// Copyright (c) 2021 Computer Vision Center (CVC) at the Universitat Autonoma +// de Barcelona (UAB). +// +// This work is licensed under the terms of the MIT license. +// For a copy, see . + +#pragma once +PRAGMA_DISABLE_DEPRECATION_WARNINGS + +#include "CoreMinimal.h" +#include "GameFramework/Pawn.h" +#include "MovementComponents/BaseCarlaMovementComponent.h" +#include "DisplayDebugHelpers.h" + +#include "CarlaSimpleVehicle.generated.h" + + +UCLASS() +class CARLA_API ACarlaSimpleVehicle : public APawn +{ + GENERATED_BODY() + +public: + ACarlaSimpleVehicle(const FObjectInitializer& ObjectInitializer); + ~ACarlaSimpleVehicle(); + +protected: + // Called when the game starts or when spawned + virtual void BeginPlay() override; + +public: + // Called every frame + virtual void Tick(float DeltaTime) override; + + /** The main skeletal mesh associated with this Vehicle */ + UPROPERTY(Category = Vehicle, VisibleDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = "true")) + class USkeletalMeshComponent* Mesh; + + /** vehicle simulation component */ + UPROPERTY(Category = Vehicle, VisibleDefaultsOnly, BlueprintReadOnly, meta = (AllowPrivateAccess = "true")) + class UWheeledVehicleMovementComponent* VehicleMovement; + + +public: + + /** Name of the MeshComponent. Use this name if you want to prevent creation of the component (with ObjectInitializer.DoNotCreateDefaultSubobject). */ + static FName VehicleMeshComponentName; + + /** Name of the VehicleMovement. Use this name if you want to use a different class (with ObjectInitializer.SetDefaultSubobjectClass). */ + static FName VehicleMovementComponentName; + + /** Util to get the wheeled vehicle movement component */ + class UWheeledVehicleMovementComponent* GetVehicleMovementComponent() const; + + //~ Begin AActor Interface + virtual void DisplayDebug(class UCanvas* Canvas, const FDebugDisplayInfo& DebugDisplay, float& YL, float& YPos) override; + //~ End Actor Interface + + /** Returns Mesh subobject **/ + class USkeletalMeshComponent* GetMesh() const { return Mesh; } + /** Returns VehicleMovement subobject **/ + class UWheeledVehicleMovementComponent* GetVehicleMovement() const { return VehicleMovement; } + + +private: + + UPROPERTY(Category = "CARLA Simple Wheeled Vehicle", VisibleAnywhere) + bool bPhysicsEnabled = true; + + // Small workarround to allow optional CarSim plugin usage + UPROPERTY(Category = "CARLA Simple Wheeled Vehicle", VisibleAnywhere, BlueprintReadOnly, meta = (AllowPrivateAccess = "true")) + UBaseCarlaMovementComponent* BaseMovementComponent = nullptr; +}; + + +PRAGMA_ENABLE_DEPRECATION_WARNINGS diff --git a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Vehicle/CarlaWheeledVehicle.cpp b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Vehicle/CarlaWheeledVehicle.cpp index 4998962a2..a2fd89100 100644 --- a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Vehicle/CarlaWheeledVehicle.cpp +++ b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Vehicle/CarlaWheeledVehicle.cpp @@ -74,6 +74,26 @@ void ACarlaWheeledVehicle::SetWheelCollision(UWheeledVehicleMovementComponent4W } +void ACarlaWheeledVehicle::SetWheelCollisionNW(UWheeledVehicleMovementComponentNW *VehicleNW, + const FVehiclePhysicsControl &PhysicsControl ) { + + #ifdef WHEEL_SWEEP_ENABLED + const bool IsEqual = VehicleNW->UseSweepWheelCollision == PhysicsControl.UseSweepWheelCollision; + + if (IsEqual) + return; + + VehicleNW->UseSweepWheelCollision = PhysicsControl.UseSweepWheelCollision; + + #else + + if (PhysicsControl.UseSweepWheelCollision) + UE_LOG(LogCarla, Warning, TEXT("Error: Sweep for wheel collision is not available. \ + Make sure you have installed the required patch.") ); + + #endif +} + void ACarlaWheeledVehicle::BeginPlay() { Super::BeginPlay(); @@ -136,42 +156,44 @@ void ACarlaWheeledVehicle::BeginPlay() float FrictionScale = 3.5f; - UWheeledVehicleMovementComponent4W *Vehicle4W = Cast( - GetVehicleMovementComponent()); - check(Vehicle4W != nullptr); + UWheeledVehicleMovementComponent* MovementComponent = GetVehicleMovementComponent(); - // Setup Tire Configs with default value. This is needed to avoid getting - // friction values of previously created TireConfigs for the same vehicle - // blueprint. - TArray OriginalFrictions; - OriginalFrictions.Init(FrictionScale, Vehicle4W->Wheels.Num()); - SetWheelsFrictionScale(OriginalFrictions); - - // Check if it overlaps with a Friction trigger, if so, update the friction - // scale. - TArray OverlapActors; - GetOverlappingActors(OverlapActors, AFrictionTrigger::StaticClass()); - for (const auto &Actor : OverlapActors) + if (MovementComponent) { - AFrictionTrigger *FrictionTrigger = Cast(Actor); - if (FrictionTrigger) + check(MovementComponent != nullptr); + + // Setup Tire Configs with default value. This is needed to avoid getting + // friction values of previously created TireConfigs for the same vehicle + // blueprint. + TArray OriginalFrictions; + OriginalFrictions.Init(FrictionScale, MovementComponent->Wheels.Num()); + SetWheelsFrictionScale(OriginalFrictions); + + // Check if it overlaps with a Friction trigger, if so, update the friction + // scale. + TArray OverlapActors; + GetOverlappingActors(OverlapActors, AFrictionTrigger::StaticClass()); + for (const auto &Actor : OverlapActors) { - FrictionScale = FrictionTrigger->Friction; + AFrictionTrigger *FrictionTrigger = Cast(Actor); + if (FrictionTrigger) + { + FrictionScale = FrictionTrigger->Friction; + } } + + // Set the friction scale to Wheel CDO and update wheel setups + TArray NewWheelSetups = MovementComponent->WheelSetups; + for (const auto &WheelSetup : NewWheelSetups) + { + UVehicleWheel *Wheel = WheelSetup.WheelClass.GetDefaultObject(); + check(Wheel != nullptr); + } + + MovementComponent->WheelSetups = NewWheelSetups; + + LastPhysicsControl = GetVehiclePhysicsControl(); } - - // Set the friction scale to Wheel CDO and update wheel setups - TArray NewWheelSetups = Vehicle4W->WheelSetups; - - for (const auto &WheelSetup : NewWheelSetups) - { - UVehicleWheel *Wheel = WheelSetup.WheelClass.GetDefaultObject(); - check(Wheel != nullptr); - } - - Vehicle4W->WheelSetups = NewWheelSetups; - - LastPhysicsControl = GetVehiclePhysicsControl(); } void ACarlaWheeledVehicle::AdjustVehicleBounds() @@ -282,111 +304,199 @@ void ACarlaWheeledVehicle::SetHandbrakeInput(const bool Value) TArray ACarlaWheeledVehicle::GetWheelsFrictionScale() { - UWheeledVehicleMovementComponent4W *Vehicle4W = Cast( - GetVehicleMovement()); - check(Vehicle4W != nullptr); + UWheeledVehicleMovementComponent* Movement = GetVehicleMovement(); TArray WheelsFrictionScale; - for (auto &Wheel : Vehicle4W->Wheels) + if (Movement) { - WheelsFrictionScale.Add(Wheel->TireConfig->GetFrictionScale()); + check(Movement != nullptr); + + for (auto &Wheel : Movement->Wheels) + { + WheelsFrictionScale.Add(Wheel->TireConfig->GetFrictionScale()); + } } return WheelsFrictionScale; } void ACarlaWheeledVehicle::SetWheelsFrictionScale(TArray &WheelsFrictionScale) { - UWheeledVehicleMovementComponent4W *Vehicle4W = Cast( - GetVehicleMovement()); - check(Vehicle4W != nullptr); - check(Vehicle4W->Wheels.Num() == WheelsFrictionScale.Num()); - for (int32 i = 0; i < Vehicle4W->Wheels.Num(); ++i) + UWheeledVehicleMovementComponent* Movement = GetVehicleMovement(); + if (Movement) { - Vehicle4W->Wheels[i]->TireConfig->SetFrictionScale(WheelsFrictionScale[i]); + check(Movement != nullptr); + check(Movement->Wheels.Num() == WheelsFrictionScale.Num()); + + for (int32 i = 0; i < Movement->Wheels.Num(); ++i) + { + Movement->Wheels[i]->TireConfig->SetFrictionScale(WheelsFrictionScale[i]); + } } } + + FVehiclePhysicsControl ACarlaWheeledVehicle::GetVehiclePhysicsControl() const { - UWheeledVehicleMovementComponent4W *Vehicle4W = Cast( - GetVehicleMovement()); - check(Vehicle4W != nullptr); - FVehiclePhysicsControl PhysicsControl; - // Engine Setup - PhysicsControl.TorqueCurve = Vehicle4W->EngineSetup.TorqueCurve.EditorCurveData; - PhysicsControl.MaxRPM = Vehicle4W->EngineSetup.MaxRPM; - PhysicsControl.MOI = Vehicle4W->EngineSetup.MOI; - PhysicsControl.DampingRateFullThrottle = Vehicle4W->EngineSetup.DampingRateFullThrottle; - PhysicsControl.DampingRateZeroThrottleClutchEngaged = - Vehicle4W->EngineSetup.DampingRateZeroThrottleClutchEngaged; - PhysicsControl.DampingRateZeroThrottleClutchDisengaged = - Vehicle4W->EngineSetup.DampingRateZeroThrottleClutchDisengaged; + if (!bIsSixWVehicle) { + UWheeledVehicleMovementComponent4W *Vehicle4W = Cast( + GetVehicleMovement()); + check(Vehicle4W != nullptr); - // Transmission Setup - PhysicsControl.bUseGearAutoBox = Vehicle4W->TransmissionSetup.bUseGearAutoBox; - PhysicsControl.GearSwitchTime = Vehicle4W->TransmissionSetup.GearSwitchTime; - PhysicsControl.ClutchStrength = Vehicle4W->TransmissionSetup.ClutchStrength; - PhysicsControl.FinalRatio = Vehicle4W->TransmissionSetup.FinalRatio; + // Engine Setup + PhysicsControl.TorqueCurve = Vehicle4W->EngineSetup.TorqueCurve.EditorCurveData; + PhysicsControl.MaxRPM = Vehicle4W->EngineSetup.MaxRPM; + PhysicsControl.MOI = Vehicle4W->EngineSetup.MOI; + PhysicsControl.DampingRateFullThrottle = Vehicle4W->EngineSetup.DampingRateFullThrottle; + PhysicsControl.DampingRateZeroThrottleClutchEngaged = + Vehicle4W->EngineSetup.DampingRateZeroThrottleClutchEngaged; + PhysicsControl.DampingRateZeroThrottleClutchDisengaged = + Vehicle4W->EngineSetup.DampingRateZeroThrottleClutchDisengaged; - TArray ForwardGears; + // Transmission Setup + PhysicsControl.bUseGearAutoBox = Vehicle4W->TransmissionSetup.bUseGearAutoBox; + PhysicsControl.GearSwitchTime = Vehicle4W->TransmissionSetup.GearSwitchTime; + PhysicsControl.ClutchStrength = Vehicle4W->TransmissionSetup.ClutchStrength; + PhysicsControl.FinalRatio = Vehicle4W->TransmissionSetup.FinalRatio; - for (const auto &Gear : Vehicle4W->TransmissionSetup.ForwardGears) - { - FGearPhysicsControl GearPhysicsControl; + TArray ForwardGears; - GearPhysicsControl.Ratio = Gear.Ratio; - GearPhysicsControl.UpRatio = Gear.UpRatio; - GearPhysicsControl.DownRatio = Gear.DownRatio; + for (const auto &Gear : Vehicle4W->TransmissionSetup.ForwardGears) + { + FGearPhysicsControl GearPhysicsControl; + + GearPhysicsControl.Ratio = Gear.Ratio; + GearPhysicsControl.UpRatio = Gear.UpRatio; + GearPhysicsControl.DownRatio = Gear.DownRatio; + + ForwardGears.Add(GearPhysicsControl); + } + + PhysicsControl.ForwardGears = ForwardGears; + + // Vehicle Setup + PhysicsControl.Mass = Vehicle4W->Mass; + PhysicsControl.DragCoefficient = Vehicle4W->DragCoefficient; + + // Center of mass offset (Center of mass is always zero vector in local + // position) + UPrimitiveComponent *UpdatedPrimitive = Cast(Vehicle4W->UpdatedComponent); + check(UpdatedPrimitive != nullptr); + + PhysicsControl.CenterOfMass = UpdatedPrimitive->BodyInstance.COMNudge; + + // Transmission Setup + PhysicsControl.SteeringCurve = Vehicle4W->SteeringCurve.EditorCurveData; + + // Wheels Setup + TArray Wheels; + + for (int32 i = 0; i < Vehicle4W->WheelSetups.Num(); ++i) + { + FWheelPhysicsControl PhysicsWheel; + + PxVehicleWheelData PWheelData = Vehicle4W->PVehicle->mWheelsSimData.getWheelData(i); + PhysicsWheel.DampingRate = Cm2ToM2(PWheelData.mDampingRate); + PhysicsWheel.MaxSteerAngle = FMath::RadiansToDegrees(PWheelData.mMaxSteer); + PhysicsWheel.Radius = PWheelData.mRadius; + PhysicsWheel.MaxBrakeTorque = Cm2ToM2(PWheelData.mMaxBrakeTorque); + PhysicsWheel.MaxHandBrakeTorque = Cm2ToM2(PWheelData.mMaxHandBrakeTorque); + + PxVehicleTireData PTireData = Vehicle4W->PVehicle->mWheelsSimData.getTireData(i); + PhysicsWheel.LatStiffMaxLoad = PTireData.mLatStiffX; + PhysicsWheel.LatStiffValue = PTireData.mLatStiffY; + PhysicsWheel.LongStiffValue = PTireData.mLongitudinalStiffnessPerUnitGravity; + + PhysicsWheel.TireFriction = Vehicle4W->Wheels[i]->TireConfig->GetFrictionScale(); + PhysicsWheel.Position = Vehicle4W->Wheels[i]->Location; + + Wheels.Add(PhysicsWheel); + } + + PhysicsControl.Wheels = Wheels; + + } else { + UWheeledVehicleMovementComponentNW *VehicleNW = Cast( + GetVehicleMovement()); + + check(VehicleNW != nullptr); + + // Engine Setup + PhysicsControl.TorqueCurve = VehicleNW->EngineSetup.TorqueCurve.EditorCurveData; + PhysicsControl.MaxRPM = VehicleNW->EngineSetup.MaxRPM; + PhysicsControl.MOI = VehicleNW->EngineSetup.MOI; + PhysicsControl.DampingRateFullThrottle = VehicleNW->EngineSetup.DampingRateFullThrottle; + PhysicsControl.DampingRateZeroThrottleClutchEngaged = + VehicleNW->EngineSetup.DampingRateZeroThrottleClutchEngaged; + PhysicsControl.DampingRateZeroThrottleClutchDisengaged = + VehicleNW->EngineSetup.DampingRateZeroThrottleClutchDisengaged; + + // Transmission Setup + PhysicsControl.bUseGearAutoBox = VehicleNW->TransmissionSetup.bUseGearAutoBox; + PhysicsControl.GearSwitchTime = VehicleNW->TransmissionSetup.GearSwitchTime; + PhysicsControl.ClutchStrength = VehicleNW->TransmissionSetup.ClutchStrength; + PhysicsControl.FinalRatio = VehicleNW->TransmissionSetup.FinalRatio; + + TArray ForwardGears; + + for (const auto &Gear : VehicleNW->TransmissionSetup.ForwardGears) + { + FGearPhysicsControl GearPhysicsControl; + + GearPhysicsControl.Ratio = Gear.Ratio; + GearPhysicsControl.UpRatio = Gear.UpRatio; + GearPhysicsControl.DownRatio = Gear.DownRatio; + + ForwardGears.Add(GearPhysicsControl); + } + + PhysicsControl.ForwardGears = ForwardGears; + + // VehicleNW Setup + PhysicsControl.Mass = VehicleNW->Mass; + PhysicsControl.DragCoefficient = VehicleNW->DragCoefficient; + + // Center of mass offset (Center of mass is always zero vector in local + // position) + UPrimitiveComponent *UpdatedPrimitive = Cast(VehicleNW->UpdatedComponent); + check(UpdatedPrimitive != nullptr); + + PhysicsControl.CenterOfMass = UpdatedPrimitive->BodyInstance.COMNudge; + + // Transmission Setup + PhysicsControl.SteeringCurve = VehicleNW->SteeringCurve.EditorCurveData; + + // Wheels Setup + TArray Wheels; + + for (int32 i = 0; i < VehicleNW->WheelSetups.Num(); ++i) + { + FWheelPhysicsControl PhysicsWheel; + + PxVehicleWheelData PWheelData = VehicleNW->PVehicle->mWheelsSimData.getWheelData(i); + PhysicsWheel.DampingRate = Cm2ToM2(PWheelData.mDampingRate); + PhysicsWheel.MaxSteerAngle = FMath::RadiansToDegrees(PWheelData.mMaxSteer); + PhysicsWheel.Radius = PWheelData.mRadius; + PhysicsWheel.MaxBrakeTorque = Cm2ToM2(PWheelData.mMaxBrakeTorque); + PhysicsWheel.MaxHandBrakeTorque = Cm2ToM2(PWheelData.mMaxHandBrakeTorque); + + PxVehicleTireData PTireData = VehicleNW->PVehicle->mWheelsSimData.getTireData(i); + PhysicsWheel.LatStiffMaxLoad = PTireData.mLatStiffX; + PhysicsWheel.LatStiffValue = PTireData.mLatStiffY; + PhysicsWheel.LongStiffValue = PTireData.mLongitudinalStiffnessPerUnitGravity; + + PhysicsWheel.TireFriction = VehicleNW->Wheels[i]->TireConfig->GetFrictionScale(); + PhysicsWheel.Position = VehicleNW->Wheels[i]->Location; + + Wheels.Add(PhysicsWheel); + } + + PhysicsControl.Wheels = Wheels; - ForwardGears.Add(GearPhysicsControl); } - - PhysicsControl.ForwardGears = ForwardGears; - - // Vehicle Setup - PhysicsControl.Mass = Vehicle4W->Mass; - PhysicsControl.DragCoefficient = Vehicle4W->DragCoefficient; - - // Center of mass offset (Center of mass is always zero vector in local - // position) - UPrimitiveComponent *UpdatedPrimitive = Cast(Vehicle4W->UpdatedComponent); - check(UpdatedPrimitive != nullptr); - - PhysicsControl.CenterOfMass = UpdatedPrimitive->BodyInstance.COMNudge; - - // Transmission Setup - PhysicsControl.SteeringCurve = Vehicle4W->SteeringCurve.EditorCurveData; - - // Wheels Setup - TArray Wheels; - - for (int32 i = 0; i < Vehicle4W->WheelSetups.Num(); ++i) - { - FWheelPhysicsControl PhysicsWheel; - - PxVehicleWheelData PWheelData = Vehicle4W->PVehicle->mWheelsSimData.getWheelData(i); - PhysicsWheel.DampingRate = Cm2ToM2(PWheelData.mDampingRate); - PhysicsWheel.MaxSteerAngle = FMath::RadiansToDegrees(PWheelData.mMaxSteer); - PhysicsWheel.Radius = PWheelData.mRadius; - PhysicsWheel.MaxBrakeTorque = Cm2ToM2(PWheelData.mMaxBrakeTorque); - PhysicsWheel.MaxHandBrakeTorque = Cm2ToM2(PWheelData.mMaxHandBrakeTorque); - - PxVehicleTireData PTireData = Vehicle4W->PVehicle->mWheelsSimData.getTireData(i); - PhysicsWheel.LatStiffMaxLoad = PTireData.mLatStiffX; - PhysicsWheel.LatStiffValue = PTireData.mLatStiffY; - PhysicsWheel.LongStiffValue = PTireData.mLongitudinalStiffnessPerUnitGravity; - - PhysicsWheel.TireFriction = Vehicle4W->Wheels[i]->TireConfig->GetFrictionScale(); - PhysicsWheel.Position = Vehicle4W->Wheels[i]->Location; - - Wheels.Add(PhysicsWheel); - } - - PhysicsControl.Wheels = Wheels; - return PhysicsControl; } @@ -403,109 +513,209 @@ void ACarlaWheeledVehicle::RestoreVehiclePhysicsControl() void ACarlaWheeledVehicle::ApplyVehiclePhysicsControl(const FVehiclePhysicsControl &PhysicsControl) { LastPhysicsControl = PhysicsControl; + if (!bIsSixWVehicle) { + UWheeledVehicleMovementComponent4W *Vehicle4W = Cast( + GetVehicleMovement()); + check(Vehicle4W != nullptr); - UWheeledVehicleMovementComponent4W *Vehicle4W = Cast( - GetVehicleMovement()); - check(Vehicle4W != nullptr); + // Engine Setup + Vehicle4W->EngineSetup.TorqueCurve.EditorCurveData = PhysicsControl.TorqueCurve; + Vehicle4W->EngineSetup.MaxRPM = PhysicsControl.MaxRPM; - // Engine Setup - Vehicle4W->EngineSetup.TorqueCurve.EditorCurveData = PhysicsControl.TorqueCurve; - Vehicle4W->EngineSetup.MaxRPM = PhysicsControl.MaxRPM; + Vehicle4W->EngineSetup.MOI = PhysicsControl.MOI; - Vehicle4W->EngineSetup.MOI = PhysicsControl.MOI; + Vehicle4W->EngineSetup.DampingRateFullThrottle = PhysicsControl.DampingRateFullThrottle; + Vehicle4W->EngineSetup.DampingRateZeroThrottleClutchEngaged = + PhysicsControl.DampingRateZeroThrottleClutchEngaged; + Vehicle4W->EngineSetup.DampingRateZeroThrottleClutchDisengaged = + PhysicsControl.DampingRateZeroThrottleClutchDisengaged; - Vehicle4W->EngineSetup.DampingRateFullThrottle = PhysicsControl.DampingRateFullThrottle; - Vehicle4W->EngineSetup.DampingRateZeroThrottleClutchEngaged = - PhysicsControl.DampingRateZeroThrottleClutchEngaged; - Vehicle4W->EngineSetup.DampingRateZeroThrottleClutchDisengaged = - PhysicsControl.DampingRateZeroThrottleClutchDisengaged; + // Transmission Setup + Vehicle4W->TransmissionSetup.bUseGearAutoBox = PhysicsControl.bUseGearAutoBox; + Vehicle4W->TransmissionSetup.GearSwitchTime = PhysicsControl.GearSwitchTime; + Vehicle4W->TransmissionSetup.ClutchStrength = PhysicsControl.ClutchStrength; + Vehicle4W->TransmissionSetup.FinalRatio = PhysicsControl.FinalRatio; - // Transmission Setup - Vehicle4W->TransmissionSetup.bUseGearAutoBox = PhysicsControl.bUseGearAutoBox; - Vehicle4W->TransmissionSetup.GearSwitchTime = PhysicsControl.GearSwitchTime; - Vehicle4W->TransmissionSetup.ClutchStrength = PhysicsControl.ClutchStrength; - Vehicle4W->TransmissionSetup.FinalRatio = PhysicsControl.FinalRatio; + TArray ForwardGears; - TArray ForwardGears; + for (const auto &Gear : PhysicsControl.ForwardGears) + { + FVehicleGearData GearData; - for (const auto &Gear : PhysicsControl.ForwardGears) - { - FVehicleGearData GearData; + GearData.Ratio = Gear.Ratio; + GearData.UpRatio = Gear.UpRatio; + GearData.DownRatio = Gear.DownRatio; - GearData.Ratio = Gear.Ratio; - GearData.UpRatio = Gear.UpRatio; - GearData.DownRatio = Gear.DownRatio; + ForwardGears.Add(GearData); + } + + Vehicle4W->TransmissionSetup.ForwardGears = ForwardGears; + + // Vehicle Setup + Vehicle4W->Mass = PhysicsControl.Mass; + Vehicle4W->DragCoefficient = PhysicsControl.DragCoefficient; + + // Center of mass + UPrimitiveComponent *UpdatedPrimitive = Cast(Vehicle4W->UpdatedComponent); + check(UpdatedPrimitive != nullptr); + + UpdatedPrimitive->BodyInstance.COMNudge = PhysicsControl.CenterOfMass; + + // Transmission Setup + Vehicle4W->SteeringCurve.EditorCurveData = PhysicsControl.SteeringCurve; + + // Wheels Setup + const int PhysicsWheelsNum = PhysicsControl.Wheels.Num(); + if (PhysicsWheelsNum != 4) + { + UE_LOG(LogCarla, Error, TEXT("Number of WheelPhysicsControl is not 4.")); + return; + } + + // Change, if required, the collision mode for wheels + SetWheelCollision(Vehicle4W, PhysicsControl); + + TArray NewWheelSetups = Vehicle4W->WheelSetups; + + for (int32 i = 0; i < PhysicsWheelsNum; ++i) + { + UVehicleWheel *Wheel = NewWheelSetups[i].WheelClass.GetDefaultObject(); + check(Wheel != nullptr); + + // Assigning new tire config + Wheel->TireConfig = DuplicateObject(Wheel->TireConfig, nullptr); + + // Setting a new value to friction + Wheel->TireConfig->SetFrictionScale(PhysicsControl.Wheels[i].TireFriction); + } + + Vehicle4W->WheelSetups = NewWheelSetups; + + // Recreate Physics State for vehicle setup + GetWorld()->GetPhysicsScene()->GetPxScene()->lockWrite(); + Vehicle4W->RecreatePhysicsState(); + GetWorld()->GetPhysicsScene()->GetPxScene()->unlockWrite(); + + for (int32 i = 0; i < PhysicsWheelsNum; ++i) + { + PxVehicleWheelData PWheelData = Vehicle4W->PVehicle->mWheelsSimData.getWheelData(i); + + PWheelData.mRadius = PhysicsControl.Wheels[i].Radius; + PWheelData.mMaxSteer = FMath::DegreesToRadians(PhysicsControl.Wheels[i].MaxSteerAngle); + PWheelData.mDampingRate = M2ToCm2(PhysicsControl.Wheels[i].DampingRate); + PWheelData.mMaxBrakeTorque = M2ToCm2(PhysicsControl.Wheels[i].MaxBrakeTorque); + PWheelData.mMaxHandBrakeTorque = M2ToCm2(PhysicsControl.Wheels[i].MaxHandBrakeTorque); + Vehicle4W->PVehicle->mWheelsSimData.setWheelData(i, PWheelData); + + PxVehicleTireData PTireData = Vehicle4W->PVehicle->mWheelsSimData.getTireData(i); + PTireData.mLatStiffX = PhysicsControl.Wheels[i].LatStiffMaxLoad; + PTireData.mLatStiffY = PhysicsControl.Wheels[i].LatStiffValue; + PTireData.mLongitudinalStiffnessPerUnitGravity = PhysicsControl.Wheels[i].LongStiffValue; + Vehicle4W->PVehicle->mWheelsSimData.setTireData(i, PTireData); + } + + ResetConstraints(); + } else { + UWheeledVehicleMovementComponentNW *VehicleNW = Cast( + GetVehicleMovement()); + + check(VehicleNW != nullptr); + + // Engine Setup + VehicleNW->EngineSetup.TorqueCurve.EditorCurveData = PhysicsControl.TorqueCurve; + VehicleNW->EngineSetup.MaxRPM = PhysicsControl.MaxRPM; + + VehicleNW->EngineSetup.MOI = PhysicsControl.MOI; + + VehicleNW->EngineSetup.DampingRateFullThrottle = PhysicsControl.DampingRateFullThrottle; + VehicleNW->EngineSetup.DampingRateZeroThrottleClutchEngaged = + PhysicsControl.DampingRateZeroThrottleClutchEngaged; + VehicleNW->EngineSetup.DampingRateZeroThrottleClutchDisengaged = + PhysicsControl.DampingRateZeroThrottleClutchDisengaged; + + // Transmission Setup + VehicleNW->TransmissionSetup.bUseGearAutoBox = PhysicsControl.bUseGearAutoBox; + VehicleNW->TransmissionSetup.GearSwitchTime = PhysicsControl.GearSwitchTime; + VehicleNW->TransmissionSetup.ClutchStrength = PhysicsControl.ClutchStrength; + VehicleNW->TransmissionSetup.FinalRatio = PhysicsControl.FinalRatio; + + TArray ForwardGears; + + for (const auto &Gear : PhysicsControl.ForwardGears) + { + FVehicleNWGearData GearData; + + GearData.Ratio = Gear.Ratio; + GearData.UpRatio = Gear.UpRatio; + GearData.DownRatio = Gear.DownRatio; + + ForwardGears.Add(GearData); + } + + VehicleNW->TransmissionSetup.ForwardGears = ForwardGears; + + // VehicleNW Setup + VehicleNW->Mass = PhysicsControl.Mass; + VehicleNW->DragCoefficient = PhysicsControl.DragCoefficient; + + // Center of mass + UPrimitiveComponent *UpdatedPrimitive = Cast(VehicleNW->UpdatedComponent); + check(UpdatedPrimitive != nullptr); + + UpdatedPrimitive->BodyInstance.COMNudge = PhysicsControl.CenterOfMass; + + // Transmission Setup + VehicleNW->SteeringCurve.EditorCurveData = PhysicsControl.SteeringCurve; + + // Wheels Setup + const int PhysicsWheelsNum = PhysicsControl.Wheels.Num(); + + // Change, if required, the collision mode for wheels + SetWheelCollisionNW(VehicleNW, PhysicsControl); + + TArray NewWheelSetups = VehicleNW->WheelSetups; + + for (int32 i = 0; i < PhysicsWheelsNum; ++i) + { + UVehicleWheel *Wheel = NewWheelSetups[i].WheelClass.GetDefaultObject(); + check(Wheel != nullptr); + + // Assigning new tire config + Wheel->TireConfig = DuplicateObject(Wheel->TireConfig, nullptr); + + // Setting a new value to friction + Wheel->TireConfig->SetFrictionScale(PhysicsControl.Wheels[i].TireFriction); + } + + VehicleNW->WheelSetups = NewWheelSetups; + + // Recreate Physics State for vehicle setup + GetWorld()->GetPhysicsScene()->GetPxScene()->lockWrite(); + VehicleNW->RecreatePhysicsState(); + GetWorld()->GetPhysicsScene()->GetPxScene()->unlockWrite(); + + for (int32 i = 0; i < PhysicsWheelsNum; ++i) + { + PxVehicleWheelData PWheelData = VehicleNW->PVehicle->mWheelsSimData.getWheelData(i); + + PWheelData.mRadius = PhysicsControl.Wheels[i].Radius; + PWheelData.mMaxSteer = FMath::DegreesToRadians(PhysicsControl.Wheels[i].MaxSteerAngle); + PWheelData.mDampingRate = M2ToCm2(PhysicsControl.Wheels[i].DampingRate); + PWheelData.mMaxBrakeTorque = M2ToCm2(PhysicsControl.Wheels[i].MaxBrakeTorque); + PWheelData.mMaxHandBrakeTorque = M2ToCm2(PhysicsControl.Wheels[i].MaxHandBrakeTorque); + VehicleNW->PVehicle->mWheelsSimData.setWheelData(i, PWheelData); + + PxVehicleTireData PTireData = VehicleNW->PVehicle->mWheelsSimData.getTireData(i); + PTireData.mLatStiffX = PhysicsControl.Wheels[i].LatStiffMaxLoad; + PTireData.mLatStiffY = PhysicsControl.Wheels[i].LatStiffValue; + PTireData.mLongitudinalStiffnessPerUnitGravity = PhysicsControl.Wheels[i].LongStiffValue; + VehicleNW->PVehicle->mWheelsSimData.setTireData(i, PTireData); + } + + ResetConstraints(); - ForwardGears.Add(GearData); } - Vehicle4W->TransmissionSetup.ForwardGears = ForwardGears; - - // Vehicle Setup - Vehicle4W->Mass = PhysicsControl.Mass; - Vehicle4W->DragCoefficient = PhysicsControl.DragCoefficient; - - // Center of mass - UPrimitiveComponent *UpdatedPrimitive = Cast(Vehicle4W->UpdatedComponent); - check(UpdatedPrimitive != nullptr); - - UpdatedPrimitive->BodyInstance.COMNudge = PhysicsControl.CenterOfMass; - - // Transmission Setup - Vehicle4W->SteeringCurve.EditorCurveData = PhysicsControl.SteeringCurve; - - // Wheels Setup - const int PhysicsWheelsNum = PhysicsControl.Wheels.Num(); - if (PhysicsWheelsNum != 4) - { - UE_LOG(LogCarla, Error, TEXT("Number of WheelPhysicsControl is not 4.")); - return; - } - - // Change, if required, the collision mode for wheels - SetWheelCollision(Vehicle4W, PhysicsControl); - - TArray NewWheelSetups = Vehicle4W->WheelSetups; - - for (int32 i = 0; i < PhysicsWheelsNum; ++i) - { - UVehicleWheel *Wheel = NewWheelSetups[i].WheelClass.GetDefaultObject(); - check(Wheel != nullptr); - - // Assigning new tire config - Wheel->TireConfig = DuplicateObject(Wheel->TireConfig, nullptr); - - // Setting a new value to friction - Wheel->TireConfig->SetFrictionScale(PhysicsControl.Wheels[i].TireFriction); - } - - Vehicle4W->WheelSetups = NewWheelSetups; - - // Recreate Physics State for vehicle setup - GetWorld()->GetPhysicsScene()->GetPxScene()->lockWrite(); - Vehicle4W->RecreatePhysicsState(); - GetWorld()->GetPhysicsScene()->GetPxScene()->unlockWrite(); - - for (int32 i = 0; i < PhysicsWheelsNum; ++i) - { - PxVehicleWheelData PWheelData = Vehicle4W->PVehicle->mWheelsSimData.getWheelData(i); - - PWheelData.mRadius = PhysicsControl.Wheels[i].Radius; - PWheelData.mMaxSteer = FMath::DegreesToRadians(PhysicsControl.Wheels[i].MaxSteerAngle); - PWheelData.mDampingRate = M2ToCm2(PhysicsControl.Wheels[i].DampingRate); - PWheelData.mMaxBrakeTorque = M2ToCm2(PhysicsControl.Wheels[i].MaxBrakeTorque); - PWheelData.mMaxHandBrakeTorque = M2ToCm2(PhysicsControl.Wheels[i].MaxHandBrakeTorque); - Vehicle4W->PVehicle->mWheelsSimData.setWheelData(i, PWheelData); - - PxVehicleTireData PTireData = Vehicle4W->PVehicle->mWheelsSimData.getTireData(i); - PTireData.mLatStiffX = PhysicsControl.Wheels[i].LatStiffMaxLoad; - PTireData.mLatStiffY = PhysicsControl.Wheels[i].LatStiffValue; - PTireData.mLongitudinalStiffnessPerUnitGravity = PhysicsControl.Wheels[i].LongStiffValue; - Vehicle4W->PVehicle->mWheelsSimData.setTireData(i, PTireData); - } - - ResetConstraints(); - auto * Recorder = UCarlaStatics::GetRecorder(GetWorld()); if (Recorder && Recorder->IsEnabled()) { @@ -568,7 +778,6 @@ void ACarlaWheeledVehicle::SetWheelSteerDirection(EVehicleWheelLocation WheelLoc if (bPhysicsEnabled == false) { check((uint8)WheelLocation >= 0) - check((uint8)WheelLocation < 4) UVehicleAnimInstance *VehicleAnim = Cast(GetMesh()->GetAnimInstance()); check(VehicleAnim != nullptr) VehicleAnim->SetWheelRotYaw((uint8)WheelLocation, AngleInDeg); @@ -582,7 +791,6 @@ void ACarlaWheeledVehicle::SetWheelSteerDirection(EVehicleWheelLocation WheelLoc float ACarlaWheeledVehicle::GetWheelSteerAngle(EVehicleWheelLocation WheelLocation) { check((uint8)WheelLocation >= 0) - check((uint8)WheelLocation < 4) UVehicleAnimInstance *VehicleAnim = Cast(GetMesh()->GetAnimInstance()); check(VehicleAnim != nullptr) check(VehicleAnim->GetWheeledVehicleMovementComponent() != nullptr) @@ -603,37 +811,39 @@ void ACarlaWheeledVehicle::SetSimulatePhysics(bool enabled) { return; } - UWheeledVehicleMovementComponent4W *Vehicle4W = Cast( - GetVehicleMovement()); - check(Vehicle4W != nullptr); - - if(bPhysicsEnabled == enabled) - return; - - SetActorEnableCollision(true); - auto RootComponent = Cast(GetRootComponent()); - RootComponent->SetSimulatePhysics(enabled); - RootComponent->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics); - - UVehicleAnimInstance *VehicleAnim = Cast(GetMesh()->GetAnimInstance()); - check(VehicleAnim != nullptr) - - GetWorld()->GetPhysicsScene()->GetPxScene()->lockWrite(); - if (enabled) + UWheeledVehicleMovementComponent* Movement = GetVehicleMovement(); + if (Movement) { - Vehicle4W->RecreatePhysicsState(); - VehicleAnim->ResetWheelCustomRotations(); + check(Movement != nullptr); + + if(bPhysicsEnabled == enabled) + return; + + SetActorEnableCollision(true); + auto RootComponent = Cast(GetRootComponent()); + RootComponent->SetSimulatePhysics(enabled); + RootComponent->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics); + + UVehicleAnimInstance *VehicleAnim = Cast(GetMesh()->GetAnimInstance()); + check(VehicleAnim != nullptr) + + GetWorld()->GetPhysicsScene()->GetPxScene()->lockWrite(); + if (enabled) + { + Movement->RecreatePhysicsState(); + VehicleAnim->ResetWheelCustomRotations(); + } + else + { + Movement->DestroyPhysicsState(); + } + + GetWorld()->GetPhysicsScene()->GetPxScene()->unlockWrite(); + + bPhysicsEnabled = enabled; + + ResetConstraints(); } - else - { - Vehicle4W->DestroyPhysicsState(); - } - - GetWorld()->GetPhysicsScene()->GetPxScene()->unlockWrite(); - - bPhysicsEnabled = enabled; - - ResetConstraints(); } diff --git a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Vehicle/CarlaWheeledVehicle.h b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Vehicle/CarlaWheeledVehicle.h index b72e42e8d..9baaa80ee 100644 --- a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Vehicle/CarlaWheeledVehicle.h +++ b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Vehicle/CarlaWheeledVehicle.h @@ -15,6 +15,7 @@ #include "Vehicle/VehiclePhysicsControl.h" #include "VehicleVelocityControl.h" #include "WheeledVehicleMovementComponent4W.h" +#include "WheeledVehicleMovementComponentNW.h" #include "VehicleAnimInstance.h" #include "PhysicsEngine/PhysicsConstraintComponent.h" #include "MovementComponents/BaseCarlaMovementComponent.h" @@ -160,6 +161,8 @@ public: void SetWheelCollision(UWheeledVehicleMovementComponent4W *Vehicle4W, const FVehiclePhysicsControl &PhysicsControl); + void SetWheelCollisionNW(UWheeledVehicleMovementComponentNW *VehicleNW, const FVehiclePhysicsControl &PhysicsControl); + void SetVehicleLightState(const FVehicleLightState &LightState); UFUNCTION(BlueprintNativeEvent) @@ -328,6 +331,9 @@ public: float CarSimOriginOffset = 150.f; //------------------------------------------- + UPROPERTY(Category="CARLA Wheeled Vehicle", EditAnywhere) + bool bIsSixWVehicle = false; + private: UPROPERTY(Category="CARLA Wheeled Vehicle", VisibleAnywhere) diff --git a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Vehicle/CarlaWheeledVehicleNW.cpp b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Vehicle/CarlaWheeledVehicleNW.cpp new file mode 100644 index 000000000..783393569 --- /dev/null +++ b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Vehicle/CarlaWheeledVehicleNW.cpp @@ -0,0 +1,15 @@ +// Copyright (c) 2022 Computer Vision Center (CVC) at the Universitat Autonoma +// de Barcelona (UAB). +// Copyright (c) 2019 Intel Corporation +// +// This work is licensed under the terms of the MIT license. +// For a copy, see . + +#include "CarlaWheeledVehicleNW.h" +#include "WheeledVehicleMovementComponentNW.h" + +ACarlaWheeledVehicleNW::ACarlaWheeledVehicleNW(const FObjectInitializer& ObjectInitializer) : + Super(ObjectInitializer.SetDefaultSubobjectClass(AWheeledVehicle::VehicleMovementComponentName)) +{} + +ACarlaWheeledVehicleNW::~ACarlaWheeledVehicleNW() {} diff --git a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Vehicle/CarlaWheeledVehicleNW.h b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Vehicle/CarlaWheeledVehicleNW.h new file mode 100644 index 000000000..4e004ac29 --- /dev/null +++ b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Vehicle/CarlaWheeledVehicleNW.h @@ -0,0 +1,28 @@ +// Copyright (c) 2022 Computer Vision Center (CVC) at the Universitat Autonoma +// de Barcelona (UAB). +// +// This work is licensed under the terms of the MIT license. +// For a copy, see . + +#pragma once + +#include "CarlaWheeledVehicle.h" + +#include "CarlaWheeledVehicleNW.generated.h" + +/// Base class for CARLA wheeled vehicles. +UCLASS() +class CARLA_API ACarlaWheeledVehicleNW : public ACarlaWheeledVehicle +{ + GENERATED_BODY() + + // =========================================================================== + /// @name Constructor and destructor + // =========================================================================== + /// @{ +public: + + ACarlaWheeledVehicleNW(const FObjectInitializer &ObjectInitializer); + + ~ACarlaWheeledVehicleNW(); +}; diff --git a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Vehicle/WheeledVehicleMovementComponentNW.cpp b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Vehicle/WheeledVehicleMovementComponentNW.cpp new file mode 100644 index 000000000..347d0cc1c --- /dev/null +++ b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Vehicle/WheeledVehicleMovementComponentNW.cpp @@ -0,0 +1,404 @@ +#include "WheeledVehicleMovementComponentNW.h" +#include "PhysicsPublic.h" +#include "PhysXPublic.h" +#include "PhysXVehicleManager.h" +#include "Components/PrimitiveComponent.h" +#include "Logging/MessageLog.h" + +UWheeledVehicleMovementComponentNW::UWheeledVehicleMovementComponentNW(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) +{ + // grab default values from physx + PxVehicleEngineData DefEngineData; + EngineSetup.MOI = DefEngineData.mMOI; + EngineSetup.MaxRPM = OmegaToRPM(DefEngineData.mMaxOmega); + EngineSetup.DampingRateFullThrottle = DefEngineData.mDampingRateFullThrottle; + EngineSetup.DampingRateZeroThrottleClutchEngaged = DefEngineData.mDampingRateZeroThrottleClutchEngaged; + EngineSetup.DampingRateZeroThrottleClutchDisengaged = DefEngineData.mDampingRateZeroThrottleClutchDisengaged; + + // Convert from PhysX curve to ours + FRichCurve* TorqueCurveData = EngineSetup.TorqueCurve.GetRichCurve(); + for (PxU32 KeyIdx = 0; KeyIdx < DefEngineData.mTorqueCurve.getNbDataPairs(); ++KeyIdx) + { + float Input = DefEngineData.mTorqueCurve.getX(KeyIdx) * EngineSetup.MaxRPM; + float Output = DefEngineData.mTorqueCurve.getY(KeyIdx) * DefEngineData.mPeakTorque; + TorqueCurveData->AddKey(Input, Output); + } + + PxVehicleClutchData DefClutchData; + TransmissionSetup.ClutchStrength = DefClutchData.mStrength; + + PxVehicleGearsData DefGearSetup; + TransmissionSetup.GearSwitchTime = DefGearSetup.mSwitchTime; + TransmissionSetup.ReverseGearRatio = DefGearSetup.mRatios[PxVehicleGearsData::eREVERSE]; + TransmissionSetup.FinalRatio = DefGearSetup.mFinalRatio; + + PxVehicleAutoBoxData DefAutoBoxSetup; + TransmissionSetup.NeutralGearUpRatio = DefAutoBoxSetup.mUpRatios[PxVehicleGearsData::eNEUTRAL]; + TransmissionSetup.GearAutoBoxLatency = DefAutoBoxSetup.getLatency(); + TransmissionSetup.bUseGearAutoBox = true; + + for (uint32 i = PxVehicleGearsData::eFIRST; i < DefGearSetup.mNbRatios; ++i) + { + FVehicleNWGearData GearData; + GearData.DownRatio = DefAutoBoxSetup.mDownRatios[i]; + GearData.UpRatio = DefAutoBoxSetup.mUpRatios[i]; + GearData.Ratio = DefGearSetup.mRatios[i]; + TransmissionSetup.ForwardGears.Add(GearData); + } + + // Init steering speed curve + FRichCurve* SteeringCurveData = SteeringCurve.GetRichCurve(); + SteeringCurveData->AddKey(0.0f, 1.0f); + SteeringCurveData->AddKey(20.0f, 0.9f); + SteeringCurveData->AddKey(60.0f, 0.8f); + SteeringCurveData->AddKey(120.0f, 0.7f); + + // Initialize WheelSetups array with 4 wheels, this can be modified via editor later + const int32 NbrWheels = 4; + WheelSetups.SetNum(NbrWheels); + DifferentialSetup.SetNum(NbrWheels); + + IdleBrakeInput = 10; +} + +#if WITH_EDITOR +void UWheeledVehicleMovementComponentNW::PostEditChangeProperty(struct FPropertyChangedEvent& PropertyChangedEvent) +{ + Super::PostEditChangeProperty(PropertyChangedEvent); + const FName PropertyName = PropertyChangedEvent.Property ? PropertyChangedEvent.Property->GetFName() : NAME_None; + + if (PropertyName == TEXT("DownRatio")) + { + for (int32 GearIdx = 0; GearIdx < TransmissionSetup.ForwardGears.Num(); ++GearIdx) + { + FVehicleNWGearData& GearData = TransmissionSetup.ForwardGears[GearIdx]; + GearData.DownRatio = FMath::Min(GearData.DownRatio, GearData.UpRatio); + } + } + else if (PropertyName == TEXT("UpRatio")) + { + for (int32 GearIdx = 0; GearIdx < TransmissionSetup.ForwardGears.Num(); ++GearIdx) + { + FVehicleNWGearData& GearData = TransmissionSetup.ForwardGears[GearIdx]; + GearData.UpRatio = FMath::Max(GearData.DownRatio, GearData.UpRatio); + } + } + else if (PropertyName == TEXT("SteeringCurve")) + { + //make sure values are capped between 0 and 1 + TArray SteerKeys = SteeringCurve.GetRichCurve()->GetCopyOfKeys(); + for (int32 KeyIdx = 0; KeyIdx < SteerKeys.Num(); ++KeyIdx) + { + float NewValue = FMath::Clamp(SteerKeys[KeyIdx].Value, 0.0f, 1.0f); + SteeringCurve.GetRichCurve()->UpdateOrAddKey(SteerKeys[KeyIdx].Time, NewValue); + } + } +} +#endif + +static void GetVehicleDifferentialNWSetup(const TArray& Setup, PxVehicleDifferentialNWData& PxSetup) +{ + for (int32 i = 0; i < Setup.Num(); ++i) + { + PxSetup.setDrivenWheel(i, Setup[i].bDriven); + } +} + +float FVehicleNWEngineData::FindPeakTorque() const +{ + // Find max torque + float PeakTorque = 0.0f; + TArray TorqueKeys = TorqueCurve.GetRichCurveConst()->GetCopyOfKeys(); + for (int32 KeyIdx = 0; KeyIdx < TorqueKeys.Num(); ++KeyIdx) + { + FRichCurveKey& Key = TorqueKeys[KeyIdx]; + PeakTorque = FMath::Max(PeakTorque, Key.Value); + } + return PeakTorque; +} + +static void GetVehicleEngineSetup(const FVehicleNWEngineData& Setup, PxVehicleEngineData& PxSetup) +{ + PxSetup.mMOI = M2ToCm2(Setup.MOI); + PxSetup.mMaxOmega = RPMToOmega(Setup.MaxRPM); + PxSetup.mDampingRateFullThrottle = M2ToCm2(Setup.DampingRateFullThrottle); + PxSetup.mDampingRateZeroThrottleClutchEngaged = M2ToCm2(Setup.DampingRateZeroThrottleClutchEngaged); + PxSetup.mDampingRateZeroThrottleClutchDisengaged = M2ToCm2(Setup.DampingRateZeroThrottleClutchDisengaged); + + float PeakTorque = Setup.FindPeakTorque(); // In Nm + PxSetup.mPeakTorque = M2ToCm2(PeakTorque); // convert Nm to (kg cm^2/s^2) + + // Convert from our curve to PhysX + PxSetup.mTorqueCurve.clear(); + TArray TorqueKeys = Setup.TorqueCurve.GetRichCurveConst()->GetCopyOfKeys(); + int32 NumTorqueCurveKeys = FMath::Min(TorqueKeys.Num(), PxVehicleEngineData::eMAX_NB_ENGINE_TORQUE_CURVE_ENTRIES); + for (int32 KeyIdx = 0; KeyIdx < NumTorqueCurveKeys; ++KeyIdx) + { + FRichCurveKey& Key = TorqueKeys[KeyIdx]; + PxSetup.mTorqueCurve.addPair(FMath::Clamp(Key.Time / Setup.MaxRPM, 0.0f, 1.0f), Key.Value / PeakTorque); // Normalize torque to 0-1 range + } +} + +static void GetVehicleGearSetup(const FVehicleNWTransmissionData& Setup, PxVehicleGearsData& PxSetup) +{ + PxSetup.mSwitchTime = Setup.GearSwitchTime; + PxSetup.mRatios[PxVehicleGearsData::eREVERSE] = Setup.ReverseGearRatio; + for (int32 i = 0; i < Setup.ForwardGears.Num(); i++) + { + PxSetup.mRatios[i + PxVehicleGearsData::eFIRST] = Setup.ForwardGears[i].Ratio; + } + PxSetup.mFinalRatio = Setup.FinalRatio; + PxSetup.mNbRatios = Setup.ForwardGears.Num() + PxVehicleGearsData::eFIRST; +} + +static void GetVehicleAutoBoxSetup(const FVehicleNWTransmissionData& Setup, PxVehicleAutoBoxData& PxSetup) +{ + for (int32 i = 0; i < Setup.ForwardGears.Num(); ++i) + { + const FVehicleNWGearData& GearData = Setup.ForwardGears[i]; + PxSetup.mUpRatios[i + PxVehicleGearsData::eFIRST] = GearData.UpRatio; + PxSetup.mDownRatios[i + PxVehicleGearsData::eFIRST] = GearData.DownRatio; + } + PxSetup.mUpRatios[PxVehicleGearsData::eNEUTRAL] = Setup.NeutralGearUpRatio; + PxSetup.setLatency(Setup.GearAutoBoxLatency); + +} + +int32 UWheeledVehicleMovementComponentNW::GetCustomGearBoxNumForwardGears() const +{ + return TransmissionSetup.ForwardGears.Num(); +} + +void SetupDriveHelper(const UWheeledVehicleMovementComponentNW* VehicleData, const PxVehicleWheelsSimData* PWheelsSimData, PxVehicleDriveSimDataNW& DriveData) +{ + PxVehicleDifferentialNWData DifferentialSetup; + GetVehicleDifferentialNWSetup(VehicleData->DifferentialSetup, DifferentialSetup); + + DriveData.setDiffData(DifferentialSetup); + + PxVehicleEngineData EngineSetup; + GetVehicleEngineSetup(VehicleData->EngineSetup, EngineSetup); + DriveData.setEngineData(EngineSetup); + + PxVehicleClutchData ClutchSetup; + ClutchSetup.mStrength = M2ToCm2(VehicleData->TransmissionSetup.ClutchStrength); + DriveData.setClutchData(ClutchSetup); + + PxVehicleGearsData GearSetup; + GetVehicleGearSetup(VehicleData->TransmissionSetup, GearSetup); + DriveData.setGearsData(GearSetup); + + PxVehicleAutoBoxData AutoBoxSetup; + GetVehicleAutoBoxSetup(VehicleData->TransmissionSetup, AutoBoxSetup); + DriveData.setAutoBoxData(AutoBoxSetup); +} + +void UWheeledVehicleMovementComponentNW::SetupVehicle() +{ + if (!UpdatedPrimitive) + { + return; + } + + if (WheelSetups.Num() < 2) + { + PVehicle = nullptr; + PVehicleDrive = nullptr; + return; + } + + for (int32 WheelIdx = 0; WheelIdx < WheelSetups.Num(); ++WheelIdx) + { + const FWheelSetup& WheelSetup = WheelSetups[WheelIdx]; + if (WheelSetup.BoneName == NAME_None) + { + return; + } + } + + // Setup the chassis and wheel shapes + SetupVehicleShapes(); + + // Setup mass properties + SetupVehicleMass(); + + // Setup the wheels + PxVehicleWheelsSimData* PWheelsSimData = PxVehicleWheelsSimData::allocate(WheelSetups.Num()); + SetupWheels(PWheelsSimData); + + // Setup drive data + PxVehicleDriveSimDataNW DriveData; + SetupDriveHelper(this, PWheelsSimData, DriveData); + + // Create the vehicle + PxVehicleDriveNW* PVehicleDriveNW = PxVehicleDriveNW::allocate(WheelSetups.Num()); + check(PVehicleDriveNW); + + FBodyInstance* TargetInstance = UpdatedPrimitive->GetBodyInstance(); + + FPhysicsCommand::ExecuteWrite(TargetInstance->ActorHandle, [&](const FPhysicsActorHandle& Actor) + { + PxRigidActor* PActor = FPhysicsInterface::GetPxRigidActor_AssumesLocked(Actor); + if (!PActor) + { + return; + } + + if (PxRigidDynamic* PVehicleActor = PActor->is()) + { + PVehicleDriveNW->setup(GPhysXSDK, PVehicleActor, *PWheelsSimData, DriveData, 0); + PVehicleDriveNW->setToRestState(); + + // cleanup + PWheelsSimData->free(); + } + }); + + PWheelsSimData = nullptr; + + // cache values + PVehicle = PVehicleDriveNW; + PVehicleDrive = PVehicleDriveNW; + + SetUseAutoGears(TransmissionSetup.bUseGearAutoBox); + +} + +void UWheeledVehicleMovementComponentNW::UpdateSimulation(float DeltaTime) +{ + if (PVehicleDrive == nullptr) + return; + + FBodyInstance* TargetInstance = UpdatedPrimitive->GetBodyInstance(); + + FPhysicsCommand::ExecuteWrite(TargetInstance->ActorHandle, [&](const FPhysicsActorHandle& Actor) + { + PxVehicleDriveNWRawInputData RawInputData; + RawInputData.setAnalogAccel(ThrottleInput); + RawInputData.setAnalogSteer(SteeringInput); + RawInputData.setAnalogBrake(BrakeInput); + RawInputData.setAnalogHandbrake(HandbrakeInput); + + if (!PVehicleDrive->mDriveDynData.getUseAutoGears()) + { + RawInputData.setGearUp(bRawGearUpInput); + RawInputData.setGearDown(bRawGearDownInput); + } + + // Convert from our curve to PxFixedSizeLookupTable + PxFixedSizeLookupTable<8> SpeedSteerLookup; + TArray SteerKeys = SteeringCurve.GetRichCurve()->GetCopyOfKeys(); + const int32 MaxSteeringSamples = FMath::Min(8, SteerKeys.Num()); + for (int32 KeyIdx = 0; KeyIdx < MaxSteeringSamples; KeyIdx++) + { + FRichCurveKey& Key = SteerKeys[KeyIdx]; + SpeedSteerLookup.addPair(KmHToCmS(Key.Time), FMath::Clamp(Key.Value, 0.0f, 1.0f)); + } + + PxVehiclePadSmoothingData SmoothData = { + { ThrottleInputRate.RiseRate, BrakeInputRate.RiseRate, HandbrakeInputRate.RiseRate, SteeringInputRate.RiseRate, SteeringInputRate.RiseRate }, + { ThrottleInputRate.FallRate, BrakeInputRate.FallRate, HandbrakeInputRate.FallRate, SteeringInputRate.FallRate, SteeringInputRate.FallRate } + }; + + PxVehicleDriveNW* PVehicleDriveNW = (PxVehicleDriveNW*)PVehicleDrive; + PxVehicleDriveNWSmoothAnalogRawInputsAndSetAnalogInputs(SmoothData, SpeedSteerLookup, RawInputData, DeltaTime, false, *PVehicleDriveNW); + }); +} + +void UWheeledVehicleMovementComponentNW::UpdateEngineSetup(const FVehicleNWEngineData& NewEngineSetup) +{ + if (PVehicleDrive) + { + PxVehicleEngineData EngineData; + GetVehicleEngineSetup(NewEngineSetup, EngineData); + + PxVehicleDriveNW* PVehicleDriveNW = (PxVehicleDriveNW*)PVehicleDrive; + PVehicleDriveNW->mDriveSimData.setEngineData(EngineData); + } +} + +void UWheeledVehicleMovementComponentNW::UpdateDifferentialSetup(const TArray& NewDifferentialSetup) +{ + if (PVehicleDrive) + { + PxVehicleDifferentialNWData DifferentialData; + GetVehicleDifferentialNWSetup(NewDifferentialSetup, DifferentialData); + + PxVehicleDriveNW* PVehicleDriveNW = (PxVehicleDriveNW*)PVehicleDrive; + PVehicleDriveNW->mDriveSimData.setDiffData(DifferentialData); + } +} + +void UWheeledVehicleMovementComponentNW::UpdateTransmissionSetup(const FVehicleNWTransmissionData& NewTransmissionSetup) +{ + if (PVehicleDrive) + { + PxVehicleGearsData GearData; + GetVehicleGearSetup(NewTransmissionSetup, GearData); + + PxVehicleAutoBoxData AutoBoxData; + GetVehicleAutoBoxSetup(NewTransmissionSetup, AutoBoxData); + + PxVehicleDriveNW* PVehicleDriveNW = (PxVehicleDriveNW*)PVehicleDrive; + PVehicleDriveNW->mDriveSimData.setGearsData(GearData); + PVehicleDriveNW->mDriveSimData.setAutoBoxData(AutoBoxData); + } +} + +void BackwardsConvertCm2ToM2NW(float& val, float defaultValue) +{ + if (val != defaultValue) + { + val = Cm2ToM2(val); + } +} + +void UWheeledVehicleMovementComponentNW::Serialize(FArchive& Ar) +{ + Super::Serialize(Ar); + if (Ar.IsLoading() && Ar.UE4Ver() < VER_UE4_VEHICLES_UNIT_CHANGE) + { + PxVehicleEngineData DefEngineData; + const float DefaultRPM = OmegaToRPM(DefEngineData.mMaxOmega); + + // 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. + EngineSetup.MaxRPM = EngineSetup.MaxRPM != DefaultRPM ? OmegaToRPM(EngineSetup.MaxRPM) : DefaultRPM; //need to convert from rad/s to RPM + } + + if (Ar.IsLoading() && Ar.UE4Ver() < VER_UE4_VEHICLES_UNIT_CHANGE2) + { + PxVehicleEngineData DefEngineData; + PxVehicleClutchData DefClutchData; + + // 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. + BackwardsConvertCm2ToM2NW(EngineSetup.DampingRateFullThrottle, DefEngineData.mDampingRateFullThrottle); + BackwardsConvertCm2ToM2NW(EngineSetup.DampingRateZeroThrottleClutchDisengaged, DefEngineData.mDampingRateZeroThrottleClutchDisengaged); + BackwardsConvertCm2ToM2NW(EngineSetup.DampingRateZeroThrottleClutchEngaged, DefEngineData.mDampingRateZeroThrottleClutchEngaged); + BackwardsConvertCm2ToM2NW(EngineSetup.MOI, DefEngineData.mMOI); + BackwardsConvertCm2ToM2NW(TransmissionSetup.ClutchStrength, DefClutchData.mStrength); + } +} + +void UWheeledVehicleMovementComponentNW::ComputeConstants() +{ + Super::ComputeConstants(); + MaxEngineRPM = EngineSetup.MaxRPM; +} + +const void* UWheeledVehicleMovementComponentNW::GetTireData(physx::PxVehicleWheels* InWheels, UVehicleWheel* InWheel) +{ + const void* realShaderData = &InWheels->mWheelsSimData.getTireData((PxU32)InWheel->WheelIndex); + return realShaderData; +} + +const int32 UWheeledVehicleMovementComponentNW::GetWheelShapeMapping(physx::PxVehicleWheels* InWheels, uint32 InWheel) +{ + const physx::PxI32 ShapeIndex = InWheels->mWheelsSimData.getWheelShapeMapping((PxU32)InWheel); + return ShapeIndex; +} + +const physx::PxVehicleWheelData UWheeledVehicleMovementComponentNW::GetWheelData(physx::PxVehicleWheels* InWheels, uint32 InWheel) +{ + const physx::PxVehicleWheelData WheelData = InWheels->mWheelsSimData.getWheelData((physx::PxU32)InWheel); + return WheelData; +} diff --git a/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Vehicle/WheeledVehicleMovementComponentNW.h b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Vehicle/WheeledVehicleMovementComponentNW.h new file mode 100644 index 000000000..b583ab441 --- /dev/null +++ b/Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Vehicle/WheeledVehicleMovementComponentNW.h @@ -0,0 +1,161 @@ +#pragma once +#include "WheeledVehicleMovementComponent.h" +#include "Curves/CurveFloat.h" +#include "WheeledVehicleMovementComponentNW.generated.h" + +namespace physx +{ + class PxVehicleWheelData; +} + +USTRUCT() +struct FVehicleNWWheelDifferentialData +{ + GENERATED_USTRUCT_BODY() + + /** If True, torque is applied to this wheel */ + UPROPERTY(EditAnywhere, Category = Setup) + bool bDriven; + + FVehicleNWWheelDifferentialData() + : bDriven(true) + { } +}; + +USTRUCT() +struct FVehicleNWEngineData +{ + GENERATED_USTRUCT_BODY() + + /** Torque (Nm) at a given RPM*/ + UPROPERTY(EditAnywhere, Category = Setup) + FRuntimeFloatCurve TorqueCurve; + + /** Maximum revolutions per minute of the engine */ + UPROPERTY(EditAnywhere, Category = Setup, meta = (ClampMin = "0.01", UIMin = "0.01")) + float MaxRPM; + + /** Moment of inertia of the engine around the axis of rotation (Kgm^2). */ + UPROPERTY(EditAnywhere, Category = Setup, meta = (ClampMin = "0.01", UIMin = "0.01")) + float MOI; + + /** Damping rate of engine when full throttle is applied (Kgm^2/s) */ + UPROPERTY(EditAnywhere, Category = Setup, AdvancedDisplay, meta = (ClampMin = "0.0", UIMin = "0.0")) + float DampingRateFullThrottle; + + /** Damping rate of engine in at zero throttle when the clutch is engaged (Kgm^2/s)*/ + UPROPERTY(EditAnywhere, Category = Setup, AdvancedDisplay, meta = (ClampMin = "0.0", UIMin = "0.0")) + float DampingRateZeroThrottleClutchEngaged; + + /** Damping rate of engine in at zero throttle when the clutch is disengaged (in neutral gear) (Kgm^2/s)*/ + UPROPERTY(EditAnywhere, Category = Setup, AdvancedDisplay, meta = (ClampMin = "0.0", UIMin = "0.0")) + float DampingRateZeroThrottleClutchDisengaged; + + /** Find the peak torque produced by the TorqueCurve */ + float FindPeakTorque() const; +}; + +USTRUCT() +struct FVehicleNWGearData +{ + GENERATED_USTRUCT_BODY() + + /** Determines the amount of torque multiplication*/ + UPROPERTY(EditAnywhere, Category = Setup) + float Ratio; + + /** Value of engineRevs/maxEngineRevs that is low enough to gear down*/ + UPROPERTY(EditAnywhere, meta = (ClampMin = "0.0", UIMin = "0.0", ClampMax = "1.0", UIMax = "1.0"), Category = Setup) + float DownRatio; + + /** Value of engineRevs/maxEngineRevs that is high enough to gear up*/ + UPROPERTY(EditAnywhere, meta = (ClampMin = "0.0", UIMin = "0.0", ClampMax = "1.0", UIMax = "1.0"), Category = Setup) + float UpRatio; +}; + +USTRUCT() +struct FVehicleNWTransmissionData +{ + GENERATED_USTRUCT_BODY() + /** Whether to use automatic transmission */ + UPROPERTY(EditAnywhere, Category = VehicleSetup, meta = (DisplayName = "Automatic Transmission")) + bool bUseGearAutoBox; + + /** Time it takes to switch gears (seconds) */ + UPROPERTY(EditAnywhere, Category = Setup, meta = (ClampMin = "0.0", UIMin = "0.0")) + float GearSwitchTime; + + /** Minimum time it takes the automatic transmission to initiate a gear change (seconds)*/ + UPROPERTY(EditAnywhere, Category = Setup, meta = (editcondition = "bUseGearAutoBox", ClampMin = "0.0", UIMin = "0.0")) + float GearAutoBoxLatency; + + /** The final gear ratio multiplies the transmission gear ratios.*/ + UPROPERTY(EditAnywhere, AdvancedDisplay, Category = Setup) + float FinalRatio; + + /** Forward gear ratios (up to 30) */ + UPROPERTY(EditAnywhere, Category = Setup, AdvancedDisplay) + TArray ForwardGears; + + /** Reverse gear ratio */ + UPROPERTY(EditAnywhere, AdvancedDisplay, Category = Setup) + float ReverseGearRatio; + + /** Value of engineRevs/maxEngineRevs that is high enough to increment gear*/ + UPROPERTY(EditAnywhere, AdvancedDisplay, Category = Setup, meta = (ClampMin = "0.0", UIMin = "0.0", ClampMax = "1.0", UIMax = "1.0")) + float NeutralGearUpRatio; + + /** Strength of clutch (Kgm^2/s)*/ + UPROPERTY(EditAnywhere, Category = Setup, AdvancedDisplay, meta = (ClampMin = "0.0", UIMin = "0.0")) + float ClutchStrength; +}; + +UCLASS(ClassGroup = (Physics), meta = (BlueprintSpawnableComponent), hidecategories = (PlanarMovement, "Components|Movement|Planar", Activation, "Components|Activation")) +class PHYSXVEHICLES_API UWheeledVehicleMovementComponentNW : public UWheeledVehicleMovementComponent +{ + GENERATED_UCLASS_BODY() + + /** Engine */ + UPROPERTY(EditAnywhere, Category = MechanicalSetup) + FVehicleNWEngineData EngineSetup; + + /** Differential */ + UPROPERTY(EditAnywhere, Category = MechanicalSetup) + TArray DifferentialSetup; + + /** Transmission data */ + UPROPERTY(EditAnywhere, Category = MechanicalSetup) + FVehicleNWTransmissionData TransmissionSetup; + + /** Maximum steering versus forward speed (km/h) */ + UPROPERTY(EditAnywhere, Category = SteeringSetup) + FRuntimeFloatCurve SteeringCurve; + + virtual void Serialize(FArchive& Ar) override; + virtual void ComputeConstants() override; +#if WITH_EDITOR + virtual void PostEditChangeProperty(struct FPropertyChangedEvent& PropertyChangedEvent) override; +#endif + +protected: + + virtual const void* GetTireData(physx::PxVehicleWheels* Wheels, UVehicleWheel* Wheel); + virtual const int32 GetWheelShapeMapping(physx::PxVehicleWheels* Wheels, uint32 Wheel); + virtual const physx::PxVehicleWheelData GetWheelData(physx::PxVehicleWheels* Wheels, uint32 Wheel); + + /** Allocate and setup the PhysX vehicle */ + virtual void SetupVehicle() override; + + virtual int32 GetCustomGearBoxNumForwardGears() const; + + virtual void UpdateSimulation(float DeltaTime) override; + + /** update simulation data: engine */ + virtual void UpdateEngineSetup(const FVehicleNWEngineData& NewEngineSetup); + + /** update simulation data: differential */ + virtual void UpdateDifferentialSetup(const TArray& NewDifferentialSetup); + + /** update simulation data: transmission */ + virtual void UpdateTransmissionSetup(const FVehicleNWTransmissionData& NewGearSetup); +};