CARLA
 
载入中...
搜索中...
未找到
SpringBasedVegetationComponent.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
9#include "Math/Matrix.h"
10#include "Components/CapsuleComponent.h"
11#include "DrawDebugHelpers.h"
12#include "Kismet/KismetMathLibrary.h"
13#include "BaseVegetationActor.h"
15#include <unordered_set>
16#include <vector>
17#include <cmath>
18#include <sstream>
19
21#include "carla/rpc/String.h"
23
24#define SPRINGVEGETATIONLOGS 0
25#define SOLVERLOGS 0
26#define COLLISIONLOGS 0
27#define ACCUMULATIONLOGS 0
28#define FICTITIOUSFORCELOGS 0
29#define OTHERLOGS 0
30
31#if SOLVERLOGS && SPRINGVEGETATIONLOGS
32#define SOLVER_LOG(Level, Msg, ...) UE_LOG(LogCarla, Level, TEXT(Msg), ##__VA_ARGS__)
33#else
34#define SOLVER_LOG(...)
35#endif
36#if COLLISIONLOGS && SPRINGVEGETATIONLOGS
37#define COLLISION_LOG(Level, Msg, ...) UE_LOG(LogCarla, Level, TEXT(Msg), ##__VA_ARGS__)
38#else
39#define COLLISION_LOG(...)
40#endif
41#if ACCUMULATIONLOGS && SPRINGVEGETATIONLOGS
42#define ACC_LOG(Level, Msg, ...) UE_LOG(LogCarla, Level, TEXT(Msg), ##__VA_ARGS__)
43#else
44#define ACC_LOG(...)
45#endif
46#if FICTITIOUSFORCELOGS && SPRINGVEGETATIONLOGS
47#define FICT_LOG(Level, Msg, ...) UE_LOG(LogCarla, Level, TEXT(Msg), ##__VA_ARGS__)
48#else
49#define FICT_LOG(...)
50#endif
51#if OTHERLOGS && SPRINGVEGETATIONLOGS
52#define OTHER_LOG(Level, Msg, ...) UE_LOG(LogCarla, Level, TEXT(Msg), ##__VA_ARGS__)
53#else
54#define OTHER_LOG(...)
55#endif
56
57
58FRotator GetDeltaRotator(const FRotator & Rotator1, const FRotator & Rotator2)
59{
60 float HalfCircle = 180.f;
61 float FullCircle = 360.f;
62 auto GetDeltaAngle = [&](float Angle1, float Angle2) -> float
63 {
64 if (Angle1 < 0)
65 {
66 Angle1 = FullCircle + Angle1;
67 }
68 if (Angle2 < 0)
69 {
70 Angle2 = FullCircle + Angle2;
71 }
72 float Diff = fmod( Angle1 - Angle2 + HalfCircle , FullCircle) - HalfCircle;
73 return Diff < -HalfCircle ? Diff + FullCircle : Diff;
74 };
75
76 return FRotator(
77 GetDeltaAngle(Rotator1.Pitch, Rotator2.Pitch),
78 GetDeltaAngle(Rotator1.Yaw, Rotator2.Yaw),
79 GetDeltaAngle(Rotator1.Roll, Rotator2.Roll)
80 );
81}
82
83template <class T>
84static T GetSign(T n)
85{
86 return n < 0.0f ? -1.0f : 1.0f;
87}
88template <class T>
89static FString EigenToFString(T& t)
90{
91 std::stringstream ss;
92 ss << t;
93 return carla::rpc::ToFString(ss.str());
94}
95static Eigen::Matrix3d OuterProduct(const Eigen::Vector3d& V1, const Eigen::Vector3d& V2)
96{
97 return V1 * V2.transpose();
98}
99static Eigen::Matrix3d OuterProduct(const Eigen::Vector3d& V1)
100{
101 return V1 * V1.transpose();
102}
103// convert to right handed frame by flipping z coordinate
104static Eigen::Vector3d ToEigenVector(const FVector& V1)
105{
106 return Eigen::Vector3d(V1.X, V1.Y, -V1.Z);
107}
108static FVector ToUnrealVector(const Eigen::Vector3d& V1)
109{
110 return FVector(V1(0), V1(1), -V1(2));
111}
112static Eigen::Matrix3d ToEigenMatrix(const FMatrix& Matrix) // Matrix[row][column]
113{
114 Eigen::Matrix3d EigenMatrix;
115 EigenMatrix << Matrix.M[0][0], Matrix.M[0][1], -Matrix.M[0][2],
116 Matrix.M[1][0], Matrix.M[1][1], -Matrix.M[1][2],
117 Matrix.M[2][0], Matrix.M[2][1], -Matrix.M[2][2];
118 return EigenMatrix.transpose();
119}
120static Eigen::Matrix3d ToEigenMatrix(const FTransform& Transform)
121{
122 FMatrix Matrix = Transform.ToMatrixNoScale(); // Matrix[row][column]
123 return ToEigenMatrix(Matrix);
124}
125static Eigen::Vector3d RotatorToEigenVector(const FRotator& Rotator)
126{
127 return Eigen::Vector3d(
128 FMath::DegreesToRadians(Rotator.Roll),
129 FMath::DegreesToRadians(Rotator.Pitch),
130 -FMath::DegreesToRadians(Rotator.Yaw));
131}
132static FRotator EigenVectorToRotator(const Eigen::Vector3d& Vector)
133{
134 return FRotator(
135 FMath::RadiansToDegrees(Vector(1)),
136 -FMath::RadiansToDegrees(Vector(2)),
137 FMath::RadiansToDegrees(Vector(0)));
138}
139
141{
142 Joints.Empty();
143 EndJoints.Empty();
144 EndToRootOrder.Empty();
145 RootToEndOrder.Empty();
146}
148{
149 TRACE_CPUPROFILER_EVENT_SCOPE(FSkeletonHierarchy::ComputeChildrenJointsAndBones);
150 for (int i = 1; i < Joints.Num(); i++)
151 {
152 FSkeletonJoint& Joint = Joints[i];
153 FSkeletonJoint& ParentJoint = Joints[Joint.ParentId];
154 ParentJoint.ChildrenIds.Add(i);
155 }
156
157 // debug
158 for (int i = 0; i < Joints.Num(); i++)
159 {
160 FSkeletonJoint& Joint = Joints[i];
161 FString ChildrenIds = "";
162 for (int ChildrenId : Joint.ChildrenIds)
163 {
164 ChildrenIds += FString::FromInt(ChildrenId) + ", ";
165 }
166 OTHER_LOG(Warning, "Joint %d, Children: %s.", i, *ChildrenIds);
167 }
168}
169
171{
172 TRACE_CPUPROFILER_EVENT_SCOPE(FSkeletonHierarchy::ComputeEndJoints);
173 EndJoints.Empty();
174 for (int i = 0; i < Joints.Num(); i++)
175 {
176 FSkeletonJoint& Joint = Joints[i];
177 if (!Joint.ChildrenIds.Num())
178 {
179 EndJoints.Add(i);
180 }
181 }
182
183 // build traversal order so that parent nodes are visited before any children
184 RootToEndOrder.Empty();
185 std::vector<int> JointsToVisit;
186 JointsToVisit.emplace_back(0); // root element in the hierarchy
187 RootToEndOrder.Add(0);
188 while (JointsToVisit.size())
189 {
190 FSkeletonJoint& Joint = Joints[JointsToVisit.back()];
191 JointsToVisit.pop_back();
192
193 for (int ChildrenId : Joint.ChildrenIds)
194 {
195 RootToEndOrder.Add(ChildrenId);
196 JointsToVisit.emplace_back(ChildrenId);
197 }
198 }
199
200 // build the order in reverse, children visited before parents
201 EndToRootOrder.Empty();
202 FString IdOrder = "";
203 FString NameOrder = "";
204 for(int i = RootToEndOrder.Num() - 1; i >= 0; i--)
205 {
206 int Id = RootToEndOrder[i];
207 EndToRootOrder.Add(Id);
208 IdOrder += FString::FromInt(Id) + " ";
209 NameOrder += Joints[Id].JointName + " ";
210 }
211 //debug
212 OTHER_LOG(Warning, "Tree order: %s", *IdOrder);
213 OTHER_LOG(Warning, "Tree order (names): %s", *NameOrder);
214 OTHER_LOG(Warning, "Num elements: %d", EndToRootOrder.Num());
215}
216
217void FSkeletonHierarchy::AddForce(const FString& BoneName, const FVector& Force)
218{
219 TRACE_CPUPROFILER_EVENT_SCOPE(FSkeletonHierarchy::AddForce);
220 for (FSkeletonJoint& Joint : Joints)
221 {
222 if(Joint.JointName == BoneName)
223 {
224 Joint.ExternalForces += Force;
225 }
226 }
227}
229{
230 TRACE_CPUPROFILER_EVENT_SCOPE(FSkeletonHierarchy::ClearExternalForces);
231 for (FSkeletonJoint& Joint : Joints)
232 {
233 Joint.ExternalForces = FVector(0,0,0);
234 }
235}
236
237USpringBasedVegetationComponent::USpringBasedVegetationComponent(const FObjectInitializer& ObjectInitializer)
238 : Super(ObjectInitializer)
239{
240 PrimaryComponentTick.bCanEverTick = true;
241 PrimaryComponentTick.bStartWithTickEnabled = true;
242}
243
244void USpringBasedVegetationComponent::GenerateSkeletonHierarchy()
245{
246 TRACE_CPUPROFILER_EVENT_SCOPE(USpringBasedVegetationComponent::GenerateSkeletonHierarchy);
247 OTHER_LOG(Warning, "Get skeleton hierarchy");
248 // Get skeleton hierarchy
249 if (!SkeletalMesh)
250 {
251 UActorComponent* Component = GetOwner()->GetComponentByClass(USkeletalMeshComponent::StaticClass());
252 SkeletalMesh = Cast<USkeletalMeshComponent>(Component);
253 }
254 TArray<FName> BoneNames;
255 SkeletalMesh->GetBoneNames(BoneNames);
256 Skeleton.Clear();
257 for (int32 i = 0; i < BoneNames.Num(); i++)
258 {
259 FName& BoneName = BoneNames[i];
260 FString BoneNameString = BoneName.ToString();
261 bool bIsFixedJoint = FixedJointsList.Contains(BoneNameString) ||
262 (DebugJointsToSimulate.Num() && !DebugJointsToSimulate.Contains(BoneNameString));
263 FName ParentBoneName = SkeletalMesh->GetParentBone(BoneName);
264 int32 ParentIndex = SkeletalMesh->GetBoneIndex(ParentBoneName);
265 Skeleton.Joints.Add(FSkeletonJoint{i, ParentIndex, BoneNameString, bIsFixedJoint});
266 OTHER_LOG(Log, "Added bone %s with id %d and parent %d", *BoneNameString, i, ParentIndex);
267 }
268
269 Skeleton.ComputeChildrenJointsAndBones();
270 Skeleton.ComputeEndJoints();
271
272 // Get resting pose for bones
273 auto *AnimInst = SkeletalMesh->GetAnimInstance();
274 if (!AnimInst)
275 {
276 OTHER_LOG(Error, "Could not get animation instance.");
277 return;
278 }
279 UWalkerAnim *WalkerAnim = Cast<UWalkerAnim>(AnimInst);
280 if (!WalkerAnim)
281 {
282 OTHER_LOG(Error, "Could not get UWalkerAnim.");
283 return;
284 }
285
286 // get current pose
287 FPoseSnapshot TempSnapshot;
288 SkeletalMesh->SnapshotPose(TempSnapshot);
289
290 // copy pose
291 WalkerAnim->Snap = TempSnapshot;
292
293 for (int i=0; i<Skeleton.Joints.Num(); ++i)
294 {
295 FSkeletonJoint& Joint = Skeleton.Joints[i];
296 FTransform JointTransform = SkeletalMesh->GetSocketTransform(FName(*Joint.JointName), ERelativeTransformSpace::RTS_ParentBoneSpace);
297 Joint.Transform = JointTransform;
298 Joint.RestingAngles = JointTransform.Rotator();
299 OTHER_LOG(Log, "Getting info for bone %s, %f, %f, %f, %f", *Joint.JointName, Joint.RestingAngles.Pitch, Joint.RestingAngles.Yaw, Joint.RestingAngles.Roll);
300 if(i > 0)
301 {
302 FSkeletonJoint& ParentJoint = Skeleton.Joints[Joint.ParentId];
303 FVector BoneCOM = Joint.Transform.GetLocation()*0.5f;
304 float BoneLength = Joint.Transform.GetLocation().Size();
305 ParentJoint.Bones.Add({10, BoneLength, BoneCOM});
306 }
307 }
308
309 UpdateGlobalTransform();
310}
311
312void USpringBasedVegetationComponent::BeginPlay()
313{
314 TRACE_CPUPROFILER_EVENT_SCOPE(USpringBasedVegetationComponent::BeginPlay);
315 Super::BeginPlay();
316 OTHER_LOG(Warning, "USpringBasedVegetationComponent::BeginPlay");
317 OTHER_LOG(Warning, "Params: BaseSpringStrength %f, Num joints: %d, CollisionForceParameter %f", BaseSpringStrength, Skeleton.Joints.Num(), CollisionForceParameter);
318 if (!SkeletalMesh)
319 {
320 UActorComponent* Component = GetOwner()->GetComponentByClass(USkeletalMeshComponent::StaticClass());
321 SkeletalMesh = Cast<USkeletalMeshComponent>(Component);
322 }
323 if (!SkeletalMesh)
324 {
325 SetComponentTickEnabled(false);
326 OTHER_LOG(Error, "Could not find skeletal mesh component.");
327 return;
328 }
329
330 ABaseVegetationActor* BaseVegetation = Cast<ABaseVegetationActor>(GetOwner());
331 if(BaseVegetation)
332 {
333 BaseVegetation->SetParametersToComponent();
334 }
335
336 // set callbacks
337 SkeletalMesh->OnComponentHit.AddDynamic(this, &USpringBasedVegetationComponent::OnCollisionEvent);
338
339 if (!Skeleton.Joints.Num())
340 {
341 GenerateSkeletonHierarchy();
342 }
343
344 UpdateGlobalTransform();
345 GenerateCollisionCapsules();
346 if(bAutoComputeStrength)
347 {
348 ComputeSpringStrengthForBranches();
349 }
350
351 JointCollisionList.resize(Skeleton.Joints.Num());
352}
353
354void USpringBasedVegetationComponent::ResetComponent()
355{
356 Skeleton.ClearExternalForces();
357 SkeletalMesh->ResetAllBodiesSimulatePhysics();
358}
359
360void USpringBasedVegetationComponent::GenerateCollisionCapsules()
361{
362 for (FSkeletonJoint& Joint : Skeleton.Joints)
363 {
364 for (FSkeletonBone& Bone : Joint.Bones)
365 {
366 if (Bone.Length < MinBoneLength)
367 {
368 continue;
369 }
370 UCapsuleComponent* Capsule = NewObject<UCapsuleComponent>(GetOwner());
371 Capsule->AttachToComponent(SkeletalMesh, FAttachmentTransformRules::KeepRelativeTransform, FName(*Joint.JointName));
372 Capsule->RegisterComponent();
373 // create rotation from z direction to align the capsule
374 FRotator BoneRotation = UKismetMathLibrary::MakeRotFromZ(Bone.CenterOfMass.GetSafeNormal());
375 FTransform CapsuleTransform(BoneRotation, Bone.CenterOfMass, FVector(1,1,1));
376 Capsule->SetRelativeTransform(CapsuleTransform);
377 Capsule->SetCapsuleHalfHeight(Bone.Length*0.5f);
378 Capsule->SetCapsuleRadius(CapsuleRadius);
379 if (Joint.bIsStatic)
380 {
381 Capsule->SetGenerateOverlapEvents(false);
382 Capsule->SetCollisionProfileName("BlockAll");
383 Capsule->OnComponentHit.AddDynamic(this, &USpringBasedVegetationComponent::OnCollisionEvent);
384 }
385 else
386 {
387 Capsule->SetGenerateOverlapEvents(true);
388 Capsule->SetCollisionProfileName("OverlapAll");
389 Capsule->OnComponentBeginOverlap.AddDynamic(this, &USpringBasedVegetationComponent::OnBeginOverlapEvent);
390 Capsule->OnComponentEndOverlap.AddDynamic(this, &USpringBasedVegetationComponent::OnEndOverlapEvent);
391 }
392
393 BoneCapsules.Add(Capsule);
394 CapsuleToJointId.Add(Capsule, Joint.JointId);
395 }
396 }
397}
398
399void USpringBasedVegetationComponent::ComputeSpringStrengthForBranches()
400{
401 TRACE_CPUPROFILER_EVENT_SCOPE(USpringBasedVegetationComponent::ComputeSpringStrengthForBranches);
402 FTransform RootTransform = Skeleton.GetRootJoint().GlobalTransform;
403 FVector RootLocation = RootTransform.GetLocation();
404 // FVector TreeAxis = RootTransform.GetRotation().GetUpVector();
405 FVector TreeAxis = FVector(0,0,1);
406 for (FSkeletonJoint& Joint : Skeleton.Joints)
407 {
408 FVector JointLocation = Joint.GlobalTransform.GetLocation();
409 FVector ClosestPoint;
410 float HorizontalDistance = FMath::PointDistToLine(JointLocation, TreeAxis, RootLocation, ClosestPoint);
411 float VerticalDistance = FVector::Distance(ClosestPoint, RootLocation);
412
413 Joint.SpringStrength = FMath::Max(
414 BaseSpringStrength - HorizontalFallof*HorizontalDistance - VerticalFallof*VerticalDistance,
415 MinSpringStrength);
416
417 OTHER_LOG(Log, "Joint: %s, location %s, Strength %f", *Joint.JointName, *JointLocation.ToString(), Joint.SpringStrength);
418 }
419}
420
421void USpringBasedVegetationComponent::EndPlay(const EEndPlayReason::Type EndPlayReason)
422{
423 for (UPrimitiveComponent* Capsule : BoneCapsules)
424 {
425 Capsule->DestroyComponent();
426 }
427 BoneCapsules.Empty();
428}
429
430// Compute a single joint properties (Center of Mass, Inertia, Forces and Torque)
431void USpringBasedVegetationComponent::ComputePerJointProperties(
432 std::vector<FJointProperties>& JointLocalPropertiesList,
433 std::vector<FJointProperties>& JointPropertiesList)
434{
435 TRACE_CPUPROFILER_EVENT_SCOPE(USpringBasedVegetationComponent::ComputePerJointProperties);
436 for(FSkeletonJoint& Joint : Skeleton.Joints)
437 {
438 FJointProperties& Properties = JointLocalPropertiesList[Joint.JointId];
439 Eigen::Vector3d JointGlobalPosition = ToEigenVector(Joint.GlobalTransform.GetLocation())/100.f;
441 JointPropertiesList[Joint.JointId].JointToGlobalMatrix = Properties.JointToGlobalMatrix;
442 if (!Joint.Bones.Num())
443 continue;
444 // COM and mass
445 for (FSkeletonBone& Bone : Joint.Bones)
446 {
447 Properties.Mass += Bone.Mass;
448 FVector GlobalCenterOfMass = Joint.GlobalTransform.TransformPositionNoScale(Bone.CenterOfMass);
449 Properties.CenterOfMass += Bone.Mass*ToEigenVector(GlobalCenterOfMass)/100.f;
450 }
451 Properties.CenterOfMass = Properties.CenterOfMass/Properties.Mass;
452
453 // force
454 Eigen::Vector3d GravityForce = ToEigenVector(Gravity)/100.f; // world space gravity
455 Properties.Force = Properties.Mass * GravityForce + ToEigenVector(Joint.ExternalForces)/100.f;
456 // torque
457 Properties.Torque = (Properties.CenterOfMass - JointGlobalPosition).cross(Properties.Force);
458 // inertia tensor
459 for (FSkeletonBone& Bone : Joint.Bones)
460 {
461 if (Bone.Length < 1)
462 continue;
463 float CylinderRadius = 0.1f;
464 float CylinderHeight = Bone.Length/100.f;
465 Eigen::Matrix3d LocalCylinderInertia;
466 LocalCylinderInertia <<
467 0.5 * Bone.Mass*CylinderRadius*CylinderRadius, 0.f, 0.f,
468 0.f, 1.f/12.f * Bone.Mass*(3*CylinderRadius*CylinderRadius + CylinderHeight*CylinderHeight), 0.f,
469 0.f, 0.f, 1.f/12.f * Bone.Mass*(3*CylinderRadius*CylinderRadius + CylinderHeight*CylinderHeight);
470 Eigen::Vector3d BoneVector = ToEigenVector(Bone.CenterOfMass)/100.f;
471 Eigen::Vector3d LocalV1 = BoneVector.normalized();
472 Eigen::Vector3d LocalV2 = LocalV1.cross(Eigen::Vector3d(0,1,0));
473 if (LocalV2.norm() == 0)
474 LocalV2 = LocalV1.cross(Eigen::Vector3d(0,0,1));
475 LocalV2.normalize();
476 Eigen::Vector3d LocalV3 = LocalV1.cross(LocalV2);
477 Eigen::Matrix3d LocalToJointMatrix;
478 LocalToJointMatrix << LocalV1, LocalV2, LocalV3;
479 Eigen::Matrix3d JointSpaceInertia = LocalToJointMatrix*LocalCylinderInertia*(LocalToJointMatrix.transpose());
480 Properties.InertiaTensor += Properties.JointToGlobalMatrix*JointSpaceInertia*Properties.JointToGlobalMatrix.transpose();
481 Eigen::Vector3d BoneCenterWorldSpace = ToEigenVector(Joint.GlobalTransform.TransformPositionNoScale(Bone.CenterOfMass))/100.0;
482 Properties.InertiaTensor += Properties.Mass*OuterProduct(Properties.CenterOfMass - BoneCenterWorldSpace, Properties.CenterOfMass - BoneCenterWorldSpace);
483 }
484 ACC_LOG(Log, "Local Joint: %s \n Inertia \n %s \n Force \n %s \n Torque \n %s \n COM: \n %s \n Mass %f", *Joint.JointName, *EigenToFString(Properties.InertiaTensor), *EigenToFString(Properties.Force), *EigenToFString(Properties.Torque), *EigenToFString(Properties.CenterOfMass), Properties.Mass);
485 }
486}
487
488// Compute accumulated properties (Center of Mass, Inertia, Forces and Torque)
489void USpringBasedVegetationComponent::ComputeCompositeBodyContribution(
490 std::vector<FJointProperties>& JointLocalPropertiesList,
491 std::vector<FJointProperties>& JointPropertiesList)
492{
493 TRACE_CPUPROFILER_EVENT_SCOPE(USpringBasedVegetationComponent::ComputeCompositeBodyContribution);
494 for (int Id : Skeleton.EndToRootOrder)
495 {
496 FSkeletonJoint& Joint = Skeleton.Joints[Id];
497 FJointProperties& JointProperties = JointPropertiesList[Joint.JointId];
498 FJointProperties& JointLocalProperties = JointLocalPropertiesList[Joint.JointId];
499
500 if (!Joint.ChildrenIds.Num())
501 {
502 continue;
503 }
504
505 Eigen::Vector3d CenterOfMass = JointLocalProperties.Mass*JointLocalProperties.CenterOfMass;
506 // compute COM and accumulate mass
507 JointProperties.Mass = JointLocalProperties.Mass;
508 for(int ChildrenId : Joint.ChildrenIds)
509 {
510 FSkeletonJoint& ChildrenJoint = Skeleton.Joints[ChildrenId];
511 FJointProperties& ChildrenProperties = JointPropertiesList[ChildrenId];
512 CenterOfMass += ChildrenProperties.Mass*ChildrenProperties.CenterOfMass;
513 JointProperties.Mass += ChildrenProperties.Mass;
514 }
515 JointProperties.CenterOfMass = CenterOfMass / JointProperties.Mass;
516
517 // compute forces
518 JointProperties.Force = JointLocalProperties.Force;
519 for(int ChildrenId : Joint.ChildrenIds)
520 {
521 FSkeletonJoint& ChildrenJoint = Skeleton.Joints[ChildrenId];
522 FJointProperties& ChildrenProperties = JointPropertiesList[ChildrenId];
523 JointProperties.Force += ChildrenProperties.Force;
524 }
525
526 // compute torque
527 JointProperties.Torque = JointLocalProperties.Torque;
528 for(int ChildrenId : Joint.ChildrenIds)
529 {
530 FSkeletonJoint& ChildrenJoint = Skeleton.Joints[ChildrenId];
531 FJointProperties& ChildrenProperties = JointPropertiesList[ChildrenId];
532 Eigen::Vector3d ChildrenJointGlobalPosition = ToEigenVector(ChildrenJoint.GlobalTransform.GetLocation())/100.f;
533 Eigen::Vector3d ParentJointGlobalPosition = ToEigenVector(Joint.GlobalTransform.GetLocation())/100.f;
534 JointProperties.Torque += ChildrenProperties.Torque + (ChildrenJointGlobalPosition - ParentJointGlobalPosition).cross(ChildrenProperties.Force);
535 }
536
537 // compute inertia tensor
538 JointProperties.InertiaTensor = JointLocalProperties.InertiaTensor + JointLocalProperties.Mass*OuterProduct(JointProperties.CenterOfMass - JointLocalProperties.CenterOfMass, JointProperties.CenterOfMass - JointLocalProperties.CenterOfMass);
539 for(int ChildrenId : Joint.ChildrenIds)
540 {
541 FSkeletonJoint& ChildrenJoint = Skeleton.Joints[ChildrenId];
542 FJointProperties& ChildrenProperties = JointPropertiesList[ChildrenId];
543 Eigen::Vector3d ChildrenToCenterOfMass = JointProperties.CenterOfMass - ChildrenProperties.CenterOfMass;
544
545 JointProperties.InertiaTensor += ChildrenProperties.InertiaTensor + ChildrenProperties.Mass*OuterProduct(ChildrenToCenterOfMass, ChildrenToCenterOfMass);
546 }
547 ACC_LOG(Log, "Accumulated Joint: %s \n Inertia \n %s \n Force \n %s \n Torque \n %s \n COM: \n %s \n Mass %f", *Joint.JointName, *EigenToFString(JointProperties.InertiaTensor), *EigenToFString(JointProperties.Force), *EigenToFString(JointProperties.Torque), *EigenToFString(JointProperties.CenterOfMass), JointProperties.Mass);
548 }
549}
550
551void USpringBasedVegetationComponent::ComputeFictitiousForces(
552 std::vector<FJointProperties>& JointLocalPropertiesList,
553 std::vector<FJointProperties>& JointPropertiesList)
554{
555 TRACE_CPUPROFILER_EVENT_SCOPE(USpringBasedVegetationComponent::ComputeFictitiousForces);
556 // fictitious forces
557 FSkeletonJoint& RootJoint = Skeleton.Joints[0];
558 FJointProperties& RootProperties = JointPropertiesList[0];
559 for (int i = 1; i < Skeleton.RootToEndOrder.Num(); i++)
560 {
561 int Id = Skeleton.RootToEndOrder[i];
562 FSkeletonJoint& Joint = Skeleton.Joints[Id];
563 FJointProperties& JointProperties = JointPropertiesList[Joint.JointId];
564 FSkeletonJoint& ParentJoint = Skeleton.Joints[Joint.ParentId];
565 FJointProperties& ParentProperties = JointPropertiesList[Joint.ParentId];
566
567 Eigen::Matrix3d JointToGlobalMatrix = JointProperties.JointToGlobalMatrix;
568 Eigen::Matrix3d GlobalToJointMatrix = JointToGlobalMatrix.transpose();
569 Eigen::Matrix3d ParentJointToGlobalMatrix = ParentProperties.JointToGlobalMatrix;
570 Eigen::Matrix3d GlobalToParentJointMatrix = ParentJointToGlobalMatrix.transpose();
571 Eigen::Vector3d JointGlobalPosition = ToEigenVector(Joint.GlobalTransform.GetLocation())/100.f;
572 Eigen::Vector3d ParentJointGlobalPosition = ToEigenVector(ParentJoint.GlobalTransform.GetLocation())/100.f;
573
574 JointProperties.AngularVelocity = ParentProperties.AngularVelocity
575 + ParentJointToGlobalMatrix*RotatorToEigenVector(ParentJoint.AngularVelocity);
576 JointProperties.LinearVelocity = ParentProperties.LinearVelocity
577 + ParentProperties.AngularVelocity.cross(JointGlobalPosition - ParentJointGlobalPosition);
578 JointProperties.AngularAcceleration = ParentProperties.AngularAcceleration
579 + ParentJointToGlobalMatrix*RotatorToEigenVector(ParentJoint.AngularAcceleration)
580 + ParentProperties.AngularVelocity.cross(JointProperties.AngularVelocity);
581 JointProperties.LinearAcceleration = ParentProperties.LinearAcceleration
582 + ParentProperties.LinearAcceleration.cross(JointGlobalPosition - ParentJointGlobalPosition)
583 + ParentProperties.AngularVelocity.cross(JointProperties.AngularVelocity - ParentProperties.AngularVelocity);
584
585 Eigen::Vector3d CompositeCenterOfMass = JointProperties.CenterOfMass;
586 Eigen::Vector3d CompositeLinearVelocity = JointProperties.LinearVelocity
587 + JointProperties.AngularVelocity.cross(CompositeCenterOfMass - JointGlobalPosition);
588 Eigen::Vector3d CompositeLinearAcceleration = JointProperties.LinearAcceleration
589 + JointProperties.AngularAcceleration.cross(CompositeCenterOfMass - JointGlobalPosition)
590 + JointProperties.AngularVelocity.cross(CompositeLinearVelocity - JointProperties.LinearVelocity);
591
592 Eigen::Vector3d TotalForces = -Joint.Mass * JointProperties.LinearAcceleration;
593 Eigen::Vector3d TotalTorque = (CompositeCenterOfMass - JointGlobalPosition).cross(TotalForces);
594 JointProperties.FictitiousTorque = GlobalToJointMatrix*TotalTorque;
595
596 FICT_LOG(Log, "Joint: %s \n Position \n %s \n Velocity \n %s \n Acceleration \n %s \n Fictitious forces: \n %s", *Joint.JointName, *EigenToFString(CompositeCenterOfMass), *EigenToFString(CompositeLinearVelocity), *EigenToFString(CompositeLinearAcceleration), *EigenToFString(JointProperties.FictitiousTorque));
597 }
598}
599
600void USpringBasedVegetationComponent::ResolveContactsAndCollisions(
601 std::vector<FJointProperties>& JointLocalPropertiesList,
602 std::vector<FJointProperties>& JointPropertiesList)
603{
604 TRACE_CPUPROFILER_EVENT_SCOPE(USpringBasedVegetationComponent::ResolveContactsAndCollisions);
605
606 // set all joints that can rest
607 for (auto &Joint : JointCollisionList)
608 {
609 Joint.CanRest = true;
610 }
611
612 for (auto& ActorCapsules : OverlappingActors)
613 {
614 TRACE_CPUPROFILER_EVENT_SCOPE(ActorLoop);
615 AActor* CollidingActor = ActorCapsules.Key;
616 if (!IsValid(CollidingActor))
617 continue;
618 UPrimitiveComponent* Primitive = Cast<UPrimitiveComponent>(CollidingActor->GetRootComponent());
619 if (!IsValid(Primitive))
620 continue;
621 // force transferring momentum (for the initial collision frame)
622 const FVector PrimitiveVelocity = Primitive->GetComponentVelocity();
623 const Eigen::Vector3d ColliderVelocity = ToEigenVector(PrimitiveVelocity) / 100.f;
624 const FVector Impulse = (Primitive->GetMass() * PrimitiveVelocity);
625 const Eigen::Vector3d CollisionImpulse = 0*ToEigenVector(Impulse) / 100.f;
626 TArray<UPrimitiveComponent*>& CollidingCapsules = ActorCapsules.Value;
627 for (UPrimitiveComponent* Capsule : CollidingCapsules)
628 {
629 TRACE_CPUPROFILER_EVENT_SCOPE(CapsuleLoop);
630 if (!IsValid(Capsule))
631 continue;
632 const FVector CapsuleLocation = Capsule->GetComponentLocation();
633 FVector PrimitiveLocation = Primitive->GetComponentLocation();
634 PrimitiveLocation = PrimitiveLocation + Primitive->GetUpVector()*VehicleCenterZOffset;
635 FVector ClosestPointOnCapsule;
636 float DistanceOnCapsule;
637 FHitResult HitResult;
638 bool HitFound;
639 FVector ClosestPointOnCollider;
640 float DistanceToCollider;
641 {
642 TRACE_CPUPROFILER_EVENT_SCOPE(ColliderPenetrationDistance);
643 DistanceOnCapsule = Capsule->GetClosestPointOnCollision(PrimitiveLocation, ClosestPointOnCapsule);
644 FVector LineDirection = (ClosestPointOnCapsule - PrimitiveLocation).GetSafeNormal();
645 FVector LineTraceStart = ClosestPointOnCapsule + LineTraceMaxDistance*LineDirection;
646 FVector LineTraceEnd = ClosestPointOnCapsule;
647 HitFound = Primitive->LineTraceComponent(HitResult,
648 LineTraceStart, LineTraceEnd, FCollisionQueryParams());
649 ClosestPointOnCollider = HitResult.Location;
650 DistanceToCollider = (ClosestPointOnCollider - ClosestPointOnCapsule).Size();
651 if (DebugEnableVisualization)
652 {
653 DrawDebugLine(GetWorld(), LineTraceStart, LineTraceEnd, FColor::Orange, false, 0.1f, 0.0f, 1.f);
654 }
655 }
656 if(!HitFound)
657 {
658 continue;
659 }
660
661 if (DebugEnableVisualization)
662 {
663 TRACE_CPUPROFILER_EVENT_SCOPE(DebugEnableVisualization);
664 DrawDebugLine(GetWorld(), ClosestPointOnCapsule, ClosestPointOnCollider, FColor::Green, false, 0.1f, 0.0f, 1.f);
665 static constexpr float DEBUG_SPHERE_SIZE = 5.0f;
666 DrawDebugSphere(GetWorld(), ClosestPointOnCapsule, DEBUG_SPHERE_SIZE, 64, FColor(255, 0, 255, 255));
667 DrawDebugSphere(GetWorld(), ClosestPointOnCollider, DEBUG_SPHERE_SIZE, 64, FColor(255, 0, 255, 255));
668 DrawDebugSphere(GetWorld(), CapsuleLocation, DEBUG_SPHERE_SIZE, 64, FColor(255, 255, 255, 255));
669 DrawDebugSphere(GetWorld(), PrimitiveLocation, DEBUG_SPHERE_SIZE, 64, FColor(255, 255, 255, 255));
670 }
671
672 const int JointId = CapsuleToJointId[Capsule];
673 const FSkeletonJoint& Joint = Skeleton.Joints[JointId];
674 FJointProperties& JointProperties = JointLocalPropertiesList[Joint.JointId];
675 FJointCollision& JointCollision = JointCollisionList[Joint.JointId];
676 const Eigen::Vector3d JointGlobalPosition = ToEigenVector(Joint.GlobalTransform.GetLocation()) / 100.f;
677 const Eigen::Vector3d CapsulePosition = ToEigenVector(CapsuleLocation) / 100.f;
678 const Eigen::Vector3d PointOnCapsulePosition = ToEigenVector(ClosestPointOnCapsule) / 100.f;
679 const Eigen::Vector3d ColliderPosition = ToEigenVector(ClosestPointOnCollider) / 100.f;
680 Eigen::Vector3d CollisionTorque = Eigen::Vector3d::Zero();
681
682 // Contact forces due to spring strength
683 const FRotator CurrRotator = Joint.Transform.Rotator();
684 const FRotator RestRotator = Joint.RestingAngles;
685 const FRotator DeltaRotator =
686 GetDeltaRotator(CurrRotator, RestRotator);
687 const Eigen::Vector3d SpringTorque = Joint.SpringStrength * RotatorToEigenVector(DeltaRotator);
688 const Eigen::Vector3d JointCapsuleVector = JointGlobalPosition - CapsulePosition;
689 const Eigen::Vector3d RepulsionForce = SpringTorque.cross(JointCapsuleVector) * JointCapsuleVector.squaredNorm();
690
691 FVector RepulsionForceUE = -ToUnrealVector(RepulsionForce) * 100.f;
692 Primitive->AddForceAtLocation(RepulsionForceUE, ClosestPointOnCollider);
693
694 // force to repel geometry overlapping
695 float ForceFactor = 1.f;
696 // from eq f = 1 - a*d^p, f: ForceFactor, a: ProportionalConstant, p: ForceDistanceFalloffExponent, d: DistanceOnCapsule
697 // float ProportionalConstant = 1.f/(FMath::Pow(ForceMaxDistance, ForceDistanceFalloffExponent));
698 // ForceFactor = 1.f - ProportionalConstant * FMath::Pow(DistanceOnCapsule, ForceDistanceFalloffExponent);
699 // from eq f = a*d^p, f: ForceFactor, a: ProportionalConstant, p: ForceDistanceFalloffExponent, d: DistanceToCollider
700 float ProportionalConstant = 1.f/(FMath::Pow(ForceMaxDistance, ForceDistanceFalloffExponent));
701 ForceFactor = ProportionalConstant * FMath::Pow(DistanceToCollider, ForceDistanceFalloffExponent);
702 ForceFactor = FMath::Clamp(ForceFactor, MinForceFactor, 1.f);
703
704 // const Eigen::Vector3d OverlappingForces = (ColliderPosition - CapsulePosition).normalized() * CollisionForceParameter * ForceFactor;
705 // const Eigen::Vector3d OverlappingForces = (ColliderPosition - PointOnCapsulePosition).normalized() * CollisionForceParameter * ForceFactor;
706 float Factor = 1.0f - ((JointCollision.Iteration / 100.0f) * RestFactor);
707 const Eigen::Vector3d OverlappingForces = (ColliderPosition - PointOnCapsulePosition).normalized() * CollisionForceParameter * ForceFactor * Factor * Joint.CollisionForceProportionalFactor;
708 Primitive->AddForceAtLocation(-ToUnrealVector(OverlappingForces) * 100.f, ClosestPointOnCollider);
709 CollisionTorque += (PointOnCapsulePosition - JointGlobalPosition).cross(CollisionImpulse + OverlappingForces);
710 JointProperties.Torque += CollisionTorque;
711 // COLLISION_LOG(Log, "Joint: %s \n ProjectedSpeed %f, ProportionalFactor %f \n RepulsionForce %s \n", *Joint.JointName,ProjectedSpeed,ProportionalFactor,*EigenToFString(RepulsionForce),*EigenToFString(CollisionTorque));
712 //UE_LOG(LogCarla, Display, TEXT("DistanceToCollider: %f, ForceFactor: %f"), DistanceToCollider, ForceFactor);
713
714 // block forces to go to rest angles
715 int TempId = JointId;
716 do
717 {
718 FJointCollision& TempJointCollision = JointCollisionList[TempId];
719 TempJointCollision.CanRest = false;
720
721 FSkeletonJoint &TempJoint = Skeleton.Joints[TempId];
722 TempId = TempJoint.ParentId;
723 }
724 while (TempId != -1);
725
726 if (DebugEnableVisualization)
727 {
728 static constexpr float DEBUG_SPHERE_SIZE = 5.0f;
729 // drawing
730 const FVector Start = Capsule->GetComponentLocation();
731 const FVector End = Primitive->GetComponentLocation();
732 const FColor LineColor(FColor::Green);
733 DrawDebugLine(GetWorld(), Start, End, LineColor, false, 0.1f, 0.0f, 1.f);
734 DrawDebugLine(GetWorld(), ClosestPointOnCollider, ClosestPointOnCollider+RepulsionForceUE.GetSafeNormal()*20.f, FColor::Red, false, 0.1f, 0.0f, 1.f);
735 FVector UEOverlapForces = ToUnrealVector(OverlappingForces)*100.f;
736 DrawDebugLine(GetWorld(), ClosestPointOnCapsule, ClosestPointOnCapsule+UEOverlapForces.GetSafeNormal()*20.f, FColor::Turquoise, false, 0.1f, 0.0f, 1.f);
737 FVector UECOM = ToUnrealVector(JointProperties.CenterOfMass )*100.f;
738 DrawDebugSphere(GetWorld(), UECOM, DEBUG_SPHERE_SIZE, 64, FColor::Emerald);
739 FVector UEJointPos = ToUnrealVector(JointGlobalPosition )*100.f;
740 DrawDebugSphere(GetWorld(), UEJointPos, DEBUG_SPHERE_SIZE, 64, FColor::Purple);
741 DrawDebugLine(GetWorld(), ClosestPointOnCapsule, UEJointPos, FColor::Cyan, false, 0.1f, 0.0f, 1.f);
742 }
743 }
744 }
745
746 // reset iteration
747 for (auto &Joint : JointCollisionList)
748 {
749 if (Joint.CanRest)
750 {
751 if (Joint.Iteration > 1)
752 {
753 --Joint.Iteration;
754 }
755 }
756 else
757 {
758 if (Joint.Iteration <= 95)
759 {
760 Joint.Iteration += 5;
761 }
762 }
763 }
764}
765
766void USpringBasedVegetationComponent::SolveEquationOfMotion(
767 std::vector<FJointProperties>& JointPropertiesList,
768 float DeltaTime)
769{
770 TRACE_CPUPROFILER_EVENT_SCOPE(USpringBasedVegetationComponent::SolveEquationOfMotion);
771 // solver
772 for (FSkeletonJoint& Joint : Skeleton.Joints)
773 {
774 if (!Joint.Bones.Num() || Joint.bIsStatic)
775 {
776 continue;
777 }
778 FJointProperties& JointProperties = JointPropertiesList[Joint.JointId];
779 FJointCollision& JointCollision = JointCollisionList[Joint.JointId];
780
781 // debug drawing
782 if (DebugEnableVisualization)
783 {
784 if (Joint.ParentId != -1)
785 {
786 FVector Start = Joint.GlobalTransform.GetLocation();
787 FVector End = Skeleton.Joints[Joint.ParentId].GlobalTransform.GetLocation();
788 if (!JointCollision.CanRest)
789 {
790 DrawDebugLine(GetWorld(), Start, End, FColor::Red, false, 0.3f, 0.0f, 1.f);
791 }
792 else
793 {
794 DrawDebugLine(GetWorld(), Start, End, FColor::Blue, false, 0.1f, 0.0f, 1.f);
795 }
796 }
797 }
798
799 float Mass = JointProperties.Mass;
800 Eigen::Vector3d CenterToJoint = JointProperties.CenterOfMass - ToEigenVector(Joint.GlobalTransform.GetLocation())/100.f;
801 Eigen::Matrix3d GlobalToJointMatrix = JointProperties.JointToGlobalMatrix.transpose();
802 Eigen::Matrix3d JointSpaceIntertiaTensor = JointProperties.Mass*OuterProduct(CenterToJoint, CenterToJoint)
803 + GlobalToJointMatrix*JointProperties.InertiaTensor*GlobalToJointMatrix.transpose();
804 Eigen::Vector3d Torque = GlobalToJointMatrix*JointProperties.Torque + JointProperties.FictitiousTorque;
805 // build differential equation
806 Eigen::Matrix3d I = JointSpaceIntertiaTensor;
807 float SpringStrength = Joint.SpringStrength;
808 float beta = Beta;
809 float alpha = Alpha;
810 Eigen::Matrix3d K;
811 K << SpringStrength*SpringStrengthMulFactor.X,0.f,0.f,
812 0.f,SpringStrength*SpringStrengthMulFactor.Y,0.f,
813 0.f,0.f,SpringStrength*SpringStrengthMulFactor.Z;
814 Eigen::LLT<Eigen::Matrix3d> lltofI (I);
815 Eigen::Matrix3d L = lltofI.matrixL();
816 Eigen::Matrix3d Linv = L.inverse();
817 Eigen::EigenSolver<Eigen::Matrix3d> EigenDecomposition(Linv*K*Linv.transpose());
818 Eigen::Matrix3d Lambda = EigenDecomposition.eigenvalues().real().asDiagonal();
819 Eigen::Matrix3d X = EigenDecomposition.eigenvectors().real();
820 // Eigen::Matrix3d Lambda = U.transpose()*K*U;
821 Eigen::Matrix3d U = Linv.transpose()*X;
822 // Eigen::Matrix3d Uinv = U.inverse();
823 Eigen::Matrix3d Uinv = X.transpose()*L.transpose();
824 Eigen::Vector3d Coeffsb = Eigen::Vector3d(alpha,alpha,alpha) + beta*Lambda*Eigen::Vector3d(1,1,1);
825 Eigen::Vector3d Coeffsk = Lambda*Eigen::Vector3d(1,1,1);
826 Eigen::Vector3d Coeffsf = U.transpose()*Torque;
827 FString StringI = EigenToFString(I);
828 FString StringTorque = EigenToFString(Torque);
829 FString StringU = EigenToFString(U);
830 FString StringLambda = EigenToFString(Lambda);
831 FString StringGlobalToJoint = EigenToFString(GlobalToJointMatrix);
832 FString StringCenterToJoint = EigenToFString(CenterToJoint);
833 SOLVER_LOG(Log, "Bone %s: \n I: \n %s \n Tau: \n %s \n U: \n %s \n Lambda: \n %s \n X: \n %s \n GlobalToJoint \n %s \n CenterToJoint \n %s", *Joint.JointName, *StringI, *StringTorque, *StringU, *StringLambda, *EigenToFString(X), *StringGlobalToJoint, *StringCenterToJoint);
834
835 FRotator CurrRotator = Joint.Transform.Rotator();
836 FRotator RestRotator = Joint.RestingAngles;
837 FRotator AngularVelocity = Joint.AngularVelocity;
838 FRotator DeltaRotator =
839 GetDeltaRotator(CurrRotator, RestRotator);
840 if (!JointCollision.CanRest)
841 {
842 float Factor = 1.0f - ((JointCollision.Iteration / 100.0f) * RestFactor);
843 // DeltaRotator *= Factor;
844 AngularVelocity *= Factor;
845 }
846 Eigen::Vector3d InitialTheta = Uinv*RotatorToEigenVector(DeltaRotator);
847 Eigen::Vector3d InitialThetaVelocity = Uinv*RotatorToEigenVector(AngularVelocity);
848 SOLVER_LOG(Log, "Old angle for joint %s, %s", *Joint.JointName, *CurrRotator.ToString());
849 SOLVER_LOG(Log, "InitialTheta \n %s", *EigenToFString(InitialTheta));
850 Eigen::Vector3d NewTheta (0.f,0.f,0.f);
851 Eigen::Vector3d NewThetaVelocity (0.f,0.f,0.f);
852 Eigen::Vector3d NewThetaAccel (0.f,0.f,0.f);
853 Eigen::Vector3d Discriminant = Coeffsb.cwiseProduct(Coeffsb) - 4*Coeffsk;
854 // 1st row
855 for (int i = 0; i < 3; i++)
856 {
857 double b = Coeffsb(i);
858 double k = Coeffsk(i);
859 double f = Coeffsf(i);
860 double discriminant = Discriminant(i);
861 double theta0 = InitialTheta(i);
862
863 SOLVER_LOG(Log, "Bone %s, component %d, b %f, k %f, f %f, discriminant %f, theta0 %f", *Joint.JointName, i, b, k, f, discriminant, theta0);
864 if(k == 0)
865 {
866 NewTheta(i) = theta0;
867 SOLVER_LOG(Log, "In Bone %s, K is 0 in component %d", *Joint.JointName, i);
868 }
869 double dtheta0 = InitialThetaVelocity(i); // compute
870 double deltatheta = 0;
871 double angularvelocity = 0;
872 float angularaccel = 0;
873 if (discriminant > 0)
874 {
875 double r1 = (-b + FMath::Sqrt(discriminant))*0.5f;
876 double r2 = (-b - FMath::Sqrt(discriminant))*0.5f;
877 double c1 = (r2*(theta0 - f/k) - dtheta0)/(r2-r1);
878 double c2 = (dtheta0 - c1*r1)/r2;
879 deltatheta = c1*std::exp(r1*DeltaTime) + c2*std::exp(r2*DeltaTime) + f/k;
880 angularvelocity = c1*r1*std::exp(r1*DeltaTime) + c2*r2*std::exp(r2*DeltaTime);
881 SOLVER_LOG(Log, "r1 %f, r2 %f, c1 %f, c2 %f, deltatheta %f", r1, r2, c1, c2, deltatheta);
882 }
883 else if (discriminant == 0)
884 {
885 double r = -b/2.f;
886 double c1 = theta0 - f/k;
887 double c2 = dtheta0 - c1*r;
888 deltatheta = (c1 + c2*DeltaTime)*std::exp(r*DeltaTime) + f/k;
889 angularvelocity = (c1*r + c2 + c2*r*DeltaTime)*std::exp(r*DeltaTime);
890 SOLVER_LOG(Log, "r %f, c1 %f, c2 %f, deltatheta %f", r, c1, c2, deltatheta);
891 }
892 else
893 {
894 double gamma = -b/2.f;
895 double mu = FMath::Sqrt(FMath::Abs(discriminant))/2.f;
896 double c1 = theta0 - f/k;
897 double c2 = (c1*gamma - dtheta0)/mu;
898 deltatheta =
899 c1*std::exp(gamma*DeltaTime)*std::cos(mu*DeltaTime) +
900 c2*std::exp(gamma*DeltaTime)*std::sin(mu*DeltaTime) + f/k;
901 angularvelocity =
902 c1*std::exp(gamma*DeltaTime)*(gamma*std::cos(mu*DeltaTime) + mu*std::sin(mu*DeltaTime)) +
903 c2*std::exp(gamma*DeltaTime)*(gamma*std::sin(mu*DeltaTime) - mu*std::cos(mu*DeltaTime));
904 SOLVER_LOG(Log, "gamma %f, mu %f, c1 %f, c2 %f, deltatheta %f", gamma, mu, c1, c2, deltatheta);
905 }
906 angularaccel = f - b*angularvelocity - k*deltatheta;
907 if (!FMath::IsNaN(deltatheta))
908 {
909 NewTheta(i) = deltatheta;
910 if (angularvelocity > 1e-4)
911 {
912 NewThetaVelocity(i) = angularvelocity;
913 }
914 if (angularaccel > 1e-2)
915 {
916 NewThetaAccel(i) = angularaccel;
917 }
918 }
919 }
920 Eigen::Vector3d FinalNewTheta = U*NewTheta;
921 Eigen::Vector3d FinalNewThetaVelocity = U*NewThetaVelocity;
922 Eigen::Vector3d FinalNewThetaAccel = U*NewThetaAccel;
923
924 auto NewPitch = FMath::RadiansToDegrees(FinalNewTheta(1));
925 auto NewYaw = FMath::RadiansToDegrees(FinalNewTheta(2));
926 auto NewRoll = FMath::RadiansToDegrees(FinalNewTheta(0));
927
928 FRotator NewAngularVelocity = EigenVectorToRotator(FinalNewThetaVelocity);
929 FRotator NewAngularAccel = EigenVectorToRotator(FinalNewThetaAccel);
930
931 FRotator NewAngle(
932 RestRotator.Pitch + NewPitch,
933 RestRotator.Yaw - NewYaw,
934 RestRotator.Roll + NewRoll);
935 SOLVER_LOG(Log, "FinalNewTheta \n %s \n FinalNewThetaVelocity \n %s \n FinalNewThetaAccel \n %s",
936 *EigenToFString(FinalNewTheta), *EigenToFString(FinalNewThetaVelocity), *EigenToFString(FinalNewThetaAccel));
937 SOLVER_LOG(Log, "New angle %s, new angular velocity %s, new angular accel %s",
938 *NewAngle.ToString(), *NewAngularVelocity.ToString(), *NewAngularAccel.ToString());
939 Joint.Transform.SetRotation(NewAngle.Quaternion());
940 Joint.AngularVelocity = NewAngularVelocity;
941 Joint.AngularAcceleration = NewAngularAccel;
942 }
943}
944
945void USpringBasedVegetationComponent::TickComponent(
946 float DeltaTime,
947 enum ELevelTick TickType,
948 FActorComponentTickFunction * ThisTickFunction)
949{
950 TRACE_CPUPROFILER_EVENT_SCOPE(USpringBasedVegetationComponent::TickComponent);
951 Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
952
953 float DeltaTimeFinal = DeltaTime;
954 if (DeltaTimeOverride > 0)
955 DeltaTimeFinal = DeltaTimeOverride;
956
957 std::vector<FJointProperties> JointPropertiesList;
958 JointPropertiesList.resize(Skeleton.Joints.Num());
959 std::vector<FJointProperties> JointLocalPropertiesList;
960 JointLocalPropertiesList.resize(Skeleton.Joints.Num());
961
962 ComputePerJointProperties(JointLocalPropertiesList, JointPropertiesList);
963
964 ResolveContactsAndCollisions(JointLocalPropertiesList, JointPropertiesList);
965
966 ComputeCompositeBodyContribution(JointLocalPropertiesList, JointPropertiesList);
967
968 ComputeFictitiousForces(JointLocalPropertiesList, JointPropertiesList);
969
970 SolveEquationOfMotion(JointPropertiesList, DeltaTimeFinal);
971
972 UpdateSkeletalMesh();
973 UpdateGlobalTransform();
974 Skeleton.ClearExternalForces();
975}
976
977void USpringBasedVegetationComponent::OnCollisionEvent(
978 UPrimitiveComponent* HitComponent,
979 AActor* OtherActor,
980 UPrimitiveComponent* OtherComponent,
981 FVector NormalImpulse,
982 const FHitResult& Hit)
983{
984 // prevent self collision
985 if (OtherActor == GetOwner())
986 return;
987 // prevent collision with other tree actors
988 if(OtherActor->GetComponentByClass(USpringBasedVegetationComponent::StaticClass()) != nullptr)
989 return;
990 ACarlaWheeledVehicle* Vehicle = nullptr;
991 if (DebugEnableAllCollisions)
992 {
993 if (!IsValid(OtherActor))
994 return;
995 }
996 else
997 {
998 Vehicle = Cast<ACarlaWheeledVehicle>(OtherActor);
999 if (!IsValid(Vehicle))
1000 return;
1001 }
1002 COLLISION_LOG(LogCarla, Log, TEXT("Collision with bone %s, with impulse %s"), *Hit.MyBoneName.ToString(), *NormalImpulse.ToString());
1003 Skeleton.AddForce(Hit.MyBoneName.ToString(), NormalImpulse);
1004}
1005
1006void USpringBasedVegetationComponent::OnBeginOverlapEvent(
1007 UPrimitiveComponent* OverlapComponent,
1008 AActor* OtherActor,
1009 UPrimitiveComponent* OtherComponent,
1010 int32 OtherBodyIndex,
1011 bool bFromSweep,
1012 const FHitResult& SweepResult)
1013{
1014 // prevent self collision
1015 if (OtherActor == GetOwner())
1016 return;
1017 // prevent collision with other tree actors
1018 if(OtherActor->GetComponentByClass(USpringBasedVegetationComponent::StaticClass()) != nullptr)
1019 return;
1020 ACarlaWheeledVehicle* Vehicle = nullptr;
1021 if (DebugEnableAllCollisions)
1022 {
1023 if (!IsValid(OtherActor))
1024 return;
1025 }
1026 else
1027 {
1028 Vehicle = Cast<ACarlaWheeledVehicle>(OtherActor);
1029 if (!IsValid(Vehicle))
1030 return;
1031 }
1032
1033 if (!OverlappingActors.Contains(OtherActor))
1034 {
1035 OverlappingActors.Add(OtherActor);
1036 }
1037 TArray<UPrimitiveComponent*>& OverlappingCapsules = OverlappingActors.FindOrAdd(OtherActor);
1038 if (!OverlappingCapsules.Contains(OverlapComponent))
1039 {
1040 OverlappingCapsules.Add(OverlapComponent);
1041 }
1042}
1043
1044void USpringBasedVegetationComponent::OnEndOverlapEvent(
1045 UPrimitiveComponent* OverlapComponent,
1046 AActor* OtherActor,
1047 UPrimitiveComponent* OtherComponent,
1048 int32 OtherBodyIndex)
1049{
1050 // prevent self collision
1051 if (OtherActor == GetOwner())
1052 return;
1053 // prevent collision with other tree actors
1054 if(OtherActor->GetComponentByClass(USpringBasedVegetationComponent::StaticClass()) != nullptr)
1055 return;
1056 ACarlaWheeledVehicle* Vehicle = nullptr;
1057 if (DebugEnableAllCollisions)
1058 {
1059 if (!IsValid(OtherActor))
1060 return;
1061 }
1062 else
1063 {
1064 Vehicle = Cast<ACarlaWheeledVehicle>(OtherActor);
1065 if (!IsValid(Vehicle))
1066 return;
1067 }
1068
1069 if (!OverlappingActors.Contains(OtherActor))
1070 return;
1071 TArray<UPrimitiveComponent*>& OverlappingCapsules = OverlappingActors.FindOrAdd(OtherActor);
1072 if (OverlappingCapsules.Contains(OverlapComponent))
1073 {
1074 OverlappingCapsules.RemoveSingle(OverlapComponent);
1075 if (OverlappingCapsules.Num() == 0)
1076 {
1077 OverlappingActors.Remove(OtherActor);
1078 }
1079 }
1080}
1081
1082void USpringBasedVegetationComponent::UpdateSkeletalMesh()
1083{
1084 TRACE_CPUPROFILER_EVENT_SCOPE(USpringBasedVegetationComponent::UpdateSkeletalMesh);
1085 // get the walker animation class
1086 auto *AnimInst = SkeletalMesh->GetAnimInstance();
1087 if (!AnimInst) return;
1088 UWalkerAnim *WalkerAnim = Cast<UWalkerAnim>(AnimInst);
1089 if (!WalkerAnim) return;
1090
1091 // if pose is empty, then get a first version
1092 if (WalkerAnim->Snap.BoneNames.Num() == 0)
1093 {
1094 // get current pose
1095 SkeletalMesh->SnapshotPose(WalkerAnim->Snap);
1096 }
1097
1098 TMap<FName, FTransform> JointsMap;
1099 for (int i=0; i<Skeleton.Joints.Num(); ++i)
1100 {
1101 FSkeletonJoint& Joint = Skeleton.Joints[i];
1102 FName JointName = FName(*Joint.JointName);
1103 JointsMap.Add(JointName, Joint.Transform);
1104 }
1105
1106 // assign common bones
1107 for (int i=0; i<WalkerAnim->Snap.BoneNames.Num(); ++i)
1108 {
1109 FTransform *Trans = JointsMap.Find(WalkerAnim->Snap.BoneNames[i]);
1110 if (Trans)
1111 {
1112 WalkerAnim->Snap.LocalTransforms[i] = *Trans;
1113 }
1114 }
1115}
1116
1117void USpringBasedVegetationComponent::UpdateGlobalTransform()
1118{
1119 TRACE_CPUPROFILER_EVENT_SCOPE(USpringBasedVegetationComponent::UpdateGlobalTransform);
1120 FTransform InitialTransform = SkeletalMesh->GetOwner()->GetActorTransform();
1121 FSkeletonJoint& RootJoint = Skeleton.Joints[0];
1122 RootJoint.GlobalTransform = RootJoint.Transform * InitialTransform;
1123 RootJoint.GolbalInverseTransform = RootJoint.GlobalTransform.Inverse();
1124 for (int i = 1; i < Skeleton.RootToEndOrder.Num(); i++)
1125 {
1126 int Id = Skeleton.RootToEndOrder[i];
1127 FSkeletonJoint& Joint = Skeleton.Joints[Id];
1128 FSkeletonJoint& ParentJoint = Skeleton.Joints[Joint.ParentId];
1129 FTransform Transform = Joint.Transform * ParentJoint.GlobalTransform;
1130 Joint.GlobalTransform = Transform;
1131 Joint.GolbalInverseTransform = Transform.Inverse();
1132 }
1133}
static Eigen::Vector3d ToEigenVector(const FVector &V1)
#define SOLVER_LOG(...)
static FVector ToUnrealVector(const Eigen::Vector3d &V1)
static Eigen::Matrix3d OuterProduct(const Eigen::Vector3d &V1, const Eigen::Vector3d &V2)
#define COLLISION_LOG(...)
static FRotator EigenVectorToRotator(const Eigen::Vector3d &Vector)
#define OTHER_LOG(...)
FRotator GetDeltaRotator(const FRotator &Rotator1, const FRotator &Rotator2)
static Eigen::Matrix3d ToEigenMatrix(const FMatrix &Matrix)
#define ACC_LOG(...)
static T GetSign(T n)
static FString EigenToFString(T &t)
#define FICT_LOG(...)
static Eigen::Vector3d RotatorToEigenVector(const FRotator &Rotator)
static bool IsValid(const ACarlaWheeledVehicle *Vehicle)
Base class for CARLA wheeled vehicles.
FPoseSnapshot Snap
Definition WalkerAnim.h:25
geom::Transform Transform
void AddForce(const FString &BoneName, const FVector &Force)
TArray< FSkeletonJoint > Joints
TArray< FSkeletonBone > Bones