CARLA
Loading...
Searching...
No Matches
CarlaVehicleAnimationInstance.cpp
Go to the documentation of this file.
1// Copyright (c) 2026 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 "Carla.h"
10
11#include <util/ue-header-guard-begin.h>
12#include "AnimationRuntime.h"
13#include "ChaosWheeledVehicleMovementComponent.h"
14#include <util/ue-header-guard-end.h>
15
16static float RollWheel(float SpinAngle, float Travel, float Radius, float MaxTravel)
17{
18 const bool bHasRadius = Radius > UE_KINDA_SMALL_NUMBER;
19 const bool bTeleported = FMath::Abs(Travel) > MaxTravel;
20 if (!bHasRadius || bTeleported)
21 {
22 return SpinAngle;
23 }
24 return FMath::UnwindDegrees(SpinAngle - FMath::RadiansToDegrees(Travel / Radius));
25}
26
28{
29 Super::NativeUpdateAnimation(DeltaSeconds);
30
31 const ACarlaWheeledVehicle *Vehicle = Cast<ACarlaWheeledVehicle>(GetOwningActor());
32 if (Vehicle == nullptr)
33 {
34 return;
35 }
38 {
39 bRollingWheels = false;
40 // So the first frame of rolling turns the wheels by that frame's travel.
42 return;
43 }
44 if (!bRollingWheels)
45 {
47 bRollingWheels = true;
48 }
49 RollWheels(*Vehicle, DeltaSeconds);
50}
51
53{
54 return GetWheeledVehicleComponent() != nullptr &&
55 !Vehicle.IsSimulatedByChaos() &&
56 !Vehicle.IsWheelAnimationOverridden();
57}
58
60{
61 const UChaosWheeledVehicleMovementComponent *Movement = GetWheeledVehicleComponent();
62 const FTransform MeshTransform = GetSkelMeshComponent()->GetComponentTransform();
63 const USkeletalMesh *SkeletalMesh = GetSkelMeshComponent()->GetSkeletalMeshAsset();
64
65 Wheels.Init(FWheel(), Movement->WheelSetups.Num());
66 for (int32 i = 0; i < Wheels.Num(); ++i)
67 {
68 FWheel &Wheel = Wheels[i];
69 if (SkeletalMesh != nullptr)
70 {
71 const FReferenceSkeleton &RefSkeleton = SkeletalMesh->GetRefSkeleton();
72 const int32 BoneIndex = RefSkeleton.FindBoneIndex(Movement->WheelSetups[i].BoneName);
73 if (BoneIndex != INDEX_NONE)
74 {
75 Wheel.RestLocation =
76 FAnimationRuntime::GetComponentSpaceTransformRefPose(RefSkeleton, BoneIndex).GetLocation();
77 }
78 }
79 Wheel.LastLocation = MeshTransform.TransformPosition(Wheel.RestLocation);
80 }
81}
82
84{
85 const UChaosWheeledVehicleMovementComponent *Movement = GetWheeledVehicleComponent();
86 if (Movement == nullptr)
87 {
88 return;
89 }
90 if (Wheels.Num() != Movement->WheelSetups.Num())
91 {
92 InitWheels();
93 return;
94 }
95 const FTransform MeshTransform = GetSkelMeshComponent()->GetComponentTransform();
96 for (FWheel &Wheel : Wheels)
97 {
98 Wheel.LastLocation = MeshTransform.TransformPosition(Wheel.RestLocation);
99 }
100}
101
103{
104 if (Wheels.Num() != GetWheeledVehicleComponent()->WheelSetups.Num())
105 {
106 InitWheels();
107 }
108 const TArray<FWheelAnimationData> &WheelPoses = GetWheelPoses();
109 for (int32 i = 0; i < Wheels.Num(); ++i)
110 {
111 // Carry on from the angle Chaos left.
112 Wheels[i].SpinAngle = WheelPoses.IsValidIndex(i) ? WheelPoses[i].RotOffset.Pitch : 0.0f;
113 }
114}
115
117{
118 TArray<FWheelAnimationData> &WheelPoses = GetWheelPoses();
119 const FTransform MeshTransform = GetSkelMeshComponent()->GetComponentTransform();
120 const FVector Forward = MeshTransform.GetUnitAxis(EAxis::X);
121 const float MaxTravel = MaxTravelSpeed * DeltaSeconds;
122
123 for (int32 i = 0; i < Wheels.Num() && i < WheelPoses.Num(); ++i)
124 {
125 FWheel &Wheel = Wheels[i];
126 const FVector Location = MeshTransform.TransformPosition(Wheel.RestLocation);
127 const float Travel = FVector::DotProduct(Location - Wheel.LastLocation, Forward);
128 Wheel.SpinAngle = RollWheel(Wheel.SpinAngle, Travel, Vehicle.GetWheelRadius(i), MaxTravel);
129 Wheel.LastLocation = Location;
130 WheelPoses[i].RotOffset.Pitch = Wheel.SpinAngle;
131 }
132}
133
135{
136 const bool bOverridden = Vehicle.IsWheelAnimationOverridden();
137 TArray<FWheelAnimationData> &WheelPoses = GetWheelPoses();
138 if (bOverridden)
139 {
140 const TArray<FWheelAnimationData> &OverriddenPoses = Vehicle.GetOverriddenWheelPoses();
141 for (int32 i = 0; i < WheelPoses.Num() && i < OverriddenPoses.Num(); ++i)
142 {
143 WheelPoses[i].RotOffset = OverriddenPoses[i].RotOffset;
144 WheelPoses[i].LocOffset = OverriddenPoses[i].LocOffset;
145 }
146 }
147 else if (bWasWheelAnimationOverridden && !Vehicle.IsSimulatedByChaos())
148 {
149 // Nothing else steers or compresses the wheels without Chaos. The roll
150 // carries on from the pitch left.
151 for (FWheelAnimationData &Pose : WheelPoses)
152 {
153 Pose.RotOffset.Yaw = 0.0f;
154 Pose.LocOffset = FVector::ZeroVector;
155 }
156 }
157 bWasWheelAnimationOverridden = bOverridden;
158}
159
160const FWheelAnimationData *UCarlaVehicleAnimationInstance::GetWheelPose(int32 WheelIndex) const
161{
162 const TArray<FWheelAnimationData> &WheelPoses =
163 GetProxyOnGameThread<FVehicleAnimationInstanceProxy>().GetWheelAnimData();
164 return WheelPoses.IsValidIndex(WheelIndex) ? &WheelPoses[WheelIndex] : nullptr;
165}
166
168{
169 // The engine has no setter for the wheel poses.
170 return const_cast<TArray<FWheelAnimationData> &>(
171 GetProxyOnGameThread<FVehicleAnimationInstanceProxy>().GetWheelAnimData());
172}
static float RollWheel(float SpinAngle, float Travel, float Radius, float MaxTravel)
Base class for CARLA wheeled vehicles.
void UpdateWheelAnimationOverride(const ACarlaWheeledVehicle &Vehicle)
float MaxTravelSpeed
cm/s. A wheel moving faster than this was teleported, and is not turned.
void RollWheels(const ACarlaWheeledVehicle &Vehicle, float DeltaSeconds)
virtual void NativeUpdateAnimation(float DeltaSeconds) override
void TrackWheelLocations()
World locations of the wheels, kept while not rolling.
bool ShouldRollWheels(const ACarlaWheeledVehicle &Vehicle) const
const FWheelAnimationData * GetWheelPose(int32 WheelIndex) const
The pose last written for a wheel, or nullptr if there is no such wheel.
TArray< FWheelAnimationData > & GetWheelPoses()
FVector RestLocation
Reference pose, component space.
FVector LastLocation
World space, previous update.