CARLA
 
载入中...
搜索中...
未找到
VegetationManager.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
7#include "ProceduralFoliageVolume.h"
8#include "ProceduralFoliageComponent.h"
9
14
15static FString GetVersionFromFString(const FString& String)
16{
17 TRACE_CPUPROFILER_EVENT_SCOPE(GetVersionFromFString);
18 auto IsDigit = [](TCHAR charToCheck) {
19 if (charToCheck == TCHAR('0')) return true;
20 if (charToCheck == TCHAR('1')) return true;
21 if (charToCheck == TCHAR('2')) return true;
22 if (charToCheck == TCHAR('3')) return true;
23 if (charToCheck == TCHAR('4')) return true;
24 if (charToCheck == TCHAR('5')) return true;
25 if (charToCheck == TCHAR('6')) return true;
26 if (charToCheck == TCHAR('7')) return true;
27 if (charToCheck == TCHAR('8')) return true;
28 if (charToCheck == TCHAR('9')) return true;
29 return false;
30 };
31 int index = String.Find(TEXT("_v"));
32 if (index != -1)
33 {
34 index += 2;
35 FString Version = "_v";
36 while(IsDigit(String[index]))
37 {
38 Version += String[index];
39 ++index;
40 if (index == String.Len())
41 return Version;
42 }
43 return Version;
44 }
45 return FString();
46}
47
51
52/********************************************************************************/
53/********** POOLED ACTOR STRUCT *************************************************/
54/********************************************************************************/
55void FPooledActor::EnableActor(const FTransform& Transform, int32 NewIndex, std::shared_ptr<FTileMeshComponent>& NewTileMeshComponent)
56{
57 TRACE_CPUPROFILER_EVENT_SCOPE(FPooledActor::EnableActor);
58 InUse = true;
59 IsActive = false;
60 GlobalTransform = Transform;
61 Index = NewIndex;
62 TileMeshComponent = NewTileMeshComponent;
63 TileMeshComponent->IndicesInUse.Emplace(Index);
64
65 Actor->SetActorHiddenInGame(false);
66 Actor->SetActorTickEnabled(true);
67
68 USpringBasedVegetationComponent* Component = Actor->FindComponentByClass<USpringBasedVegetationComponent>();
69 if (Component)
70 {
71 Component->ResetComponent();
72 }
73}
74
76{
77 TRACE_CPUPROFILER_EVENT_SCOPE(FPooledActor::ActiveActor);
78
79 IsActive = true;
80 Actor->SetActorEnableCollision(true);
81
82 USpringBasedVegetationComponent* Component = Actor->FindComponentByClass<USpringBasedVegetationComponent>();
83 if (Component)
84 {
85 Component->SetComponentTickEnabled(true);
86 }
87
88 USkeletalMeshComponent* SkeletalMesh = Actor->FindComponentByClass<USkeletalMeshComponent>();
89 if (SkeletalMesh)
90 {
91 SkeletalMesh->bNoSkeletonUpdate = false;
92 }
93}
94
96{
97 TRACE_CPUPROFILER_EVENT_SCOPE(FPooledActor::DisableActor);
98
100 {
101 if (TileMeshComponent->bIsAlive)
102 {
103 if (TileMeshComponent->IndicesInUse.Contains(Index))
104 {
105 TileMeshComponent->IndicesInUse.RemoveSingle(Index);
106 }
107 }
108 }
109
110 InUse = false;
111 IsActive = false;
112 Index = -1;
113 TileMeshComponent = nullptr;
114
115 Actor->SetActorEnableCollision(false);
116 Actor->SetActorHiddenInGame(true);
117 Actor->SetActorTickEnabled(false);
118
119 USpringBasedVegetationComponent* Component = Actor->FindComponentByClass<USpringBasedVegetationComponent>();
120 if (Component)
121 {
122 Component->SetComponentTickEnabled(false);
123 }
124
125 USkeletalMeshComponent* SkeletalMesh = Actor->FindComponentByClass<USkeletalMeshComponent>();
126 if (SkeletalMesh)
127 {
128 SkeletalMesh->bNoSkeletonUpdate = true;
129 }
130}
131
132/********************************************************************************/
133/********** FOLIAGE BLUEPRINT STRUCT ********************************************/
134/********************************************************************************/
136{
137 if (BPFullClassName.IsEmpty() || !BPFullClassName.Contains("_C"))
138 return false;
139 return SpawnedClass != nullptr;
140}
141
142bool FFoliageBlueprint::SetBPClassName(const FString& Path)
143{
144 TRACE_CPUPROFILER_EVENT_SCOPE(FoliageBlueprintCache::SetBPClassName);
145 if (Path.IsEmpty())
146 return false;
147 TArray< FString > ParsedString;
148 Path.ParseIntoArray(ParsedString, TEXT("/"), false);
149 int Position = ParsedString.Num() - 1;
150 const FString FullVersion = GetVersionFromFString(ParsedString[Position]);
151 const FString Folder = ParsedString[--Position];
152 const FString BPClassName = "BP_" + Folder + FullVersion;
153 BPFullClassName = "Blueprint'";
154 for (int i = 0; i <= Position; ++i)
155 {
156 BPFullClassName += ParsedString[i];
157 BPFullClassName += '/';
158 }
159 BPFullClassName += BPClassName;
160 BPFullClassName += ".";
161 BPFullClassName += BPClassName;
162 BPFullClassName += "_C'";
163 return true;
164}
165
167{
168 TRACE_CPUPROFILER_EVENT_SCOPE(FoliageBlueprintCache::SetSpawnedClass);
169 UClass* CastedBlueprint = LoadObject< UClass >(nullptr, *BPFullClassName);
170 if (CastedBlueprint)
171 {
172 SpawnedClass = CastedBlueprint;
173 return true;
174 }
175 SpawnedClass = nullptr;
176 return false;
177}
178
179/********************************************************************************/
180/********** TILE DATA STRUCT ****************************************************/
181/********************************************************************************/
182void FTileData::UpdateTileMeshComponent(UInstancedStaticMeshComponent* NewInstancedStaticMeshComponent)
183{
184 UInstancedStaticMeshComponent* Aux { nullptr };
185 for (std::shared_ptr<FTileMeshComponent>& ElementPtr
187 {
188 FTileMeshComponent& Element = *ElementPtr;
189 if (Element.InstancedStaticMeshComponent == NewInstancedStaticMeshComponent)
190 {
191 int32 CurrentCount = Element.InstancedStaticMeshComponent->GetInstanceCount();
192 int32 NewCount = NewInstancedStaticMeshComponent->GetInstanceCount();
193 Element.bIsAlive = true;
194 if (NewCount > CurrentCount)
195 {
196 Element.InstancedStaticMeshComponent = NewInstancedStaticMeshComponent;
197 Element.IndicesInUse.Empty();
198 }
199 }
200 }
201}
202
203bool FTileData::ContainsMesh(const UInstancedStaticMeshComponent* Mesh) const
204{
205 for (const std::shared_ptr<FTileMeshComponent>& Element
207 {
208 if (Element->InstancedStaticMeshComponent == Mesh)
209 return true;
210 }
211 return false;
212}
213
214void FTileData::UpdateMaterialCache(const FLinearColor& Value, bool DebugMaterials)
215{
216 TRACE_CPUPROFILER_EVENT_SCOPE(FTileData::UpdateMaterialCache);
217 for (UMaterialInstanceDynamic* Material : MaterialInstanceDynamicCache)
218 {
219 if (DebugMaterials)
220 Material->SetScalarParameterValue("ActivateDebug", 1);
221 else
222 Material->SetScalarParameterValue("ActivateDebug", 0);
223 Material->SetScalarParameterValue("ActivateOpacity", 1);
224 Material->SetVectorParameterValue("VehiclePosition", Value);
225 }
226}
227
228/********************************************************************************/
229/********** OVERRIDE FROM ACTOR *************************************************/
230/********************************************************************************/
232{
233 TRACE_CPUPROFILER_EVENT_SCOPE(AVegetationManager::BeginPlay);
234 Super::BeginPlay();
236 FWorldDelegates::LevelAddedToWorld.AddUObject(this, &AVegetationManager::OnLevelAddedToWorld);
237 FWorldDelegates::LevelRemovedFromWorld.AddUObject(this, &AVegetationManager::OnLevelRemovedFromWorld);
238 FCoreDelegates::PostWorldOriginOffset.AddUObject(this, &AVegetationManager::PostWorldOriginOffset);
239}
240
241void AVegetationManager::Tick(float DeltaTime)
242{
243 TRACE_CPUPROFILER_EVENT_SCOPE(AVegetationManager::Tick);
244 {
245 TRACE_CPUPROFILER_EVENT_SCOPE(Parent Tick);
246 Super::Tick(DeltaTime);
247 }
248 if (!LargeMap)
249 return;
251 if (!IsValid(HeroVehicle))
252 return;
253
255 TArray<FString> TilesInUse = GetTilesInUse();
256 if (TilesInUse.Num() == 0)
257 {
258 UE_LOG(LogCarla, Warning, TEXT("No tiles detected."));
259 return;
260 }
261
262 for (const FString& TileName : TilesInUse)
263 {
264 FTileData* Tile = TileCache.Find(TileName);
265 if (!Tile)
266 continue;
267 UpdateMaterials(Tile);
268 TArray<FElementsToSpawn> ElementsToSpawn = GetElementsToSpawn(Tile);
269 SpawnSkeletalFoliages(ElementsToSpawn);
272 }
273
274}
275
276/********************************************************************************/
277/********** VEHICLE *************************************************************/
278/********************************************************************************/
280{
281 TRACE_CPUPROFILER_EVENT_SCOPE(AVegetationManager::AddVehicle);
282 if (!IsValid(Vehicle))
283 return;
285 UE_LOG(LogCarla, Display, TEXT("Vehicle added."));
286}
287
289{
290 TRACE_CPUPROFILER_EVENT_SCOPE(AVegetationManager::RemoveVehicle);
291 if (!IsValid(Vehicle))
292 return;
293 HeroVehicle = nullptr;
294 UE_LOG(LogCarla, Display, TEXT("Vehicle removed."));
295}
296
297/********************************************************************************/
298/********** CACHES **************************************************************/
299/********************************************************************************/
301{
302 TRACE_CPUPROFILER_EVENT_SCOPE(AVegetationManager::CreateOrUpdateTileCache);
303 FTileData TileData {};
304 for (AActor* Actor : InLevel->Actors)
305 {
306 AInstancedFoliageActor* InstancedFoliageActor = Cast<AInstancedFoliageActor>(Actor);
307 if (!IsValid(InstancedFoliageActor))
308 continue;
309 TileData.InstancedFoliageActor = InstancedFoliageActor;
310 break;
311 }
312 if (!IsValid(TileData.InstancedFoliageActor))
313 return;
314
315 for (AActor* Actor : InLevel->Actors)
316 {
317 AProceduralFoliageVolume* ProceduralFoliageVolume = Cast<AProceduralFoliageVolume>(Actor);
318 if (!IsValid(ProceduralFoliageVolume))
319 continue;
320 TileData.ProceduralFoliageVolume = ProceduralFoliageVolume;
321 break;
322 }
323 if (!IsValid(TileData.ProceduralFoliageVolume))
324 return;
325
326 const FString TileName = TileData.InstancedFoliageActor->GetLevel()->GetOuter()->GetName();
327 FTileData* ExistingTileData = TileCache.Find(TileName);
328 if (ExistingTileData)
329 {
330 ExistingTileData->InstancedFoliageActor = TileData.InstancedFoliageActor;
331 ExistingTileData->ProceduralFoliageVolume = TileData.ProceduralFoliageVolume;
332 ExistingTileData->TileMeshesCache.Empty();
333 ExistingTileData->MaterialInstanceDynamicCache.Empty();
334 SetTileDataInternals(*ExistingTileData);
335 }
336 else
337 {
338 SetTileDataInternals(TileData);
339 TileCache.Emplace(TileName, TileData);
340 }
341}
342
344{
345 TRACE_CPUPROFILER_EVENT_SCOPE(AVegetationManager::SetTileDataInternals);
347 SetMaterialCache(TileData);
348}
349
351{
353 const TSet<UActorComponent*>& ActorComponents = TileData.InstancedFoliageActor->GetComponents();
354 for (UActorComponent* Component : ActorComponents)
355 {
356 UInstancedStaticMeshComponent* Mesh = Cast<UInstancedStaticMeshComponent>(Component);
357 if (!IsValid(Mesh))
358 continue;
359 const FString Path = Mesh->GetStaticMesh()->GetPathName();
360 const FFoliageBlueprint* BPCache = FoliageBlueprintCache.Find(Path);
361 if (!BPCache)
362 continue;
363
364 if (TileData.ContainsMesh(Mesh))
365 {
366 TileData.UpdateTileMeshComponent(Mesh);
367 }
368 else
369 {
370 std::shared_ptr<FTileMeshComponent> Aux =
371 std::make_shared<FTileMeshComponent>();
372 Aux->InstancedStaticMeshComponent = Mesh;
373 Aux->bIsAlive = true;
374 TileData.TileMeshesCache.Emplace(Aux);
375 }
376 }
377}
378
380{
381 TRACE_CPUPROFILER_EVENT_SCOPE(AVegetationManager::SetMaterialCache);
382 if (TileData.MaterialInstanceDynamicCache.Num() > 0)
383 TileData.MaterialInstanceDynamicCache.Empty();
384
385 for (std::shared_ptr<FTileMeshComponent>& ElementPtr
386 : TileData.TileMeshesCache)
387 {
388 FTileMeshComponent& Element = *ElementPtr;
389 UInstancedStaticMeshComponent* Mesh = Element.InstancedStaticMeshComponent;
390 if (!IsValid(Mesh))
391 continue;
392 int32 Index = -1;
393 for (UMaterialInterface* Material : Mesh->GetMaterials())
394 {
395 ++Index;
396 if (!IsValid(Material))
397 continue;
398 UMaterialInstanceDynamic* MaterialInstanceDynamic = UMaterialInstanceDynamic::Create(Material, this);
399 if (!MaterialInstanceDynamic)
400 continue;
401 if (TileData.MaterialInstanceDynamicCache.Contains(MaterialInstanceDynamic))
402 continue;
403 MaterialInstanceDynamic->SetScalarParameterValue("ActivateOpacity", 0);
404 MaterialInstanceDynamic->SetScalarParameterValue("ActivateDebug", 0);
405 MaterialInstanceDynamic->SetScalarParameterValue("Distance", HideMaterialDistance);
406 Mesh->SetMaterial(Index, MaterialInstanceDynamic);
407 TileData.MaterialInstanceDynamicCache.Emplace(MaterialInstanceDynamic);
408 }
409 }
410}
411
413{
414 TRACE_CPUPROFILER_EVENT_SCOPE(AVegetationManager::UpdateFoliageBlueprintCache);
415 for (AActor* Actor : InLevel->Actors)
416 {
417 AInstancedFoliageActor* InstancedFoliageActor = Cast<AInstancedFoliageActor>(Actor);
418 if (!IsValid(InstancedFoliageActor))
419 continue;
420 const FString TileName = InstancedFoliageActor->GetLevel()->GetOuter()->GetName();
421 const TSet<UActorComponent*>& ActorComponents = InstancedFoliageActor->GetComponents();
422 for (UActorComponent* Component : ActorComponents)
423 {
424 UInstancedStaticMeshComponent* Mesh = Cast<UInstancedStaticMeshComponent>(Component);
425 if (!IsValid(Mesh))
426 continue;
427 const FString Path = Mesh->GetStaticMesh()->GetPathName();
428 if (!IsFoliageTypeEnabled(Path))
429 continue;
430 if (FoliageBlueprintCache.Contains(Path))
431 continue;
432 FFoliageBlueprint NewFoliageBlueprint;
433 NewFoliageBlueprint.SetBPClassName(Path);
434 NewFoliageBlueprint.SetSpawnedClass();
435
436 if (!NewFoliageBlueprint.IsValid())
437 {
438 UE_LOG(LogCarla, Warning, TEXT("Blueprint %s was invalid."), *NewFoliageBlueprint.BPFullClassName);
439 }
440 else
441 {
442 UE_LOG(LogCarla, Display, TEXT("Blueprint %s created."), *NewFoliageBlueprint.BPFullClassName);
443 FoliageBlueprintCache.Emplace(Path, NewFoliageBlueprint);
444 CreatePoolForBPClass(NewFoliageBlueprint);
445 }
446 }
447 }
448}
449
451{
452 if (!IsValid(InLevel))
453 return;
454 AInstancedFoliageActor* TileInstancedFoliageActor = nullptr;
455 for (AActor* Actor : InLevel->Actors)
456 {
457 if (!IsValid(Actor))
458 continue;
459 AInstancedFoliageActor* InstancedFoliageActor = Cast<AInstancedFoliageActor>(Actor);
460 if (!IsValid(InstancedFoliageActor))
461 continue;
462 TileInstancedFoliageActor = InstancedFoliageActor;
463 break;
464 }
465 if (!IsValid(TileInstancedFoliageActor))
466 return;
467 const FString TileName = TileInstancedFoliageActor->GetLevel()->GetOuter()->GetName();
468 FTileData* ExistingTileData = TileCache.Find(TileName);
469 if (ExistingTileData)
470 {
471
472 ExistingTileData->MaterialInstanceDynamicCache.Empty();
473 for (std::shared_ptr<FTileMeshComponent>& Element
474 : ExistingTileData->TileMeshesCache)
475 {
476 Element->IndicesInUse.Empty();
477 Element->bIsAlive = false;
478 }
479 ExistingTileData->TileMeshesCache.Empty();
480 ExistingTileData->InstancedFoliageActor = nullptr;
481 ExistingTileData->ProceduralFoliageVolume = nullptr;
482
483 TileCache.Remove(TileName);
484 }
485}
486
487/********************************************************************************/
488/********** TICK ****************************************************************/
489/********************************************************************************/
491{
492 TRACE_CPUPROFILER_EVENT_SCOPE(AVegetationManager::UpdateMaterials);
493 const FTransform GlobalTransform = HeroVehicle->GetActorTransform();
494 const FLinearColor Position = GlobalTransform.GetLocation();
496}
497
499{
500 TRACE_CPUPROFILER_EVENT_SCOPE(AVegetationManager::GetElementsToSpawn);
501 TArray<FElementsToSpawn> Results;
502 int32 i = -1;
503
504 for (std::shared_ptr<FTileMeshComponent>& ElementPtr
505 : Tile->TileMeshesCache)
506 {
507 FTileMeshComponent& Element = *ElementPtr;
508 TRACE_CPUPROFILER_EVENT_SCOPE(Update Foliage Usage);
509 ++i;
510 UInstancedStaticMeshComponent* InstancedStaticMeshComponent = Element.InstancedStaticMeshComponent;
511 const FString Path = InstancedStaticMeshComponent->GetStaticMesh()->GetPathName();
513 if (!BP)
514 continue;
515 TArray<int32> Indices = HeroVehicle->GetFoliageInstancesCloseToVehicle(InstancedStaticMeshComponent);
516 if (Indices.Num() == 0)
517 continue;
518 TArray<int32> NewIndices;
519 for (int32 Index : Indices)
520 {
521 if (Element.IndicesInUse.Contains(Index))
522 {
523 continue;
524 }
525 NewIndices.Emplace(Index);
526 }
527
528 FElementsToSpawn NewElement {};
529 NewElement.TileMeshComponent = Tile->TileMeshesCache[i];
530 NewElement.BP = *BP;
531 for (int32 Index : NewIndices)
532 {
533 FTransform Transform;
534 InstancedStaticMeshComponent->GetInstanceTransform(Index, Transform, true);
535 NewElement.TransformIndex.Emplace(TPair<FTransform, int32>(Transform, Index));
536 }
537 if (NewElement.TransformIndex.Num() > 0)
538 Results.Emplace(NewElement);
539 }
540 return Results;
541}
542
543void AVegetationManager::SpawnSkeletalFoliages(TArray<FElementsToSpawn>& ElementsToSpawn)
544{
545 TRACE_CPUPROFILER_EVENT_SCOPE(AVegetationManager::SpawnSkeletalFoliages);
546 const FTransform HeroTransform = HeroVehicle->GetActorTransform();
547 const FVector HeroLocation = HeroTransform.GetLocation();
548 const float HeroDetectionSizeSquared = HeroVehicle->GetDetectionSize() * HeroVehicle->GetDetectionSize();
549
550 for (FElementsToSpawn& Element : ElementsToSpawn)
551 {
552 TArray<FPooledActor>* Pool = ActorPool.Find(Element.BP.BPFullClassName);
553
554 if (Pool == nullptr)
555 {
556 UE_LOG(LogCarla, Error, TEXT("Pool not valid"));
557 continue;
558 }
559 for (const TPair<FTransform, int32>& TransformIndex : Element.TransformIndex)
560 {
561 const FTransform& Transform = TransformIndex.Key;
562 int32 Index = TransformIndex.Value;
563 if (Element.TileMeshComponent->IndicesInUse.Contains(Index))
564 {
565 continue;
566 }
567 const float Distance = FMath::Abs(FVector::DistSquared(Transform.GetLocation(), HeroLocation));
568 if (Distance > HeroDetectionSizeSquared)
569 {
570 continue;
571 }
572 bool Ok = EnableActorFromPool(Transform, Index, Element.TileMeshComponent, *Pool);
573 if (Ok)
574 {
575 }
576 else
577 {
578 FPooledActor NewElement;
579 NewElement.Actor = CreateFoliage(Element.BP, {});
580 if (IsValid(NewElement.Actor))
581 {
582 NewElement.Actor->SetTickableWhenPaused(false);
583 NewElement.EnableActor(Transform, Index, Element.TileMeshComponent);
584 Pool->Emplace(NewElement);
585 }
586 }
587 }
588 }
589}
590
592{
593 TRACE_CPUPROFILER_EVENT_SCOPE(AVegetationManager::ActivePooledActors);
594 const FTransform HeroTransform = HeroVehicle->GetActorTransform();
595 const FVector HeroLocation = HeroTransform.GetLocation();
596 const float SquaredActiveActorDistance = ActiveActorDistance * ActiveActorDistance;
597
598 for (TPair<FString, TArray<FPooledActor>>& Element : ActorPool)
599 {
600 TArray<FPooledActor>& Pool = Element.Value;
601 for (FPooledActor& Actor : Pool)
602 {
603 if (!Actor.InUse)
604 continue;
605 if (Actor.IsActive)
606 continue;
607 const FVector Location = Actor.GlobalTransform.GetLocation();
608 const float Distance = FMath::Abs(FVector::DistSquared(Location, HeroLocation));
609 if (Distance < SquaredActiveActorDistance)
610 {
611 Actor.ActiveActor();
612 }
613 }
614 }
615}
616
618{
619 TRACE_CPUPROFILER_EVENT_SCOPE(AVegetationManager::DestroySkeletalFoliages);
620 const FTransform HeroTransform = HeroVehicle->GetActorTransform();
621 const FVector HeroLocation = HeroTransform.GetLocation();
622 const float HeroDetectionSizeSquared = HeroVehicle->GetDetectionSize() * HeroVehicle->GetDetectionSize();
623
624 for (TPair<FString, TArray<FPooledActor>>& Element : ActorPool)
625 {
626 TArray<FPooledActor>& Pool = Element.Value;
627 for (FPooledActor& Actor : Pool)
628 {
629 if (!Actor.InUse)
630 continue;
631 const FVector Location = Actor.GlobalTransform.GetLocation();
632 const float Distance = FMath::Abs(FVector::DistSquared(Location, HeroLocation));
633 if (Distance > HeroDetectionSizeSquared)
634 {
635 Actor.DisableActor();
636 }
637 }
638 }
639}
640
642 const FTransform& Transform,
643 int32 Index,
644 std::shared_ptr<FTileMeshComponent>& TileMeshComponent,
645 TArray<FPooledActor>& Pool)
646{
647 TRACE_CPUPROFILER_EVENT_SCOPE(AVegetationManager::EnableActorFromPool);
648 for (FPooledActor& PooledActor : Pool)
649 {
650 if (PooledActor.InUse)
651 continue;
652 PooledActor.EnableActor(Transform, Index, TileMeshComponent);
653 PooledActor.Actor->SetActorLocationAndRotation(Transform.GetLocation(), Transform.Rotator(), true, nullptr, ETeleportType::ResetPhysics);
654 if (SpawnScale <= 1.01f && SpawnScale >= 0.99f)
655 PooledActor.Actor->SetActorScale3D(Transform.GetScale3D());
656 else
657 PooledActor.Actor->SetActorScale3D({SpawnScale, SpawnScale, SpawnScale});
658 return true;
659 }
660 return false;
661}
662
663/********************************************************************************/
664/********** POOLS ***************************************************************/
665/********************************************************************************/
667{
668 TRACE_CPUPROFILER_EVENT_SCOPE(AVegetationManager::CreatePoolForBPClass);
669 TArray<FPooledActor> AuxPool;
670 const FTransform Transform {};
671 for (int32 i = 0; i < InitialPoolSize; ++i)
672 {
673 FPooledActor NewElement;
674 NewElement.Actor = CreateFoliage(BP, Transform);
675 if (IsValid(NewElement.Actor))
676 {
677 UE_LOG(LogCarla, Display, TEXT("Created actor for pool"));
678 NewElement.Actor->SetTickableWhenPaused(false);
679 NewElement.DisableActor();
680 AuxPool.Emplace(NewElement);
681 }
682 else
683 {
684 UE_LOG(LogCarla, Error, TEXT("Failed to create actor for pool"));
685 }
686 }
687 ActorPool.Emplace(BP.BPFullClassName, AuxPool);
688 UE_LOG(LogCarla, Display, TEXT("CreatePoolForBPClass: %s"), *BP.BPFullClassName);
689}
690
691AActor* AVegetationManager::CreateFoliage(const FFoliageBlueprint& BP, const FTransform& Transform) const
692{
693 TRACE_CPUPROFILER_EVENT_SCOPE(AVegetationManager::CreateFoliage);
694
695 AActor* Actor = GetWorld()->SpawnActor<AActor>(BP.SpawnedClass,
696 Transform.GetLocation(), Transform.Rotator());
697
698 TArray<UTaggedComponent*> TaggedComponents;
699 Actor->GetComponents(TaggedComponents);
700 for (UTaggedComponent* Component: TaggedComponents)
701 {
702 Component->DestroyComponent();
703 }
704
705 if (SpawnScale <= 1.01f && SpawnScale >= 0.99f)
706 Actor->SetActorScale3D(Transform.GetScale3D());
707 else
708 Actor->SetActorScale3D({SpawnScale, SpawnScale, SpawnScale});
709 return Actor;
710}
711
713{
714 TRACE_CPUPROFILER_EVENT_SCOPE(AVegetationManager::UpdatePoolBasePosition);
715 for (TPair<FString, TArray<FPooledActor>>& Element : ActorPool)
716 {
717 TArray<FPooledActor>& Pool = Element.Value;
718 for (FPooledActor& PooledActor : Pool)
719 {
720 if (PooledActor.InUse)
721 continue;
722 PooledActor.Actor->SetActorTransform(InactivePoolTransform, true, nullptr, ETeleportType::ResetPhysics);
723 }
724 }
725}
726
727/********************************************************************************/
728/********** EVENTS **************************************************************/
729/********************************************************************************/
730void AVegetationManager::OnLevelAddedToWorld(ULevel* InLevel, UWorld* InWorld)
731{
732 TRACE_CPUPROFILER_EVENT_SCOPE(AVegetationManager::OnLevelAddedToWorld);
735}
736
737void AVegetationManager::OnLevelRemovedFromWorld(ULevel* InLevel, UWorld* InWorld)
738{
739 TRACE_CPUPROFILER_EVENT_SCOPE(AVegetationManager::OnLevelRemovedFromWorld);
740 FreeTileCache(InLevel);
741}
742
743void AVegetationManager::PostWorldOriginOffset(UWorld*, FIntVector, FIntVector)
744{
745 TRACE_CPUPROFILER_EVENT_SCOPE(AVegetationManager::PostWorldOriginOffset);
746 InactivePoolTransform.SetLocation(FVector(0.0f, 0.0f, 0.0f));
748}
749
750/********************************************************************************/
751/********** TILES ***************************************************************/
752/********************************************************************************/
753bool AVegetationManager::IsFoliageTypeEnabled(const FString& Path) const
754{
755 TRACE_CPUPROFILER_EVENT_SCOPE(AVegetationManager::IsFoliageTypeEnabled);
756 if (!SpawnRocks)
757 if (Path.Contains("/Rock"))
758 return false;
759 if (!SpawnTrees)
760 if (Path.Contains("/Tree"))
761 return false;
762 if (!SpawnBushes)
763 if (Path.Contains("/Bush"))
764 return false;
765 if (!SpawnPlants)
766 if (Path.Contains("/Plant"))
767 return false;
768 return true;
769}
770
772{
773 TRACE_CPUPROFILER_EVENT_SCOPE(AVegetationManager::CheckForNewTiles);
774 const UObject* World = GetWorld();
775 TArray<AActor*> ActorsInLevel;
776 UGameplayStatics::GetAllActorsOfClass(World, AInstancedFoliageActor::StaticClass(), ActorsInLevel);
777 for (AActor* Actor : ActorsInLevel)
778 {
779 AInstancedFoliageActor* InstancedFoliageActor = Cast<AInstancedFoliageActor>(Actor);
780 if (!IsValid(InstancedFoliageActor))
781 continue;
782 const FString TileName = InstancedFoliageActor->GetLevel()->GetOuter()->GetName();
783 if (!TileCache.Contains(TileName))
784 return true;
785 }
786 return false;
787}
788
790{
791 TRACE_CPUPROFILER_EVENT_SCOPE(AVegetationManager::GetTilesInUse);
792 TArray<FString> Results;
793
794 for (const TPair<FString, FTileData>& Element : TileCache)
795 {
796 const FTileData& TileData = Element.Value;
798 {
799 TileCache.Remove(Element.Key);
800 return Results;
801 }
802 if (Results.Contains(Element.Key))
803 continue;
804 const AProceduralFoliageVolume* Procedural = TileData.ProceduralFoliageVolume;
805 if (!IsValid(Procedural))
806 continue;
807 if (!IsValid(Procedural->ProceduralComponent))
808 continue;
809 const FBox Box = Procedural->ProceduralComponent->GetBounds();
810 if (!Box.IsValid)
811 continue;
812 if (Box.IsInside(HeroVehicle->GetActorTransform().GetLocation()))
813 Results.Emplace(Element.Key);
814 }
815 return Results;
816}
static bool IsValid(const ACarlaWheeledVehicle *Vehicle)
static FString GetVersionFromFString(const FString &String)
Base class for CARLA wheeled vehicles.
const TArray< int32 > GetFoliageInstancesCloseToVehicle(const UInstancedStaticMeshComponent *Component) const
ACarlaWheeledVehicle * GetHeroVehicle()
TMap< FString, FTileData > TileCache
FTransform InactivePoolTransform
AActor * CreateFoliage(const FFoliageBlueprint &BP, const FTransform &Transform) const
void SpawnSkeletalFoliages(TArray< FElementsToSpawn > &ElementsToSpawn)
ACarlaWheeledVehicle * HeroVehicle
void SetInstancedStaticMeshComponentCache(FTileData &TileData)
void UpdateFoliageBlueprintCache(ULevel *InLevel)
TArray< FElementsToSpawn > GetElementsToSpawn(FTileData *Tile)
void SetMaterialCache(FTileData &TileData)
bool EnableActorFromPool(const FTransform &Transform, int32 Index, std::shared_ptr< FTileMeshComponent > &TileMeshComponent, TArray< FPooledActor > &Pool)
void AddVehicle(ACarlaWheeledVehicle *Vehicle)
ALargeMapManager * LargeMap
void FreeTileCache(ULevel *InLevel)
bool IsFoliageTypeEnabled(const FString &Path) const
void RemoveVehicle(ACarlaWheeledVehicle *Vehicle)
void CreateOrUpdateTileCache(ULevel *InLevel)
void UpdateMaterials(FTileData *Tile)
void CreatePoolForBPClass(const FFoliageBlueprint &BP)
TMap< FString, FFoliageBlueprint > FoliageBlueprintCache
void PostWorldOriginOffset(UWorld *, FIntVector, FIntVector InDstOrigin)
void OnLevelAddedToWorld(ULevel *InLevel, UWorld *InWorld)
void OnLevelRemovedFromWorld(ULevel *InLevel, UWorld *InWorld)
virtual void BeginPlay() override
virtual void Tick(float DeltaTime) override
TMap< FString, TArray< FPooledActor > > ActorPool
TArray< FString > GetTilesInUse()
void SetTileDataInternals(FTileData &TileData)
static ALargeMapManager * GetLargeMapManager(const UObject *WorldContextObject)
std::shared_ptr< FTileMeshComponent > TileMeshComponent
bool SetBPClassName(const FString &Path)
TSubclassOf< AActor > SpawnedClass
FTransform GlobalTransform
void EnableActor(const FTransform &Transform, int32 NewIndex, std::shared_ptr< FTileMeshComponent > &NewTileMeshComponent)
std::shared_ptr< FTileMeshComponent > TileMeshComponent
bool ContainsMesh(const UInstancedStaticMeshComponent *) const
TArray< std::shared_ptr< FTileMeshComponent > > TileMeshesCache
AProceduralFoliageVolume * ProceduralFoliageVolume
void UpdateTileMeshComponent(UInstancedStaticMeshComponent *NewInstancedStaticMeshComponent)
void UpdateMaterialCache(const FLinearColor &Value, bool DebugMaterials)
AInstancedFoliageActor * InstancedFoliageActor
TArray< UMaterialInstanceDynamic * > MaterialInstanceDynamicCache
UInstancedStaticMeshComponent * InstancedStaticMeshComponent
TArray< int32 > IndicesInUse