CARLA
Loading...
Searching...
No Matches
SpringBasedVegetationComponent.h
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
7#pragma once
8
9#include <util/ue-header-guard-begin.h>
10#include "Components/ActorComponent.h"
11#include "Components/SkeletalMeshComponent.h"
12#include <util/ue-header-guard-end.h>
13
14#include <vector>
15
16#include "SpringBasedVegetationComponent.generated.h"
17
18struct FJointProperties;
19
20USTRUCT(BlueprintType)
22{
23 GENERATED_BODY()
24
25 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Skeleton Bone")
26 float Mass = 1.f;
27 UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = "Skeleton Bone")
28 float Length = 0.5f;
29 UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = "Skeleton Bone")
30 FVector CenterOfMass = FVector(0,0,0);
31};
32
33USTRUCT(BlueprintType)
35{
36 GENERATED_BODY()
37
38 UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = "Skeleton Bone")
39 int JointId = 0;
40 UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = "Skeleton Bone")
41 int ParentId = 0;
42 UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = "Skeleton Bone")
43 FString JointName;
44 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Skeleton Bone")
45 bool bIsStatic = false;
46 UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = "Skeleton Bone")
47 TArray<int> ChildrenIds;
48 UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = "Skeleton Bone")
49 FTransform Transform = FTransform::Identity; // relative to parent
50 UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = "Skeleton Bone")
51 FRotator RestingAngles = FRotator::ZeroRotator; // resting angle position of springs
52 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Skeleton Bone")
53 float Mass = 10.f;
54 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Skeleton Bone")
55 float SpringStrength = 1000.f;
56 UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = "Skeleton Bone")
57 FRotator AngularVelocity = FRotator::ZeroRotator;
58 UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = "Skeleton Bone")
59 FRotator AngularAcceleration = FRotator::ZeroRotator;
60 UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = "Skeleton Bone")
61 FTransform GlobalTransform = FTransform::Identity;
62 UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = "Skeleton Bone")
63 FTransform GlobalInverseTransform = FTransform::Identity;
64 UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = "Skeleton Bone")
65 TArray<FSkeletonBone> Bones;
66 UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = "Skeleton Bone")
67 FVector ExternalForces = FVector::ZeroVector;
68 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Skeleton Bone")
69 float CollisionForceProportionalFactor = 1.0f;
70};
71
73{
74 bool CanRest = true;
75 int Iteration = 1;
76};
77
78USTRUCT(BlueprintType)
80{
81 GENERATED_BODY()
82
83 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Skeleton Bone")
84 TArray<FSkeletonJoint> Joints;
85 UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = "Skeleton Bone")
86 TArray<int> EndJoints;
87 UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = "Skeleton Bone")
88 TArray<int> EndToRootOrder;
89 UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = "Skeleton Bone")
90 TArray<int> RootToEndOrder;
91
92 void Clear();
93 void ComputeChildrenJointsAndBones();
94 void ComputeEndJoints();
95 void AddForce(const FString& BoneName, const FVector& Force);
96 void ClearExternalForces();
97 FSkeletonJoint& GetRootJoint() { return Joints[0]; }
98};
99
100UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
101class CARLA_API USpringBasedVegetationComponent : public UActorComponent
102{
103 GENERATED_BODY()
104
105public:
106
107 USpringBasedVegetationComponent(const FObjectInitializer& ObjectInitializer);
108
109 void BeginPlay() override;
110
111 void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
112
113 void TickComponent(float DeltaTime,
114 enum ELevelTick TickType,
115 FActorComponentTickFunction * ThisTickFunction) override;
116
117 void UpdateSkeletalMesh();
118
119 void UpdateGlobalTransform();
120
121 void GenerateCollisionCapsules();
122
123 void ResetComponent();
124
125 UFUNCTION(CallInEditor, Category = "Spring Based Vegetation Component")
126 void ComputeSpringStrengthForBranches();
127
128 UFUNCTION()
129 void OnCollisionEvent(
130 UPrimitiveComponent* HitComponent,
131 AActor* OtherActor,
132 UPrimitiveComponent* OtherComponent,
133 FVector NormalImpulse,
134 const FHitResult& Hit);
135
136 UFUNCTION()
137 void OnBeginOverlapEvent(
138 UPrimitiveComponent* OverlapComponent,
139 AActor* OtherActor,
140 UPrimitiveComponent* OtherComponent,
141 int32 OtherBodyIndex,
142 bool bFromSweep,
143 const FHitResult& SweepResult);
144
145 UFUNCTION()
146 void OnEndOverlapEvent(
147 UPrimitiveComponent* OverlapComponent,
148 AActor* OtherActor,
149 UPrimitiveComponent* OtherComponent,
150 int32 OtherBodyIndex);
151
152 UFUNCTION(CallInEditor, Category = "Spring Based Vegetation Component")
153 void GenerateSkeletonHierarchy();
154
155 // Nested TArray value is not supported by UE5 UHT inside a UPROPERTY TMap;
156 // a USTRUCT wrapper would be required to make this GC-safe.
157 //UPROPERTY(EditAnywhere, Category = "Spring Based Vegetation Component")
158 TMap<AActor*, TArray<UPrimitiveComponent*>> OverlappingActors;
159
160 UFUNCTION(BlueprintCallable)
161 void AddForce(const FString& BoneName, const FVector& Force)
162 {
163 Skeleton.AddForce(BoneName, Force);
164 }
165 UPROPERTY(EditAnywhere, Category = "Spring Based Vegetation Component")
166 TArray<FString> FixedJointsList = {"joint1"};
167
168 UPROPERTY(EditAnywhere, Category = "Spring Based Vegetation Component")
169 TArray<FString> DebugJointsToSimulate = {};
170
171private:
172
173 void ComputePerJointProperties(
174 std::vector<FJointProperties>& JointLocalPropertiesList,
175 std::vector<FJointProperties>& JointPropertiesList);
176 void ComputeCompositeBodyContribution(
177 std::vector<FJointProperties>& JointLocalPropertiesList,
178 std::vector<FJointProperties>& JointPropertiesList);
179 void ComputeFictitiousForces(
180 std::vector<FJointProperties>& JointLocalPropertiesList,
181 std::vector<FJointProperties>& JointPropertiesList);
182 void ResolveContactsAndCollisions(
183 std::vector<FJointProperties>& JointLocalPropertiesList,
184 std::vector<FJointProperties>& JointPropertiesList);
185 void SolveEquationOfMotion(std::vector<FJointProperties>& JointPropertiesList, float DeltaTime);
186
187 std::vector<FJointCollision> JointCollisionList;
188
189public:
190 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Spring Based Vegetation Component")
191 TObjectPtr<USkeletalMeshComponent> SkeletalMesh;
192
193 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Spring Based Vegetation Component")
194 TArray<TObjectPtr<UPrimitiveComponent>> BoneCapsules;
195
196 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Spring Based Vegetation Component")
197 TMap<TObjectPtr<UPrimitiveComponent>, int> CapsuleToJointId;
198
199 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Spring Based Vegetation Component")
200 float Beta = 0.5f;
201
202 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Spring Based Vegetation Component")
203 float Alpha = 0.f;
204
205 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Spring Based Vegetation Component")
206 FVector Gravity = FVector(0,0,-1);
207
208 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Spring Based Vegetation Component")
209 float BaseSpringStrength = 10000.f;
210
211 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Spring Based Vegetation Component")
212 float MinSpringStrength = 2000.f;
213
214 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Spring Based Vegetation Component")
215 float HorizontalFallof = 0.1f;
216
217 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Spring Based Vegetation Component")
218 float VerticalFallof = 0.1f;
219
220 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Spring Based Vegetation Component")
221 float RestFactor = 0.5f;
222
223 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Spring Based Vegetation Component")
224 float DeltaTimeOverride = -1.f;
225
226 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Spring Based Vegetation Component")
227 float CollisionForceParameter = 10.f;
228
229 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Spring Based Vegetation Component")
230 float CollisionForceMinVel = 1.f;
231
232 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Spring Based Vegetation Component")
233 float ForceDistanceFalloffExponent = 1.f;
234 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Spring Based Vegetation Component")
235 float ForceMaxDistance = 180.f;
236 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Spring Based Vegetation Component")
237 float MinForceFactor = 0.01;
238 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Spring Based Vegetation Component")
239 float LineTraceMaxDistance = 180.f;
240 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Spring Based Vegetation Component")
241 float CapsuleRadius = 6.0f;
242 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Spring Based Vegetation Component")
243 float MinBoneLength = 10.f;
244 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Spring Based Vegetation Component")
245 FVector SpringStrengthMulFactor = FVector(1,1,1);
246 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Spring Based Vegetation Component")
247 float VehicleCenterZOffset = 120.f;
248
249
250
251public:
252 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Spring Based Vegetation Component")
253 FSkeletonHierarchy Skeleton;
254
255 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Spring Based Vegetation Component")
256 bool DebugEnableVisualization { false };
257
258 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Spring Based Vegetation Component")
259 bool DebugEnableAllCollisions { false };
260
261 UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Spring Based Vegetation Component")
262 bool bAutoComputeStrength = true;
263};