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]))
38 Version += String[index];
40 if (index == String.Len())
62 TileMeshComponent = NewTileMeshComponent;
63 TileMeshComponent->IndicesInUse.Emplace(Index);
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;
99 if (TileMeshComponent)
101 if (TileMeshComponent->bIsAlive)
103 if (TileMeshComponent->IndicesInUse.Contains(Index))
105 TileMeshComponent->IndicesInUse.RemoveSingle(Index);
113 TileMeshComponent =
nullptr;
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;
137 if (BPFullClassName.IsEmpty() || !BPFullClassName.Contains(
"_C"))
139 return SpawnedClass !=
nullptr;
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;
153 BPFullClassName =
"Blueprint'";
156 BPFullClassName += ParsedString[i];
157 BPFullClassName +=
'/';
159 BPFullClassName += BPClassName;
160 BPFullClassName +=
".";
161 BPFullClassName += BPClassName;
162 BPFullClassName +=
"_C'";
168 TRACE_CPUPROFILER_EVENT_SCOPE(FoliageBlueprintCache::SetSpawnedClass);
169 UClass* CastedBlueprint = LoadObject< UClass >(
nullptr, *BPFullClassName);
172 SpawnedClass = CastedBlueprint;
175 SpawnedClass =
nullptr;
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);
250 HeroVehicle = LargeMap->GetHeroVehicle();
254 HeroVehicle->UpdateDetectionBox();
255 TArray<FString> TilesInUse = GetTilesInUse();
256 if (TilesInUse.Num() == 0)
258 UE_LOG(LogCarla, Warning, TEXT(
"No tiles detected."));
262 for (
const FString& TileName : TilesInUse)
264 FTileData* Tile = TileCache.Find(TileName);
267 UpdateMaterials(Tile);
268 TArray<FElementsToSpawn> ElementsToSpawn = GetElementsToSpawn(Tile);
269 SpawnSkeletalFoliages(ElementsToSpawn);
270 ActivePooledActors();
271 DestroySkeletalFoliages();
285 UE_LOG(LogCarla, Display, TEXT(
"Vehicle added."));
293 HeroVehicle =
nullptr;
294 UE_LOG(LogCarla, Display, TEXT(
"Vehicle removed."));
307 if (!
IsValid(InstancedFoliageActor))
312 if (!
IsValid(TileData.InstancedFoliageActor))
315 for (
AActor* Actor : InLevel->Actors)
318 if (!
IsValid(ProceduralFoliageVolume))
323 if (!
IsValid(TileData.ProceduralFoliageVolume))
326 const FString TileName = TileData.InstancedFoliageActor->GetLevel()->GetOuter()->GetName();
327 FTileData* ExistingTileData = TileCache.Find(TileName);
328 if (ExistingTileData)
334 SetTileDataInternals(*ExistingTileData);
338 SetTileDataInternals(TileData);
339 TileCache.Emplace(TileName, TileData);
346 SetInstancedStaticMeshComponentCache(TileData);
347 SetMaterialCache(TileData);
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);
405 MaterialInstanceDynamic->SetScalarParameterValue(
"Distance", HideMaterialDistance);
406 Mesh->SetMaterial(Index, MaterialInstanceDynamic);
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();
428 if (!IsFoliageTypeEnabled(Path))
430 if (FoliageBlueprintCache.Contains(Path))
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);
443 FoliageBlueprintCache.Emplace(Path, NewFoliageBlueprint);
444 CreatePoolForBPClass(NewFoliageBlueprint);
454 AInstancedFoliageActor* TileInstancedFoliageActor =
nullptr;
460 if (!
IsValid(InstancedFoliageActor))
465 if (!
IsValid(TileInstancedFoliageActor))
467 const FString TileName = TileInstancedFoliageActor->GetLevel()->GetOuter()->GetName();
468 FTileData* ExistingTileData = TileCache.Find(TileName);
469 if (ExistingTileData)
473 for (std::shared_ptr<FTileMeshComponent>& Element
476 Element->IndicesInUse.Empty();
477 Element->bIsAlive =
false;
483 TileCache.Remove(TileName);
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();
515 TArray<int32> Indices = HeroVehicle->GetFoliageInstancesCloseToVehicle(InstancedStaticMeshComponent);
516 if (Indices.Num() == 0)
518 TArray<int32> NewIndices;
519 for (int32 Index : Indices)
525 NewIndices.Emplace(Index);
531 for (int32 Index : NewIndices)
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();
548 const float HeroDetectionSizeSquared = HeroVehicle->GetDetectionSize() * HeroVehicle->GetDetectionSize();
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)
572 bool Ok = EnableActorFromPool(Transform, Index, Element.TileMeshComponent, *Pool);
579 NewElement.
Actor = CreateFoliage(Element.BP, {});
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();
596 const float SquaredActiveActorDistance = ActiveActorDistance * ActiveActorDistance;
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();
622 const float HeroDetectionSizeSquared = HeroVehicle->GetDetectionSize() * HeroVehicle->GetDetectionSize();
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();
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());
657 PooledActor.Actor->SetActorScale3D({SpawnScale, SpawnScale, SpawnScale});
669 TArray<FPooledActor> AuxPool;
671 for (int32 i = 0; i < InitialPoolSize; ++i)
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());
708 Actor->SetActorScale3D({SpawnScale, SpawnScale, SpawnScale});
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);
733 UpdateFoliageBlueprintCache(InLevel);
734 CreateOrUpdateTileCache(InLevel);
740 FreeTileCache(InLevel);
746 InactivePoolTransform.SetLocation(FVector(0.0f, 0.0f, 0.0f));
747 UpdatePoolBasePosition();
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);
780 if (!
IsValid(InstancedFoliageActor))
782 const FString TileName = InstancedFoliageActor->GetLevel()->GetOuter()->GetName();
783 if (!TileCache.Contains(TileName))
792 TArray<FString> Results;
794 for (
const TPair<FString, FTileData>& Element : TileCache)
796 const FTileData& TileData = Element.Value;
799 TileCache.Remove(Element.Key);
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);
UInstancedStaticMeshComponent * InstancedStaticMeshComponent
void UpdateFoliageBlueprintCache(ULevel *InLevel)
void CreatePoolForBPClass(const FFoliageBlueprint &BP)
TArray< int32 > IndicesInUse
void EnableActor(const FTransform &Transform, int32 NewIndex, std::shared_ptr< FTileMeshComponent > &NewTileMeshComponent)
void OnLevelRemovedFromWorld(ULevel *InLevel, UWorld *InWorld)
void CreateOrUpdateTileCache(ULevel *InLevel)
void ActivePooledActors()
void SetTileDataInternals(FTileData &TileData)
void UpdateMaterials(FTileData *Tile)
std::shared_ptr< FTileMeshComponent > TileMeshComponent
std::vector< cg::Location > Path
TSubclassOf< AActor > SpawnedClass
bool SetBPClassName(const FString &Path)
TArray< FElementsToSpawn > GetElementsToSpawn(FTileData *Tile)
bool EnableActorFromPool(const FTransform &Transform, int32 Index, std::shared_ptr< FTileMeshComponent > &TileMeshComponent, TArray< FPooledActor > &Pool)
static FString GetVersionFromFString(const FString &String)
static bool IsValid(const ACarlaWheeledVehicle *Vehicle)
AProceduralFoliageVolume * ProceduralFoliageVolume
TArray< std::shared_ptr< FTileMeshComponent > > TileMeshesCache
void DestroySkeletalFoliages()
AActor * CreateFoliage(const FFoliageBlueprint &BP, const FTransform &Transform) const
void SetInstancedStaticMeshComponentCache(FTileData &TileData)
virtual void Tick(float DeltaTime) override
bg::model::box< Point3D > Box
void FreeTileCache(ULevel *InLevel)
AInstancedFoliageActor * InstancedFoliageActor
carla::SharedPtr< cc::Actor > Actor
void OnLevelAddedToWorld(ULevel *InLevel, UWorld *InWorld)
void SpawnSkeletalFoliages(TArray< FElementsToSpawn > &ElementsToSpawn)
virtual void BeginPlay() override
void UpdateTileMeshComponent(UInstancedStaticMeshComponent *NewInstancedStaticMeshComponent)
void AddVehicle(ACarlaWheeledVehicle *Vehicle)
void SetMaterialCache(FTileData &TileData)
void UpdatePoolBasePosition()
void PostWorldOriginOffset(UWorld *, FIntVector, FIntVector InDstOrigin)
bool ContainsMesh(const UInstancedStaticMeshComponent *) const
TArray< UMaterialInstanceDynamic * > MaterialInstanceDynamicCache
bool CheckForNewTiles() const
static ALargeMapManager * GetLargeMapManager(const UObject *WorldContextObject)
void UpdateMaterialCache(const FLinearColor &Value, bool DebugMaterials)
TArray< FString > GetTilesInUse()
Base class for CARLA wheeled vehicles.
bool IsFoliageTypeEnabled(const FString &Path) const
geom::Transform Transform
void RemoveVehicle(ACarlaWheeledVehicle *Vehicle)