7#include "ProceduralFoliageVolume.h"
8#include "ProceduralFoliageComponent.h"
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;
31 int index =
String.Find(TEXT(
"_v"));
35 FString Version =
"_v";
36 while(IsDigit(
String[index]))
55void FPooledActor::EnableActor(
const FTransform& Transform, int32 NewIndex, std::shared_ptr<FTileMeshComponent>& NewTileMeshComponent)
65 Actor->SetActorHiddenInGame(
false);
66 Actor->SetActorTickEnabled(
true);
68 USpringBasedVegetationComponent* Component =
Actor->FindComponentByClass<USpringBasedVegetationComponent>();
71 Component->ResetComponent();
80 Actor->SetActorEnableCollision(
true);
82 USpringBasedVegetationComponent* Component =
Actor->FindComponentByClass<USpringBasedVegetationComponent>();
85 Component->SetComponentTickEnabled(
true);
88 USkeletalMeshComponent* SkeletalMesh =
Actor->FindComponentByClass<USkeletalMeshComponent>();
91 SkeletalMesh->bNoSkeletonUpdate =
false;
115 Actor->SetActorEnableCollision(
false);
116 Actor->SetActorHiddenInGame(
true);
117 Actor->SetActorTickEnabled(
false);
119 USpringBasedVegetationComponent* Component =
Actor->FindComponentByClass<USpringBasedVegetationComponent>();
122 Component->SetComponentTickEnabled(
false);
125 USkeletalMeshComponent* SkeletalMesh =
Actor->FindComponentByClass<USkeletalMeshComponent>();
128 SkeletalMesh->bNoSkeletonUpdate =
true;
144 TRACE_CPUPROFILER_EVENT_SCOPE(FoliageBlueprintCache::SetBPClassName);
147 TArray< FString > ParsedString;
148 Path.ParseIntoArray(ParsedString, TEXT(
"/"),
false);
149 int Position = ParsedString.Num() - 1;
151 const FString Folder = ParsedString[--
Position];
152 const FString BPClassName =
"BP_" + Folder + FullVersion;
168 TRACE_CPUPROFILER_EVENT_SCOPE(FoliageBlueprintCache::SetSpawnedClass);
169 UClass* CastedBlueprint = LoadObject< UClass >(
nullptr, *
BPFullClassName);
184 UInstancedStaticMeshComponent* Aux {
nullptr };
185 for (std::shared_ptr<FTileMeshComponent>& ElementPtr
192 int32 NewCount = NewInstancedStaticMeshComponent->GetInstanceCount();
194 if (NewCount > CurrentCount)
205 for (
const std::shared_ptr<FTileMeshComponent>& Element
208 if (Element->InstancedStaticMeshComponent == Mesh)
220 Material->SetScalarParameterValue(
"ActivateDebug", 1);
222 Material->SetScalarParameterValue(
"ActivateDebug", 0);
223 Material->SetScalarParameterValue(
"ActivateOpacity", 1);
224 Material->SetVectorParameterValue(
"VehiclePosition", Value);
245 TRACE_CPUPROFILER_EVENT_SCOPE(Parent
Tick);
246 Super::Tick(DeltaTime);
256 if (TilesInUse.Num() == 0)
258 UE_LOG(LogCarla, Warning, TEXT(
"No tiles detected."));
262 for (
const FString& TileName : TilesInUse)
285 UE_LOG(LogCarla, Display, TEXT(
"Vehicle added."));
294 UE_LOG(LogCarla, Display, TEXT(
"Vehicle removed."));
304 for (
AActor* Actor : InLevel->Actors)
306 AInstancedFoliageActor* InstancedFoliageActor = Cast<AInstancedFoliageActor>(Actor);
307 if (!
IsValid(InstancedFoliageActor))
309 TileData.InstancedFoliageActor = InstancedFoliageActor;
312 if (!
IsValid(TileData.InstancedFoliageActor))
315 for (
AActor* Actor : InLevel->Actors)
317 AProceduralFoliageVolume* ProceduralFoliageVolume = Cast<AProceduralFoliageVolume>(Actor);
318 if (!
IsValid(ProceduralFoliageVolume))
320 TileData.ProceduralFoliageVolume = ProceduralFoliageVolume;
323 if (!
IsValid(TileData.ProceduralFoliageVolume))
326 const FString TileName = TileData.InstancedFoliageActor->GetLevel()->GetOuter()->GetName();
328 if (ExistingTileData)
354 for (UActorComponent* Component : ActorComponents)
356 UInstancedStaticMeshComponent* Mesh = Cast<UInstancedStaticMeshComponent>(Component);
359 const FString Path = Mesh->GetStaticMesh()->GetPathName();
370 std::shared_ptr<FTileMeshComponent> Aux =
371 std::make_shared<FTileMeshComponent>();
372 Aux->InstancedStaticMeshComponent = Mesh;
373 Aux->bIsAlive =
true;
385 for (std::shared_ptr<FTileMeshComponent>& ElementPtr
393 for (UMaterialInterface* Material : Mesh->GetMaterials())
398 UMaterialInstanceDynamic* MaterialInstanceDynamic = UMaterialInstanceDynamic::Create(Material,
this);
399 if (!MaterialInstanceDynamic)
403 MaterialInstanceDynamic->SetScalarParameterValue(
"ActivateOpacity", 0);
404 MaterialInstanceDynamic->SetScalarParameterValue(
"ActivateDebug", 0);
406 Mesh->SetMaterial(Index, MaterialInstanceDynamic);
415 for (
AActor* Actor : InLevel->Actors)
417 AInstancedFoliageActor* InstancedFoliageActor = Cast<AInstancedFoliageActor>(Actor);
418 if (!
IsValid(InstancedFoliageActor))
420 const FString TileName = InstancedFoliageActor->GetLevel()->GetOuter()->GetName();
421 const TSet<UActorComponent*>& ActorComponents = InstancedFoliageActor->GetComponents();
422 for (UActorComponent* Component : ActorComponents)
424 UInstancedStaticMeshComponent* Mesh = Cast<UInstancedStaticMeshComponent>(Component);
427 const FString Path = Mesh->GetStaticMesh()->GetPathName();
436 if (!NewFoliageBlueprint.
IsValid())
438 UE_LOG(LogCarla, Warning, TEXT(
"Blueprint %s was invalid."), *NewFoliageBlueprint.
BPFullClassName);
442 UE_LOG(LogCarla, Display, TEXT(
"Blueprint %s created."), *NewFoliageBlueprint.
BPFullClassName);
454 AInstancedFoliageActor* TileInstancedFoliageActor =
nullptr;
455 for (
AActor* Actor : InLevel->Actors)
459 AInstancedFoliageActor* InstancedFoliageActor = Cast<AInstancedFoliageActor>(Actor);
460 if (!
IsValid(InstancedFoliageActor))
462 TileInstancedFoliageActor = InstancedFoliageActor;
465 if (!
IsValid(TileInstancedFoliageActor))
467 const FString TileName = TileInstancedFoliageActor->GetLevel()->GetOuter()->GetName();
469 if (ExistingTileData)
473 for (std::shared_ptr<FTileMeshComponent>& Element
476 Element->IndicesInUse.Empty();
477 Element->bIsAlive =
false;
493 const FTransform GlobalTransform =
HeroVehicle->GetActorTransform();
494 const FLinearColor
Position = GlobalTransform.GetLocation();
501 TArray<FElementsToSpawn> Results;
504 for (std::shared_ptr<FTileMeshComponent>& ElementPtr
508 TRACE_CPUPROFILER_EVENT_SCOPE(Update Foliage Usage);
511 const FString Path = InstancedStaticMeshComponent->GetStaticMesh()->GetPathName();
516 if (Indices.Num() == 0)
518 TArray<int32> NewIndices;
519 for (int32 Index : Indices)
525 NewIndices.Emplace(Index);
531 for (int32 Index : NewIndices)
533 FTransform Transform;
534 InstancedStaticMeshComponent->GetInstanceTransform(Index, Transform,
true);
535 NewElement.TransformIndex.Emplace(TPair<FTransform, int32>(Transform, Index));
537 if (NewElement.TransformIndex.Num() > 0)
538 Results.Emplace(NewElement);
546 const FTransform HeroTransform =
HeroVehicle->GetActorTransform();
547 const FVector HeroLocation = HeroTransform.GetLocation();
552 TArray<FPooledActor>* Pool =
ActorPool.Find(Element.BP.BPFullClassName);
556 UE_LOG(LogCarla, Error, TEXT(
"Pool not valid"));
559 for (
const TPair<FTransform, int32>& TransformIndex : Element.TransformIndex)
561 const FTransform& Transform = TransformIndex.Key;
562 int32 Index = TransformIndex.Value;
563 if (Element.TileMeshComponent->IndicesInUse.Contains(Index))
567 const float Distance = FMath::Abs(FVector::DistSquared(Transform.GetLocation(), HeroLocation));
568 if (Distance > HeroDetectionSizeSquared)
582 NewElement.
Actor->SetTickableWhenPaused(
false);
583 NewElement.
EnableActor(Transform, Index, Element.TileMeshComponent);
584 Pool->Emplace(NewElement);
594 const FTransform HeroTransform =
HeroVehicle->GetActorTransform();
595 const FVector HeroLocation = HeroTransform.GetLocation();
598 for (TPair<FString, TArray<FPooledActor>>& Element :
ActorPool)
600 TArray<FPooledActor>& Pool = Element.Value;
607 const FVector Location = Actor.GlobalTransform.GetLocation();
608 const float Distance = FMath::Abs(FVector::DistSquared(Location, HeroLocation));
609 if (Distance < SquaredActiveActorDistance)
620 const FTransform HeroTransform =
HeroVehicle->GetActorTransform();
621 const FVector HeroLocation = HeroTransform.GetLocation();
624 for (TPair<FString, TArray<FPooledActor>>& Element :
ActorPool)
626 TArray<FPooledActor>& Pool = Element.Value;
631 const FVector Location = Actor.GlobalTransform.GetLocation();
632 const float Distance = FMath::Abs(FVector::DistSquared(Location, HeroLocation));
633 if (Distance > HeroDetectionSizeSquared)
635 Actor.DisableActor();
642 const FTransform& Transform,
644 std::shared_ptr<FTileMeshComponent>& TileMeshComponent,
645 TArray<FPooledActor>& Pool)
650 if (PooledActor.InUse)
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());
669 TArray<FPooledActor> AuxPool;
670 const FTransform Transform {};
677 UE_LOG(LogCarla, Display, TEXT(
"Created actor for pool"));
678 NewElement.
Actor->SetTickableWhenPaused(
false);
680 AuxPool.Emplace(NewElement);
684 UE_LOG(LogCarla, Error, TEXT(
"Failed to create actor for pool"));
688 UE_LOG(LogCarla, Display, TEXT(
"CreatePoolForBPClass: %s"), *BP.
BPFullClassName);
696 Transform.GetLocation(), Transform.Rotator());
698 TArray<UTaggedComponent*> TaggedComponents;
699 Actor->GetComponents(TaggedComponents);
702 Component->DestroyComponent();
705 if (SpawnScale <= 1.01f && SpawnScale >= 0.99f)
706 Actor->SetActorScale3D(Transform.GetScale3D());
715 for (TPair<FString, TArray<FPooledActor>>& Element :
ActorPool)
717 TArray<FPooledActor>& Pool = Element.Value;
720 if (PooledActor.InUse)
722 PooledActor.Actor->SetActorTransform(
InactivePoolTransform,
true,
nullptr, ETeleportType::ResetPhysics);
757 if (Path.Contains(
"/Rock"))
760 if (Path.Contains(
"/Tree"))
763 if (Path.Contains(
"/Bush"))
766 if (Path.Contains(
"/Plant"))
774 const UObject* World = GetWorld();
775 TArray<AActor*> ActorsInLevel;
776 UGameplayStatics::GetAllActorsOfClass(World, AInstancedFoliageActor::StaticClass(), ActorsInLevel);
777 for (
AActor* Actor : ActorsInLevel)
779 AInstancedFoliageActor* InstancedFoliageActor = Cast<AInstancedFoliageActor>(Actor);
780 if (!
IsValid(InstancedFoliageActor))
782 const FString TileName = InstancedFoliageActor->GetLevel()->GetOuter()->GetName();
792 TArray<FString> Results;
794 for (
const TPair<FString, FTileData>& Element :
TileCache)
796 const FTileData& TileData = Element.Value;
802 if (Results.Contains(Element.Key))
807 if (!
IsValid(Procedural->ProceduralComponent))
809 const FBox Box = Procedural->ProceduralComponent->GetBounds();
812 if (Box.IsInside(
HeroVehicle->GetActorTransform().GetLocation()))
813 Results.Emplace(Element.Key);
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
void UpdateDetectionBox()
float GetDetectionSize() 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
bool CheckForNewTiles() const
void UpdatePoolBasePosition()
float ActiveActorDistance
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 ActivePooledActors()
void DestroySkeletalFoliages()
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)
float HideMaterialDistance
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