CARLA
Loading...
Searching...
No Matches
StaticMeshFactory.cpp
Go to the documentation of this file.
1// Copyright (c) 2026 Computer Vision Center (CVC) at the Universitat Autonoma
2// de Barcelona (UAB).
3//
4// This work is licensed under the terms of the MIT license.
5// For a copy, see <https://opensource.org/licenses/MIT>.
6
7#include "StaticMeshFactory.h"
10
11#include <util/ue-header-guard-begin.h>
12#include "Engine/StaticMeshActor.h"
13#include <util/ue-header-guard-end.h>
14
15TArray<FActorDefinition> AStaticMeshFactory::GetDefinitions()
16{
18 auto StaticMeshDefinition = ABFL::MakeGenericDefinition(
19 TEXT("static"),
20 TEXT("prop"),
21 TEXT("mesh"));
22 StaticMeshDefinition.Class = AStaticMeshActor::StaticClass();
23 StaticMeshDefinition.Variations.Emplace(FActorVariation{
24 TEXT("mesh_path"),
26 {""}, false});
27 StaticMeshDefinition.Variations.Emplace(FActorVariation{
28 TEXT("mass"),
30 {""}, false});
31 StaticMeshDefinition.Variations.Emplace(FActorVariation{
32 TEXT("scale"),
34 {"1.0f"}, false});
35 return { StaticMeshDefinition };
36}
37
38void AStaticMeshFactory::ReleaseContentPack(const FString &MountPoint)
39{
40 for (auto It = MeshCacheByPath.CreateIterator(); It; ++It)
41 {
42 if (It.Key().StartsWith(MountPoint))
43 {
44 It.RemoveCurrent();
45 }
46 }
47}
48
50 const FTransform &SpawnAtTransform,
51 const FActorDescription &ActorDescription)
52{
54 auto *World = GetWorld();
55 if (World == nullptr)
56 {
57 UE_LOG(LogCarla, Error, TEXT
58 ("AStaticMeshFactory: cannot spawn mesh into an empty world."));
59 return {};
60 }
61
62 float Scale = ABFL::RetrieveActorAttributeToFloat("scale", ActorDescription.Variations, 1.0f);
63 FTransform ScaledTransform(SpawnAtTransform);
64 ScaledTransform.SetScale3D(FVector(Scale));
65
66 // Resolve the mesh before spawning anything: an unloadable mesh_path must
67 // fail the spawn instead of leaving a mesh-less actor (infinite bounds).
68 FString MeshPath;
69 UStaticMesh* Mesh = nullptr;
70 if (ActorDescription.Variations.Contains("mesh_path"))
71 {
72 MeshPath = ABFL::ActorAttributeToString(ActorDescription.Variations["mesh_path"], "");
73 if (MeshPath.IsEmpty())
74 {
75 // Same outcome as an unloadable path: nothing to render, no semantic tag,
76 // infinite bounds. Refuse instead of spawning a mesh-less actor.
77 UE_LOG(LogCarla, Error,
78 TEXT("AStaticMeshFactory: empty mesh_path for actor %s; spawn refused."),
79 *ActorDescription.Id);
80 FActorSpawnResult Failed;
81 Failed.Status = EActorSpawnResultStatus::InvalidDescription;
82 return Failed;
83 }
84 else
85 {
86 if (TObjectPtr<UStaticMesh>* Cached = MeshCacheByPath.Find(MeshPath))
87 {
88 Mesh = Cached->Get();
89 }
90 else
91 {
92 Mesh = LoadObject<UStaticMesh>(nullptr, *MeshPath);
93 if (Mesh != nullptr)
94 {
95 MeshCacheByPath.Add(MeshPath, Mesh);
96 }
97 }
98 if (Mesh == nullptr)
99 {
100 UE_LOG(LogCarla, Error,
101 TEXT("AStaticMeshFactory: failed to load mesh '%s' for actor %s; spawn refused."),
102 *MeshPath, *ActorDescription.Id);
103 FActorSpawnResult Failed;
104 Failed.Status = EActorSpawnResultStatus::InvalidDescription;
105 return Failed;
106 }
107 }
108 }
109
110 FActorSpawnParameters SpawnParameters;
111 SpawnParameters.SpawnCollisionHandlingOverride =
112 ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
113 auto *StaticMeshActor = World->SpawnActor<AStaticMeshActor>(
114 ActorDescription.Class, ScaledTransform, SpawnParameters);
115
116 auto *StaticMeshComponent = Cast<UStaticMeshComponent>(
117 StaticMeshActor->GetRootComponent());
118
119 if (StaticMeshComponent)
120 {
121 if (ActorDescription.Variations.Contains("mesh_path"))
122 {
123 StaticMeshComponent->SetMobility(EComponentMobility::Movable);
124 if (!StaticMeshComponent->SetStaticMesh(Mesh))
125 {
126 UE_LOG(LogCarla, Warning,
127 TEXT("AStaticMeshFactory: failed to set mesh '%s' on actor %s."),
128 *MeshPath, *ActorDescription.Id);
129 }
130 StaticMeshComponent->SetMobility(EComponentMobility::Static);
131
132 if (ActorDescription.Variations.Contains("mass"))
133 {
134 float Mass = ABFL::RetrieveActorAttributeToFloat("mass", ActorDescription.Variations, 0.0f);
135 if (Mass > 0)
136 {
137 StaticMeshComponent->SetMobility(EComponentMobility::Movable);
138 StaticMeshComponent->SetSimulatePhysics(true);
139 StaticMeshComponent->SetCollisionProfileName("PhysicsActor");
140 StaticMeshComponent->SetMassOverrideInKg("", Mass);
141 }
142 }
143 }
144 }
145 return FActorSpawnResult(StaticMeshActor);
146}
virtual void ReleaseContentPack(const FString &MountPoint) override
Drop every cached definition, parameter and loaded asset that refers to content under MountPoint ("/<...
TArray< FActorDefinition > GetDefinitions() final
Retrieve the definitions of the static mesh actor.
TMap< FString, TObjectPtr< UStaticMesh > > MeshCacheByPath
Lazy, memoizing mesh cache keyed by mesh path.
FActorSpawnResult SpawnActor(const FTransform &SpawnAtTransform, const FActorDescription &ActorDescription) final
Spawn an actor based on ActorDescription and Transform.
A description of a Carla Actor with all its variation.
TMap< FString, FActorAttribute > Variations
User selected variations of the actor.
TSubclassOf< AActor > Class
Class of the actor to be spawned.
Result of an actor spawn function.
EActorSpawnResultStatus Status